Getting Rusty: Day 1

2017-09-13 in github, rust

I've tried three times in as many years to dig into the Rust language, but it never really stuck - the first couple of times the syntax was still a bit impenetrable, and the last time I didn't have a strong use case. I've got a good one this time though!

Why are you learning Rust?

I've always liked the idea of Rust for a few reasons:

  • pleasant, composable type system
  • more compile time safety than I thought possible
  • one of the nicest/most helpful communities I've seen
  • null doesn't exist šŸ˜¹
  • I never really learned any systems/low-level language

Having a strong and usable type system is what keeps me in TypeScript (over plain JS) for front end work, and what otherwise keeps me in statically-typed server-side languages (primarily .NET). It's also what's kept me away from more than a cursory look into go - lacking generics and having to abandon compile-time safety is just sad. I'm also a fan of how behavior for an object is composed from a bunch of Trait implementations - it seems like a language-integrated I from SOLID, but without the enterprise.

One of the biggest reasons I picked Rust is wanting to branch out into more hardcore/lower-level programming, and not wanting to tie myself to C/C++. The package management system is what I'd expect from a modern language (and what I'm used to from nuget/NPM), the language is (nowadays) ergonomic, and there's enough safety built into the compiler to prevent a whole wide range of errors that I'm not used to dealing with in .NET.

The project

Over the last year I've been building and maintaining an internal tool that listens to webhooks from github and does... a ton of stuff with that data (logging all webhooks, parsing pull requests, applying labels, notifying hipchat rooms for certain actions, etc). It's built out in pretty standard .NET, using Azure AD for authentication (our local domain is synced with Azure, so I could outsource all auth). In the last year I've gotten very familiar with GitHub's API and webhook system, and the various ways both can fail/flake out.

Everything in the system that takes non-trivial time to complete executes as a background job in Hangfire, a fairly magical background job system built from the ground up for .NET (as opposed to Quartz, which still is very Java-y). The general webhook flow looks like:

  • receive HTTP call from github
  • validate the call and reject it if the hashes don't match
  • store the payload in the db in an insert-/select-only table immediately (no updates allowed to reduce locking)
  • queue a background job with the github event id (hangfire serializes all job arguments to json, so passing a big object to a job is a no-no)
  • return success immediately after queuing the job, with some ids to help debugĀ (github will show the webhook's response body in their UI, so logging the job & event ID helps a ton)

For my first real Rust project, I'm going to replicate the webhook receiver/validator and storage system. This will probably never make it to production as 1) the .NET version is faster than is needed and safe enough through a year of manual checks and 100k+ webhook events and 2) it would drastically complicate deploys/the application architecture, but it's a domain I know well so I can focus on the important part: learning and practicing Rust.

About my notes

My notes are generally going to be very unstructured/stream-of-conscious, since they are jotted down while I'm working on the project. I don't have a wealth of time outside of work so I'm keeping the overhead of blogging low to maximize the learning.

My notes are broken into "days" but they likely won't always be consecutive days and may include multiple real-world days of notes - most of my time for Rust is after work/on the weekend, and publishing a blog post with only 'fixed a bug' is just kinda wasteful.

Day one notes

  • rust setup in vscode (the recommended one on the rust homepage isn't good anymore apparently, and you should use rls-vscode + racer)
  • read/played around through the rust book's control flow section
  • I like match and miss it in .net (and also if blocks being expressions)
  • control flow things being expressions is really cool
  • I don't like the /// doc standard - I prefer the /** multiline syntax for jsdoc. This is mostly an IDE complaint that will probably be resolved over time - I don't mind it in .NET because VS will automatically continue the comment when you hit enter
  • I hope that there becomes an official doc standard for documenting arguments and return types that IDEs/generated docs can then use
  • to get full autocomplete in vscode you need vscode + the extension above + racer, and you're going to be restarting vscode a lot when the RLS crashes

    • this will get much better over time - RLS is still in nursery org, is branch new
    • the vscode extension is the reference implementation so it'll get the most love of all of them, which works for me because vscode gets most of my love too
  • my first function was a safe argument parser! just make every error return the default, and add magic casting via the From trait
  • building up types fills me with joy. also something I enjoy in typescript

    • I would like to be able to spite a type and not allow it via the type system but that doesn't seem valuable to include in a language
  • still only playing around with a test app and haven't started the webhook system just yet
  • I typed most of this while racer was installing on my macbook...