Skip to content
Jeff Davis edited this page Jan 4, 2012 · 5 revisions

Go Postmortem

I did the AI Challenge in large part because I wanted to have an interesting project to learn Go with. I wrote my first hello world a few days before the contest started and spent a fair bit of time exploring the tools, reading the Go source code, and trying to get to where I was writing idiomatic Go code.

In hindsight given the restriction of no packages and no threads imposed by the the contest I probably could have found a better way to learn. On the other hand, the contest was a blast. Lots of interesting little problems, a focus on performance and error free code, and lots of room for creativity. I ended up with almost 15,000 lines of Go, though as Pascal said "If I had more time I would write a shorter letter." I think now have a pretty good handle on how to build a real project using Go.

Things I Loved

  1. Fast - the amazingly fast tool chain was an absolute pleasure to work with.

  2. gofmt - Having a canonical source code format was great (although it helped that it was so well aligned with my own opinions about formatting); gofmt -s to "simplify code" demonstrated where I was adding unnecessary verbiage; and having gofmt run on file saves was just great. I am really not an IDE person and that combination puts me about where I want to be in terms of facilitating my coding.

  3. gotest - One of the valuable lessons learned (for about the 10th time) was write lots of tests and gotest with its extremely, light weight test framework was perfect for that. Also I spent a great deal of time tweaking code and running benchmarks; I spent a great deal of time iterating through changes and running gotest -bench=".*" -cpuprofile=prof.tmp. The only real negative was that profiling did not work on OS X (apparently due to how signals are handled there)

  4. Code - Deploying go in source form provides a high quality, code reviewed, idiomatic code base to learn from. I did a lot of browsing godoc and doing grep -r in the beginning and it brought me up the curve much faster than I otherwise would have. It's interesting that given the plethora of open source projects in various languages you should always be able to do that but for quite a few the amount of line noise you get for real multiplatform code (certainly in C or C++) drowns out insights you might otherwise gain from the code. Reading Go source was generally a pleasure.

  5. Community - Seeing threads like this or this you get insight into where the language is going. Watching the code review messages flying by on golang-dev constitutes a great tutorial by phenomenal programmers and people singularly knowledgable about the language. The dashboard is really useful and deployment of code from any of the DCVS's via goinstall is trivial.

  6. Philosophy - Go code is minimalist and consistent but not cryptic and definitely satisfies the principal of least surprise. There were a number of places where I just wrote substantive code on the assumption things should chain together in a sensible way and it all just worked (things like chaining a gzip decoder on a file reader).

  7. Performance - Maybe I did not love this but I worried I might encounter performance problems but never did. The code generation from 6g is definitely not quite what you would get from gcc or other heavily optimized compiler but there also just weren't any big performance surprises. The GC seems not to produce problematic pauses (and the visibility into the GC timing is great). I really did not feel like baseline performance of the language was an issue at all for my project.

  8. Reflect - I did not use it too much but of course the JSON package relies heavily on it as do the test frameworks and it's the kind of thing always love in a language.

Things I Did Not Love

It's really a pretty short list...

  1. Reading the code as documentation is great but in some cases it's a bit too minimal for me. An example would be the JSON tags where because the documentation was so sparse it was never clear to me if you could unmarshall arrays which did not have field identifiers. Also, I wanted to use mmap for reading the JSON replay files but the documentation is pretty unclear on what you can and can't do with the resulting mmaped data (though to be fair anything which requires the unsafe package to function is to a sharp tool).

  2. If you are not careful about your dependencies you can introduce some hard to track down bugs (and because you can't have unused imports it's easy to miss a dependency change since adding and removing imports is pretty common). That might be easily avoided with a better build environment but it happened several times and in the end I reverted to building the entire project every time.

Some Lessons

These are not really Go specific at all but some things I (re)learned.

  1. Write more tests and write them first. When writing the Symmetry code, generating the mapping table for equivalence classes is not that hard but there are a number of corner cases to worry about. Because I did not write tests for what was an "easy piece of code" I spent a long time tracking down bugs that could have easily been avoided. The same goes for the movement generation. I was pretty good on testing for the pathfinding and just never had anything but shallow bugs in that code.

  2. Break things up into smaller pieces. A number of my packages conflate several different ideas and consequently there were a lot more circular dependencies in the code and things got rigid a lot quicker than I would have liked. Running splint from the kind people at stathat.com told me just about every package had several functions that were far too long by there metrics and of course those functions were the most problematic.

  3. Be less afraid to tear things apart. If I had adhered to the previous two tenets I would have had an easier time of this. I did do a few significant refactorings and it generally went reasonably smoothly but I was nervous to do to much especially into the contest deadline.

Verdict

I love Go.

For a long time I tried to like C++ but any time I tried to do anything substantive in it I got frustrated with the language and libraries, the 50mb executables (it seemed like a lot at the time), the hour long builds, and the horrifying debugging experiences. I had a similar reaction to Java. Most of that predated the mature IDE's, STL, and stepping back from the brink of madness (the deemphasis of "Enterprise Java"). Maybe today if I was willing to come back to either of those languages I would like them better but somehow I doubt it.

I spent the last decade or so working in interpreted languages, using R, Perl, Tcl, lua, and Python at various times. I did code a bit in C or C++ if needed, either for performance (yay Rcpp) or to interface to vendor libraries. They are pleasant and productive but I definitely miss the fine control, the benefits of static typing and (oddly enough) gdb. But for a lot of problems I've worked on Go would have been a great starting point.

I thought a lot about why I had such a positive rection to Go and I credit Go's genesis in all of the work done at Bell Labs as the real reason I love it so much. My first four real programming books were written by Bell Labs guys, as was one of my favorite programming books of all time, Programming Pearls by Jon Bentley.

![Books](https://github.com/jcdny/bugnuts/wiki/img/progbookssm.jpg)

Clone this wiki locally