I'm Parker.

Working with Go

Man, Go is damn nice to work with. I figured I would hold off writing about it until after I had used it seriously at work for a couple weeks. We wrote a couple projects in Go that never really got off the ground, but the one I have been spending most of my time on nowadays is going the full 400 meters to production.

The Good

First, the good. Structure and organization are key for me when developing. If the structure of the code isn’t uniform, it makes it immensely difficult to work with. This is one reason I get really angry with Node – there’s no uniformity at all. gofmt helps ease the tension between colleagues and makes an easy case to follow “the Go way.” There are still tensions when it comes to package organization but those arguments are fewer now. So in terms of code cleanliness and organization, my inner OCD gives Go a big thumbs up. And my inner peacemaker is grateful, too.

The Go community is a really vibrant one. If you log onto the #go-nuts channel on IRC (Freenode), you’ll find lively conversation at all hours of day. The golang-nuts mailing list is also a great place to ask questions and to passively learn more about the language and its application in various problem spaces. There are loads of talks by the Go Team at Google as well; I would recommend talks by Rob Pike and Brad Fitzpatrick if you’re interested in the technical deep-dives.

I come from a background of PHP, Ruby, and JavaScript, where types feel like an afterthought. Working with Go’s strict typing system has been a really nice ease into the world of strict types. I tried my hand at Rust a little while ago and got so frustrated by the type system that I ended up putting it down. Go’s type system feels like one that helps you out rather than holds you back. It doesn’t have generics, but I barely remember generics from my Java days (oh, high school) so I don’t miss them much. Generally, I find a way for interfaces to satisfy that need if there is the need for generics. At any rate, Go’s type system gives me confidence that there won’t be some silly type error at runtime (as long as I stay away from the dreaded interface{} non-type).

Working with a compiled language is also a really nice change. I can build a binary with go build and ship that out to my production servers without even blinking. Hell, using scp or rsync to deploy?! You have those ansible/capistrano folks weeping in their sleep. The compiler’s type checking also really helps. If it builds, it probably runs – though it isn’t guaranteed that you hooked up all the bits correctly even if it does compile. A file of empty methods is still valid in Go. At any rate, working with the compiler has been a marvelous change coming from Ruby and JavaScript where almost every error is a runtime error.

It’s hella fast. A sizable test suite will often run in less than 30 seconds. The Rubyist in me was off hiding in the corner, hoping I wouldn’t notice that a similarly-sized test suite in Ruby would take 3 or 4 minutes to run. Beyond tests, there has been so much optimization in the compiler to make Go as fast as humanly possible – obviously in Google’s best interests because at their scale, every CPU millisecond counts.

Channels. Holy hell, channels are cool. Communicating between goroutines using channels instead of shared memory has changed my world for the better. If you don’t know what channels are, here’s a gentle introduction on Go By Example.

I suppose there is more I could say here, but I imagine you’re satisfied

The Frustrating

I really, really miss Enumerable. There’s no reduce, no map – none of that. Just for and a growable array type called a slice. I was writing Ruby last night and loved how concisely I could operate over large arrays. I suppose concision and speed are at war here, so at this point I’m not too broken up about it. For every step made easier by Ruby, there’s a 200ms overhead it seems.

Your code won’t compile unless it’s clean. Evan Miller famously wrote about this in Four Days of Go, where he, amongst other things both good and bad, expresses his frustration that his code must be bereft of unused imports and variables before it will compile. This makes just testing a quick fix a bit slower than usual. Given Google’s cost structure, this makes sense: an extra few minutes a developer spends cleaning up the code saves a lot of money on CPU time later. This doesn’t tend to frustrate me as much having some erroneous import or variable which used to plague me when I was learning C. So all in all, it just slows me down a bit.

Go’s still a little young and the idea that you shouldn’t make breaking changes in your library has not spread throughout the community a ton. go get simply fetches master of the repo. Without using some third-party package manager (like my fave gpm), you’re stuck using master of everything. If someone breaks something, you’re spending your time debugging your integration with this bozo’s code instead of doing something interesting. That said, it’s nice that the “don’t break things” mantra is so strictly enforced as a byproduct of using other libraries. We should stop breaking software so much.

All In All

My last few weeks writing Go every day have been marvelous. Our code is of better quality, it’s more consistent, it’s faster, and we’re having fewer arguments about dumb shit like whether to use single quotes or double quotes. Go gives you one way to do things – when working in an unpredictable, dynamic team environment, that’s a huge win.