{ karel.codes }

Go: The good, the bad, and the ugly

programming

Go has grown on me since I have been using extensively in the last couple of years. But like anything that isn’t pancakes, it isn’t perfect. Let’s take a look at the pros and cons of Go.

The good

  • Go gets out of your way. The code is easy to read and understand so you never have to wonder why a piece of code doesn’t compile. It doesn’t force overbearing abstractions on you. At the same time it gives you the tools to write programs that have good performance.
  • Good standard library. The net/http package is of course the crown jewel, but the standard library also offers many other useful packages such as compress, crypto, io, bufio, encoding/json, database/sql, unicode and others that provide interfaces and functionalities that are crucial for writing good software but are often deficient or missing in other standard libraries.
  • Good tooling built into the go command. Building, formatting, testing, profiling and dependency management are all included in a single binary and that’s just very handy.
  • Good concurrency model. As far as I know Go is the only mainstream programming language that offers effortless M:N threading. Starting concurrent threads is as easy as using the go statement and they are automatically multiplexed over the available CPU cores.
  • Cross compilation just works. Building a Windows executable on OSX is as easy as installing mingw and telling go build the target platform. It worked the first time for me.
  • Easy to deploy to the cloud. Go executables can be built without any external dependencies, not even libc, which means that you can build tiny Docker containers from scratch that contains only the executable itself and nothing else.
  • Go hands down has the cutest mascot, the Go Gopher!

The bad

  • Can be too conservative. It took the Go team a long time to design and implement generics and proper dependency management. I can live without generics but why they thought $GOPATH was ever a good idea is beyond me. Now they are taking their time to update the standard library to use generics where it makes sense (the math and container packages).
  • The concurrency model doesn’t help you write correct concurrent code. You can easily create deadlocks if you don’t manage channels properly. It would also be nice to have more standard tools to handle concurrency besides just sync.WorkGroup.
  • No dynamic linking, so you can’t load plugins compiled by others. It’s not a crucial feature but there are some use cases where this would be a really handy to have.
  • Lack of specialized libraries due to the fact that Go is mostly used to write backend web services and CLI tools. It doesn’t have any good machine learning libraries for example.

The ugly

  • You have to get used to if err != nil { ... }. It’s tedious but at the end of the day it does make error handling explicit rather than throwing exceptions in the air without regard for where they will land.
  • The Go team wants to add telemetry to the Go toolchain. I’m sure that the team has good intentions but the fact remains that they work for Google and they will use Google servers. Google simply can’t be trusted not to abuse any kind of data. It also doesn’t help that they wanted to make it opt-out at first, but at least they did change their minds to opt-in after getting too many complaints.
  • Go’s compiler is unique in that it produces machine code that significantly differs from the C/C++ standard. There are good reasons for this but it does make it hard to interop with libraries written in other languages and makes Go a bit of an island.
  • There is a trend in some programming circles to poop on Go essentially because it isn’t Rust. I think that Rust is a good language but I see it as a modern replacement for C++, whereas Go fills a previously unfilled niche between low-level compiled languages and high-level scripting languages. They are different tools for different jobs.

Conclusion

There you have it. Go has its weak spots but on the whole it is a good language that is easy to read, write and maintain. Nowadays I prefer it over Python for writing backend services. It’s even a suitable choice for writing cross-platform 2D video games with Ebitengine.