More Golang adventures

I recently wrote a little application called ConfigServer (although the project will probably be renamed). It is intended to be a tool to assist release managers and software deployments by providing a central server to hold configurations, but also allow configurations to be version controlled. ConfigServer provides some inheritance capability, the idea being that you can have a Cluster configuration, a Server configuration that inherits properties from the Cluster, and an Application configuration that inherits from the Server – ConfigServer doesn’t care about the schema, actually, but that’s an implementation detail.

The original version of this application was written in Ruby, a language that I was once extremely well-versed in, but which I haven’t used for anything but one-off command-line scripts in a few years. It took me about 6 hours to write the thing.

Out of curiosity, and since the project was so small, I decided to re-implement it in Go. When I started the rewrite, it was the second time I’d looked at Go syntax; the first was to fix a small benchmark program that was comparing Go to Vala (commentary on that is here), so it really was the first time I’d written any Go; I was utterly unfamiliar with the packages. The Go version took me about 20 hours. That time includes unit tests and a couple of refactorings to improve segregation of responsibility; I guesstimate that if I performed the same refactoring and writing unit tests for the Ruby code, I could probably spend another 6-10 hours; on the one hand, I know the shape of the modules/packages, but on the other hand, writing unit tests always takes a lot of time.

cloc tells us this:

Language files blank comment code
Go 7 104 43 482
Ruby 1 59 55 326

This excludes unit tests. So here are my observations:

All in all, Go surprises me; it’s concise, easy, encourages good separation of concerns, is easy to read, and much more functional in feel than you’d expect from looking at the tutorial. At the same time, it has some unfortunate quirks: it’s (currently) relatively slow for a compiled language, and builds large executables; some language constructs are just baffling in their constraints, such as range only being applicable to a small set of built-ins, rather than working on some well-defined interface; tail-call optimization is extremely limited, which is such a shame for a language as close to being a functional language as Go is; and the lack of ability to mix in to extra-package types is limiting.

To the first point in my list of Go quirks, I have no doubt that this will change rapidly, and Go will catch up; it’s a very young language, after all. As to the last point, the explanation put forth by the Go developers is, frankly, weak. It’s the same argument Gosling made about not supporting multiple inheritance in Java, which basically boils down to “programmers are stupid, and this feature will confuse them.” I don’t buy it; I’d rather have extra-package mix-ins with limitations based on technical merit than none at all.

I’ve learned that I vastly prefer the cost of slower development time to gain reliability and safety, as long as the cost isn’t too high. Haskell is even safer, but it pushes the boundaries of how much pain I’m willing to endure trying to get code to pass through the type checker.

Right now, I’m thinking Go’s a keeper. It is more productive than C, more reliable than Ruby, easier than Haskell, is superior to Erlang in a whole host of ways I won’t enumerate here (although, I do like the features that the OTP brings to the table, many of which are “killer” features unavailable in any other language, which keeps Erlang highly relevant), and is far better than Java in terms of simplicity, syntax, typing, threading, native compilation, and memory use. Each of these languages surpasses Go in their own ways, but I believe that Google has successfully found that sweet spot in a practical language that minimizes the annoying attributes and boiler-plate, and provides strong typing, resulting in a highly “writeable” language that compiles to native executables. We’ll see how I feel with a few gross more hours under my belt.