When I first learned about Go, Google’s very own programming language, I was intrigued. Designed and released in 2007, Go, a.k.a. Golang, was among a crowd of new languages—Rust, D, Nim, Scala, Clojure—generating buzz in the early to mid 2010s: At the time, programmers seemed eager to move away from the verbose baggage of older backend languages (Java, C++) as well as the computational inefficiency and type unsafety of dynamic languages used on the web (PHP, Ruby, Python). They wanted type safety, which meant they wanted static typing. And they wanted speed.
It was easy to find stories about startups, like IronMQ, that went from dozens of servers used for hosting Rails to a couple that could be hosted in a language like Go. And as someone who was, at the time, steeped in PHP5 and all its problems, I counted myself among the crowd of those interested.
When I first came across Go, in my old gig as CTO at ActiveCampaign, I tried writing some code in it. And I didn’t like it. It gave me problems whenever I left a variable unused or imported an unused package. Go was particularly strict about typing—I was familiar with PHP’s type coercion, but I was also used to C and C++, which let you mix signed and unsigned integers, as well as mix integer sizes (16-bit, 32-bit, 64-bit).
Go didn’t have generics. In fact, one of its chief language designers (Rob Pike) was rather strident about what the language lacked. As Pike put it, this was a good thing, and good for you. The language was designed for the “average” engineers who worked at Google, if you can call them that. In some sense, what you read about Go at that time felt like a put-down. And to this day, it’s not hard to find people who continue to share that criticism.
So what changed my mind?
Go is simple. It stands apart from other languages in that regard. Simplicity is a virtue, and any complexity that one introduces to the language is carefully considered.
For a long time—too long, if you ask some—Go lacked any real package management. It was only in 2018—after several rounds of community engagement and an unofficial experimental package manager called “dep”—that any official support for their solution (“modules”) was added to the language.
But within that simplicity you find a lot of value. You can easily write some one-liners in Ruby that do cool stuff, but hidden in those one-liners is a lot of magic: It’s hard for the unassuming developer to always grasp the process that goes on behind the scenes. Maybe it takes five lines of code to write the same thing in Go, but you know what those five lines are doing.
Go also takes away one of the classical concepts in OOP: inheritance. You can’t write a base class in Go and have another class inherit from it. In fact, you don’t have “classes” at all.
At first, it feels like a tremendous constraint to have one of the basic tools of code reuse and encapsulation taken from you. And it’s natural for your first inclination to be a feeling of resentment.
But, these days, you often don’t use inheritance, even if you could. You use interfaces, you focus on behavior and abstractions—and this you can easily do in Go. In fact, it’s all you can do in Go. After a while, the lack of inheritance feels good because you’re avoiding a layer of technical debt by not having to revisit the dangerous nest of relationships you’d built up using inheritance. Maybe Pike was onto something after all.
Today, Go has carved out a defined slot in the language ecosphere. It’s not trying to replace C++, as it was once thought (and suggested). While you might have thought you needed Java for a certain project 10 years ago, these days, you may be better off reaching for Go.