Yesterday I found one of my first Go apps. In a moment of retrospection, I realized how happy I am working with the Go language. I thought I'd take a moment to document why.
Here, in no particular order, are the top 9 reasons I like working with Go:
1. The Toolchain
A C programmer was looking at one of my Go projects. He was sorta irked at me: "Where's your Makefile?" I had to explain to him several times that I didn't need one. The
go tool handled all of that for me. "But what about dependencies?" Handled. "Installing?" Handled. "Generating documentation?" Handled.
Go feels like a language by developers for developers, and nowhere is this evidenced more than Go's fantastic tool chain. Simple and powerful, the
go porcelain makes it dead simple to build, run, format, and debug code.
I like the obvious tools (
go test), but I really love the deeper thought and work that went into things like race detection, formatting code (which I'll come back to), vetting, and installing remote packages (
2. Clean Code
Few developers take this important lesson to heart: When it comes to writing good code, the cleanliness and readability of it is just as important as the functionality. It's good for others who will be reading and editing your code, and it's good for future-you, who will curse past-you when the code is too difficult.
One of my colleagues recently made this remark about Go: "It doesn't seem to matter who writes the code, it all looks similar. I can read it." In my mind, that's one of the highest praises that a programming language as a whole can garner. Yes, sometimes Go is more verbose. Error handling is even intentionally so. But verbosity for the sake of clarity is a noble exchange, and many coding crimes have been perpetrated in the name of brevity.
The fact that coding conventions have been established from the beginning, and are gently enforced by
go fmt (and
golint) contributes to the cleanliness of Go code. But so does the simple syntax and the absence of convenient but often confusingly misused features like ternary operators.
3. Go Routines
We recently ported a major application server from Java to Go. And one of the reasons is that writing good multi-threaded Java code is hard. It's not elegant, it requires a lot of conceptual overhead, and it consumes a lot of resources.
In fact, most of the major languages I've worked with make parallel computing a chore. It used to be the case that when I heard "we need to make it multi- threaded", my brain automatically said, "Add two weeks to the development schedule."
But Go is not like that. Go routines are conceptually simple, functional, and easy on the resources. (We once accidentally generated a few hundred thousand of these on an Amazon small instance!) In fact, working with Go routines is so easy that I now use them by default! I don't even have to think about how I will manage resources or clean up the mess... I merely have to ask whether it makes sense to run in parallel. That's it!
When it's this easy to make the right choice, something was clearly done right.
Hot on the heels of any discussion of go routines, we have to talk about channels. In a nutshell, channels provide a communication layer between go routines. And they work sorta like type-sensitive sockets.
I had about a week to re-implement (on a small scale) a proprietary message queueing system provided to us by a third party. The replacement I wrote had to be compatible with all of their existing libraries, and it also had to be robust enough to handle the real time queueing and relaying.
Channels are such a natural fit for this problem that a core of a few hundred lines handled all of the fanning in and out necessary for the main message queue. With a quick API wrap-around, I had the server done with time to spare. And it was faster than the original solution.
5. Metaphysical Parsimony
I have a substantial background in philosophy. One thing that always fascinates me is reading the different approaches philosophers have taken in the field known as speculative metaphysics. Roughly speaking, this is an exercise in world-making.
In the 17-19th centuries, speculative metaphysics reached something of a pinnacle. Descartes, Spinoza, Leibniz, Hume, Kant, Hegel, and many others devised systems to describe the essential components of reality. Yet if you were to sit down and read metaphysics, one book after another, you'd be shocked at how different each metaphysician's outlook is from the others. To read, say, Hegel compared to Descartes, one would thing two entirely different universes were described.
Programming languages are like that, too. In fact, a programming language is a metaphysical system. It describes what sorts of "realities" you can build. It describes how things interact in that "reality". In fact, it even defines what a "thing" is in that world.
The trouble is, many programming languages get so bogged down in metaphysical purity that it becomes a chore to build things.
Go's approach to the metaphysics of programming is marked by a tendency toward the austere. But not austerity or for the sake of ideological purity. Rather, it feels as if Go was written as an answer to the question "what do we actually need in order to write well-ordered and elegant software?"
The result: Building Go applications is a practical exercise, not an ideological one.