Last week I delivered a talk on teaching Go at the Denver Gophers meetup. The talk included a number of what I called “controversial opinions” on Go and I have foolishly decided to make them a matter of public record.
Go is not a first language
The Go language is missing many features - objects, exceptions, and generics to name a few - but I’m not missing them. These omissions were done intentionally and were meant to turn several mainstream programming paradigms on their heads.
But it’s impossible to teach a paradigm in a language where it doesn’t exist. If I could guarantee that a new programmer would only ever write Go, I would gladly teach them its opinionated ways. That belief, however, is folly, and programmers should be exposed as soon as possible to more extensive languages, such as Python and Java.
Go is ugly
The tooling built into Go, especially
go fmt and integrated testing and benchmarking, ended numerous debates before they even began. By embracing strict semantics, Go also shrugged off superfluous semicolons and parentheses that have haunted many C-esque languages.
Despite these advances, I still believe Go to be ugly. It is mostly the verbosity and duplication of error checking, even though I agree with the purpose of errors. An over abundance of left-sided whitespace and repeated variables can activate the Spidey sense of programmer brains. Aesthetic arguments, however, are subjective and formed by experience. And if callbacks can be beautiful in Node.js, it is only a matter of time…
Go is young
The first stable release of Go was in March 2012. And despite its rapid adoption, it is still a language that was conceived after the first release of Python 3.
With this in mind, it seems unnecessary to state that the ecosystem is young and incomplete. But this problem is exacerbated by Go’s dependency management, which pulls from the master branch of remote repositories without an option to specify an alternative. Combined with project maintainers that commit to master (myself included), the only solution is forking or third-party tools.
Its youth also means a lack of best practice. Even though I would consider Go a small language, numerous questions still abound: Should the
reflect package be avoided? When is it acceptable to use
panic? Type-casts? Embedding? What shouldn’t be exported from a library? Can I refer to a package as a framework without being yelled at on the go-nuts mailing list?
Go loves purpose
During the talk, I stated “Go loves requirements” and that it’s a perfect language for building version two of a product. While I still believe this, discussion with the team at SupportLocal convinced me to make a slightly more inclusive point.
Go is being used to replace legacy systems at Google, SendGrid, Cloudflare, and others. But Go is also being used to write software that solves long-standing problems, such as Heka, Docker, and Doozer. By providing a new set of paradigms and primitives, Go has brought a number of problems from the “we’ll solve it later” to the “let’s solve it now” category.
And while Go is perfectly suited for this type of purpose driven development, I also believe the inverse: there is a major penalty to be paid when writing open-ended Go. A lack of generics means code duplication. Usage of the
reflect package removes type safety at compilation. The standard library is comprehensive, but often goes too far with unexported identifiers.
Go is here to stay
I started programming Go over two and a half years ago. I was looking for a language that was built for the web and could help me build concurrent and distributed systems. I had almost settled on using Erlang (and its one-based indexing) before I discovered Go. I immediately feel in love with channels and first-class interfaces.
Go did not get everything right and it did little to advance the state of programming languages. But Go has refined the practice of programming more than any other modern language. It is small, readable, and includes a brilliant standard library. It is also here to stay.