Every few months I try another language seriously. Rust, Kotlin, TypeScript on the backend, once even Elixir for a few weeks. I always come back to Go. This is my attempt to write down why, partly to understand it myself.
It's not the performance
Go is fast, but that's not why I reach for it. Most of the things I build are not CPU-bound — they're waiting on databases and network calls. Python would be fast enough. Node would be fast enough. Speed is a poor excuse for a language choice at this scale.
It's not the concurrency model either
Goroutines are great, but I've shipped production services that ran entirely single-threaded and the bottleneck was never there. The concurrency story is genuinely good, but it's not the reason I stay.
It's the reading
When I come back to Go code I wrote six months ago, I can read it. Not just parse it — actually read it, like prose. The language makes almost everything explicit. There's no magic inheritance chain to trace, no implicit interface to guess at, no decorator stacking up twelve behaviors on a single method call.
I've heard this called "boring" as an insult. I've come to think of it as the highest compliment. Boring code is code I don't have to think about. When the code is boring, the thinking can go toward the problem.
The error handling is actually good
I know this is the thing everyone complains about. if err != nil
repeated forty times. It bothered me too, for the first year.
Then I worked on a TypeScript codebase where errors were exceptions and half of them were swallowed somewhere in a promise chain that no one fully understood. The application would silently do the wrong thing, successfully, and nobody knew.
Explicit error handling is verbose. It is also honest. Every function that can fail says so in its signature. Every caller is forced to decide what to do about it. That discipline compounds over time into a codebase where you can trust the happy path, because the unhappy path is handled everywhere.
When I shouldn't reach for it
Scripts. Quick throwaway tools. Anything genuinely one-off. Go's compile step and module setup add friction that doesn't pay back on a 40-line script. For those I use Python and don't feel bad about it.
Frontend. Obviously. Numerical computing, ML pipelines, anything where the ecosystem is Python and fighting that isn't worth it.
The honest answer
I keep writing Go because it makes me feel like I understand what my program is doing. That feeling is not always accurate, but it's reliable enough that when something breaks, I can usually find it. With some languages I have the opposite experience: confident the code is correct until suddenly it isn't, and then completely lost about why.
That confidence has a value I didn't appreciate until I lost it.