What's the Go language really good for?

Learn the strengths, weaknesses, use cases, and future directions of Google's hit programming language

What's the Go language really good for?
Bill Selak (CC BY-ND 2.0)

During its eight-plus years in the wild, Google’s Go language—with version 1.8.1 out as of April 2017—has evolved from being a curiosity for alpha geeks to being the battle-tested programming language behind some of the world’s most important cloud-centric projects. 

Why was Go chosen by the developers of such projects as Docker and Kubernetes? What are Go’s defining characteristics, how does it differ from other programming languages, and what kinds of projects is it most suitable for building? In this article, we’ll explore Go’s feature set, the optimal use cases, the language’s omissions and limitations, and where Go may be going from here.

Go small and simple

Go, or Golang as it is often called, was developed by Google employees—chiefly longtime Unix guru and Google distinguished engineer Rob Pike—but it’s not strictly speaking a “Google project.” Rather, Go is developed as a community-led open source project, spearheaded by leadership that has strong opinions about how Go should be used and the direction the language should take.

Go is meant to be simple to learn, straightforward to work with, and easy to read by other developers. Go does not have a large feature set, especially when compared to languages like C++. Go is reminiscent of C in its syntax, making it relatively easy for longtime C developers to learn. That said, many features of Go, especially its concurrency and functional programming features, harken back to languages such as Erlang.

As a C-like language for building and maintaining cross-platform enterprise applications of all sorts, Go has much in common with Java. And as a means of enabling rapid development of code that might run anywhere, you could draw a parallel between Go and Python, though the differences are far greater than the similarities.

Something for everyone

The Go documentation describes Go as “a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.” Even a large Go program will compile in a matter of seconds. Plus, Go avoids much of the overhead of C-style include files and libraries. In short, Go makes the developer’s life easy in a number of ways:

Convenience. Go has been compared to scripting languages like Python in its ability to satisfy many common programming needs. Some of this functionality is built into the language itself, such as “goroutines” for concurrency and threadlike behavior, while additional capabilities are available in Go standard library packages, like Go’s http package. Like Python, Go provides automatic memory management capabilities including garbage collection.

Unlike scripting languages such as Python, Go code compiles to a fast-running native binary. And unlike C or C++, Go compiles extremely fast—fast enough to make working with Go feel more like working with a scripting language than a compiled language. Further, the Go build system is less complex than those of other compiled languages. It takes few steps and little bookkeeping to build and run a Go project.

Speed. Go binaries run more slowly than their C counterparts, but the difference in speed is negligible for most applications. Go performance is as good as C for the vast majority of work, and generally much faster than other languages known for speed of development (e.g., JavaScript, Python, and Ruby).

Portability. Executables created with the Go toolchain can stand alone, with no default external dependencies. The Go toolchain is available for a wide variety of operating systems and hardware platforms, and can be used to compile binaries across platforms.

Interoperability. Go delivers all of the above without sacrificing access to the underlying system. Go programs can talk to external C libraries or make native system calls. In Docker, for instance, Go interfaces with low-level Linux functions, cgroups, and namespaces, to work container magic.

Support. The Go toolchain is freely available as a Linux, MacOS, or Windows binary or as a Docker container. Go is included by default in many popular Linux distributions, such as Red Hat Enterprise Linux and Fedora, making it somewhat easier to deploy Go source to those platforms. Support for Go is also strong across many third-party development environments, from Microsoft Visual Studio Code to ActiveState’s Komodo IDE.

Where Go goes best

No language is suited to every kind of job, but some languages are suited to more jobs than others. Go shines brightest when developing a few key application types:

Distributed networked services. Network applications live and die by concurrency, and Go’s native concurrency features — goroutines and channels, mainly—are well suited for such work. Consequently, many Go projects are for networking, distributed functions, and cloud services: APIsweb serversminimal frameworks for web applications, and the like.

Cloud-native development. Go’s concurrency and networking features, and its high degree of portability, make it well-suited for building cloud-native apps. In fact, Go was used to build one of the cornerstones of cloud-native app development, the app containerization system Docker.

Replacements for existing infrastructure. Much of the software we depend on for Internet infrastructure is aging and shot through with exploits. Rewriting such things in Go provides many advantages—better memory safety, easier cross-platform deployment, and a clean code base to promote future maintenance. A new SSH server called Teleport and a new version of the Network Time Protocol are being written in Go and offered as replacements for their conventional counterparts.

