Adventures in Boundary Conditions

Permeating the World in a Particularly Unsubtle Way

Yet Another Take on Golang

Table of Contents

I'm a couple years late to the party, but I've been working with go "professionally" at both Vimeo and Datadog, and I think my issues with this language has finally metastasized into a few areas:

1 Good Parts

  • Go is, I grudgingly admit, the most "workplace productive" language I've used. It is simple enough for other people to read and understand the majority of the time, and for the most part things function as is. gofmt ensures somewhat consistent code style (although I would argue judicious use of git hooks would do the same), and if you were writing your RPC app in python before, Go is definitely an improvement.
  • Concurrency is simple to use, and for the most part, performant until you get up to massive amounts of goroutines. If your application is not working on a massive scale, go's concurrency model works great.

2 The Meh

  • Lack of generics. While for the most part golphers deny needing generics (or worse, say that interface{} is an alternative), you can definitely get by without needing generics for the most part. However, sync.map not being typesafe as a result of the lack of generics is atrocious, and is the prime candidate for why generics should be in go. If not generics, at the very minimum I would like sum types.
  • Error handling is fine, for the most part, and I can suffer through writing if err != nil an astounding number of times (Swift style optionals would go a long way to resolving this). However, error handling across multiple goroutines is not good, as syncronization and error retries are handled poorly.

3 The Bad

  • Dependency management is a dumpster fire. From glide to dep (lol cargo but bad) to vgo go has yet to figure out how to copy maven or even cargo. And you'd think this would be a bigger issue given the number of backwards-incompatible protobuf libraries google puts out.
  • Channels are good as pipes and mediocre queues, but make awful synchronization patterns and worse API's. While the offical documentation suggests using sync.wait, waitgroups continue to feel like a hack lacking a proper language primitive for synchronization. The real bad here is that many developers seem to be convinced on building channel-based API's, even using channels as a queue in their application when channels lack proper recovery mechanism when they fail, no way of reordering channels, and cannot be persisted when your application fails. Stackframes cannot capture channel state, nor is debugging channels a particularly transparent matter.

Overall, go is a language meant for companies that need programmers to just churn something out that is relatively performant, similar to C, and easy to read. It's a language that I'm fairly neutral towards, but it's not (and I doubt ever will be) a language that I enjoy working in.