The Doors Go Has Opened
--
Go has quickly become the most popular and successful systems programming language of the last 10 years.
Before Go, C, C++, Java, and C# were the big dogs in the systems programming world. Go is still a baby even today, but it’s coming for you.
It’s opened up a new world of open source software. It was the perfect language that came at the right time, and it’s sparked a new era of computing. All of this high-profile software is written in Go:
- Kubernetes: a container orchestrator used in production by large companies to run distributed services. Other companies have been started around building, hosting and supporting this software
- etcd: a strongly consistent key/value store. It’s used in mission critical distributed systems and in practice has become the open-source equivalent of Google’s Chubby. It’s a central component of Kubernetes
- Docker: the most popular container runtime on the market right now. Also a central component of Kubernetes
Cloud Native wouldn’t be possible without Go, and neither would the Cloud Native Computing Foundation. And that’s just to start. Go is taking over other parts of open source too, not to mention major parts of the internal infrastructure of big companies.
Here’s why practically everyone in open source (and elsewhere) is choosing Go to build, and rebuild, production systems and big software.
Toolchain
Everyone who tries Go starts with the Go playground. You go to a website, write some code, and run it. Nothing to install, works everywhere, and a great first-time experience.
Whatever you’re building, you focus on building it. Go already figured out the tooling for you
Then you download the toolchain — a single binary called go
. You can run go build
and you get production-grade software ready to run. No learning the GCC toolchain, clang, linux shared objects, the JVM, or anything else.
Whatever you’re building, you focus on building it rather than the tools you need. Go already figured them out for you.
You can spend your time and energy solving real problems and building real products.
A Single Binary
With the old dogs, you compiled your code but you couldn’t just run it. It needed something else on the system to run: shared objects, a JVM, and so on.
Just ship a binary to your server and you’re done
go build
spits out a single binary ready to run. Publish it and ship it to your servers. It works because it has everything you need compiled right into it.
This simple fact has powerful implications. The best thing about it is that your deployment process can be so much simpler than before— just ship a binary to your server and you’re done.
You can even build for different OSes with a few environment variables. This feature is great for CLIs. Some of the most successful ones:
etcdctl
: the CLI for etcdkubectl
: the CLI for Kubernetesdocker
: the CLI for the Docker serverdep
: the CLI for the new Golang package manager
Concurrency
The cloud isn’t new anymore, it’s the standard. VMs and containers live and die without notice, streams of data come and go non-deterministically, and RPCs are sent and retried constantly.
Instead of wrestling with threads, you put '
go’
in front of a function and it’s running concurrently
For modern software to work properly and efficiently, it needs to handle all these events concurrently. Distributed, fault-tolerant architectures are the norm today.
With the old dogs, you had to deal with OS threads, locks, condition variables and so on. Getting to the point of being able to write an efficient, resilient system meant learning — or inventing — a concurrency framework before you could move on.
Now you get built-in primitives that are easy to understand. Goroutines and channels make sense because they mimic the real world.
The end result is that you put go
in front of a function and it’s running concurrently. You can easily understand all this concurrency and again you can focus on building your product. Seeing a trend?
Go has unlocked powerful distributed systems because it makes concurrency radically easier than before.
That’s why we’re seeing more resilient, faster and more CPU efficient software. With Go, you can actually build stuff that you read in research papers.
Garbage Collection
GC is a controversial topic for Go and systems programming in general.
We can have a systems programming language and GC at the same time
In C/C++ land, you have complete control over memory. You decide when and how you allocate and release memory. The JVM has gone the other way and given up this control by shipping a garbage collector.
Overall, GC is convenient, but stop the world times have bitten lots of folks. Hard.
Manually managing memory is hard, and harder still when you have concurrency going on. Before Go, we were stuck with conflicting challenges: we needed a framework that won’t leak memory or break your program, but it had to make sense to programmers.
The end result was millions of libraries that make different tradeoffs and always force you to think about your program in a unique, specific way.
Go took a stand and said:
- Nothing will ever be easier than not having to think about memory
- We can “sit in the middle” and build a systems programming language with GC
Go is a systems programming language with GC. Hell has frozen over.
The reality is that GC has been a huge driver for Go’s explosion. There are edge cases in Go’s garbage collector that can cause problems for some. But lots of thought has gone into making it work properly — by default — for 90% of programs.
If you do hit that 10%, you can turn some knobs, and even that’s a lot easier than tuning the JVM garbage collector.
Standard Library
The Go standard library is one of the best in the biz. It’s not huge but it covers 80% of use cases, and it’s not complex but it lets you do complex things.
The ethos is all about agreeing on ideas, codifying them, and reusing them
Popular Go packages are high quality because they’re built on the high-quality standard library.
More importantly than the standard library’s code is its ethos. Generally speaking, it encourages the reuse of interface
s and idioms. Examples:
io.Reader
andio.Writer
are the ways to “pipe” data across function boundaries. These interfaces are probably the most implemented across the entire Go ecosystemcontext
is the way to provide cancellation, timeout, and value propagation semantics to goroutineserror
is the way to return and describe errors from functions
Packages generally agree on these and other common idioms, and so they work together smoothly.
The ethos is all about agreeing on ideas, codifying them, and reusing them.
Conclusion
I said in the beginning of this article that Go is the perfect language that came at the right time.
Go will become the standard programming language for several large domains in software engineering
I’ve explained why, but the bottom line is that Go has made the right things easy enough to unlock some of the most powerful and advanced software we’ve ever seen in open source.
I expect Go to continue becoming the standard for other use cases — frontend servers (replacing Rails/Node.js), CLIs (replacing many scripting languages), and maybe even GUIs and mobile apps.
The language just hit its 8 year anniversary, and its rise has been meteoric. But the next 8 years are going to be ten times bigger.
Go will become the standard programming language for several large domains in software engineering.