First Impressions on Go
Last fall, I started learning Go seriously. Since then, I've used it exclusively for personal projects, so here are my takeaways after a few months.
Background: I come from Python. I used it for years, both at work and for side projects. My projects are mostly the same kind of thing: web services, APIs, automation scripts. That's what I've been writing in Go.
Concurrency
Go sells itself as a language built for concurrency. Goroutines and
channels are part of the language. The standard library adds useful
primitives: sync.WaitGroup, atomic operations, mutexes. This
didn't disappoint me. The primitives are raw but versatile. You can pick
the mental model that fits your situation: classic threads, worker pools,
sequential promises (without the function coloring problem of
async/await), callbacks, or pipelines.
That said, concurrent programming in Go is not easy. It's hard, and the usual traps are still there. I've seen people criticize Go for being difficult when writing concurrent code. I don't fully agree. The difficulties I've faced in Go are the same I've always faced, regardless of language. Concurrency is hard by nature, and sure Go makes it more ergonomic and pragmatic, but it won't magically protect you from race conditions, deadlocks, or resource management errors, like writing to a closed channel or leaking goroutines.
Simple and Explicit
Go feels like a language that wants to be explicit. It avoids hiding control flow behind complex constructs. I'll give Go this: its constructs are simple and boring and code reads well. I sometimes read the standard library source, and so far nothing has tripped me up. Indirection levels are kept under control and even code wirtten by those smart Go contributors is explicit and easy to read.
Let's take a recent example:
func IPv6PrefixToUint(ipV6Addr net.IP) uint64 {
if len(ipV6Addr) == 16 {
return binary.BigEndian.Uint64(ipV6Addr[0:8])
}
return 0
}
No hidden details here. Eight bytes are read in big-endian order to create
a uint64-integer. The function name says exactly what it does: BigEndian.Uint64.
Quality Culture
Testing tools are well integrated. You'd expect this from any post-2000 language, but Go's tooling left me with a good impression. Setting up tests is easy. Examples double as tests and end up in generated documentation. Benchmarks let you measure progress or catch regressions.
Recently, Go started working on native fuzzing support. This kind of attention signals a language (and community) that genuinely tries to solve real engineering problems.
Performance
Go's performance hasn't disappointed me. I've inspected the generated assembly a few times (Go 1.15 and 1.16). The compiler still misses optimizations that veterans like GCC or LLVM would happily catch, but the compiler improves with each release, and performance clearly matters to the contributors.
The Go contributor also maintains hand-written assembly for performance-critical functions in the standard library. The crypto packages are full of it (e.g., AES, SHA-256, elliptic curves, etc., all with architecture-specific implementations leveraging hardware instructions). Same for CRC32 and other maths-related code. Like I said: performance matters to the contributors, and they seem to take it seriously where it matters.
For me, this is a real win. I increasingly use managed cloud services, even for personal scripts. Cloud billing is often based on resource consumption, so I have an incentive to keep it low. Go might not match C, C++, or Rust, but coming from Python, the improvement is pretty huge, and I am more than happy.
Other Things I Like
A few more points, in no particular order:
-
Cross-compilation is straighforward:
GOOS=linux GOARCH=arm64 go buildand you're done. - Static binaries. Easy containerization, lightweight images, no libc headaches.
- Fast startup time. Matters for serverless billing and container orchestration.
- The sweet spot between low-level and high-level. Not as low as C, not as high as Python. Just right for my needs.
Conclusion
Go hasn't revolutionized how I think about programming. It just gets out of the way and lets me ship things. Coming from Python, that's exactly what I needed.