What’s the Go language really good for?

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

During its nine-plus years in the wild, Google’s Go language, aka Golang—with version 1.13 out as of September 2019—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 language is 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.

Go language has 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.

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 language works best

No language is suited to every job, but some languages are suited to more jobs than others.

Go shines brightest for developing the following 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 several cornerstones of cloud-native computing including Docker, Kubernetes, and Istio.
  • 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.
  • Utilities and stand-alone tools. Go programs compile to binaries with minimal external dependencies. That makes them ideally suited to creating utilities and other tooling, because they launch quickly and can be readily packaged up for redistribution.

Go language limitations

Go’s opinionated set of features 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 in Go—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. At least one proposal for implementing generics in Go has been raised, but nothing has been set in stone.

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. This last option may work better for stand-alone distributed apps than for cloud or network services, where having debug information is useful if a service fails in place.

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 the Rust language.)

Go language futures

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 2018 Go user survey placed generics among the top three challenges in the way of broader Go adoption, along with 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 major changes, we can expect increased use of Go for infrastructure rebuilding projects, as per the replacements for SSH and NTP described above, and as part of multi-language projects. 

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

Finally, Go has also served as a base for developing entirely new languages, although two examples of this have ceased active development. One example was the Have language, which streamlined Go syntax, implemented some of the same concepts in its own way, and transpiled to Go for easy execution. Another defunct project, Oden, 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. The future of the Go language as a hackable project is just getting started. But its future as a major programming language is already assured, certainly in the cloud, where the speed and simplicity of Go ease the development of scalable infrastructure that can be maintained in the long run.

Copyright © 2019 IDG Communications, Inc.