Where Go doesn’t go

Go’s opinionated set of capabilities has drawn both praise and criticism. Go is designed to err on the side of being small and easy to understand, with certain features deliberately omitted. The result is that some features that are commonplace in other languages simply aren’t available—on purpose.

One such feature is generics, which allow a function to accept many different types of variables. Go does not include generics, and the stewards of the language are against adding them, on the basis that generics would compromise the language’s simplicity. It’s possible to work around this limitation, but many developers are still itching to see generics added to Go in some fashion.

Another downside to Go is the size of the generated binaries. Go binaries are statically compiled by default, meaning that everything needed at runtime is included in the binary image. This approach simplifies the build and deployment process, but at the cost of a simple “Hello, world!” weighing in at around 1.5MB on 64-bit Windows. The Go team has been working to reduce the size of those binaries with each successive release. It is also possible to shrink Go binaries with compression or by removing Go’s debug information.

Yet another touted feature of Go, automatic memory management, can be seen as a drawback, as garbage collection requires a certain amount of processing overhead. By design, Go doesn’t provide manual memory management, and garbage collection in Go has been criticized for not dealing well with the kinds of memory loads that appear in enterprise applications. On the plus side, Go 1.8 brings many improvements to memory management and garbage collection that reduce the lag time involved. Of course, Go developers do have the ability to use manual memory allocation in a C extension, or by way of a third-party manual memory management library.

The culture of software around building rich GUIs for Go applications, such as those in desktop applications, is still scattered.

Most Go applications are command-line tools or network services. That said, various projects are working to bring rich GUIs for Go applications. There are bindings for the GTK and GTK3 frameworks. Another project is intended to provide platform-native UIs, although these rely on C bindings and are not written in pure Go. And Windows users can try out walk. But no clear winner or safe long-term bet has emerged in this space, and some projects, such as a Google attempt to build a cross-platform GUI library, have gone by the wayside. Also, because Go is platform-independent by design, it’s unlikely any of these will become a part of the standard package set.

Although Go can talk to native system functions, it was not designed for creating low-level system components, such as kernels or device drivers, or embedded systems. After all, the Go runtime and the garbage collector for Go applications are dependent on the underlying OS. (Developers interested in a cutting-edge language for that kind of work might look into Mozilla’s Rust.)

Where to Go from here?

Go may be coming to a crossroads of sorts. The next phase in Go development may well be driven more by the wants and needs of its developer base, with Go’s minders changing the language to better accommodate this audience, rather than just leading by stubborn example. In other words, Go may gain the features that were originally not intended for it, like generics.

It’s clear Golang developers want these things. The 2016 Golang user survey placed generics at the absolute top of the list of “what changes would improve Go most,” followed by better dependency and package management. And an existing proposal on GitHub for generics remains active as a proposal for Go 2.x. Changes like these may help Go take a more central place in enterprise development, where Java, JavaScript, and Python currently reign supreme.

Even without any major changes to Go, expect to see greater use of the language for rebuilding infrastructure, and as part of multi-language project. One project that partially leverages Go for systems programming is Ethos, an OS intended to serve as a platform for highly secure software. The kernel is written in C, but the userspace applications will be written in Go—a smart way to render unto C what is suited to C, while leveraging the strengths of Go.

Third-party implementations of the Go toolchain are also proliferating. ActiveState’s ActiveGo provides a commercially supported edition of Golang, and both the LLVM and gccgo projects provide liberally licensed open source implementations of Go by way of alternate toolchains.

Another way Go may evolve is by serving as a base for developing other, entirely new languages. One example is the Have language. Have takes many ideas from Go and transpiles into Go for easy execution, but streamlines the Go syntax and implements some of the same concepts in its own way. A project named Oden, unfortunately no longer being developed, used Go’s assembler and toolchain to compile a newly designed language that took additional inspiration from languages like Lisp and Haskell.

This last set of projects illustrate one of the ways any IT innovation becomes truly revolutionary—when people take it apart and repurpose it, finding uses its designers never intended. Golang’s future as a hackable project is just getting started. But its future as a major language seems assured, certainly in the cloud, where its speed and simplicity make it easy to build scalable infrastructure that can be maintained in the long run.

Copyright © 2017 IDG Communications, Inc.

How to choose a low-code development platform