David Rio

Reducing operational cost with go

One of the features of Golang is that you can compile all your program and reduce it to a single binary. The binary is self contained. All the library dependencies are included in the binary. Having a single binary translates in reduced operational costs. Deploying, shipping your code is much simpler. You can cross compile your go source and target different architectures and operating systems.

This website runs in go. My laptop uses an ARM processor and runs in OSX but the code runs in an Intel server. When I ship new versions of this site, I cross compile the binary, rsync it to the server and restart the docker container that runs it.

With other programming languages, you have to make sure that the environment is right. Perhaps you need the right version of python and whatever python libraries your code needs. But python itself may have some other dependencies. Python is written in C and it is typically dynamically compiled meaning that some of the dependencies are linked at runtime:

$ ldd /usr/bin/python3
        linux-vdso.so.1 (0x00007ffdca7c4000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f69ebc57000)
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f69ebc26000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f69ebc0a000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f69eb9e2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f69ec332000)

Most of the time it is pretty straight forward to setup, particularly if you are in a modern linux or Unix distribution. Some other times may not be that easy.

The go runtime

The go runtime includes all the code that implements the logic of all the constructs that the language provides and more: The initial code to start your process, running it in the OS, garbage collection, the implementation of all those magic concurrent primitives. From Jon's book:

Every high-level language relies on a set of libraries to enable programs written in that language to run, and Go is no exception. The Go runtime provides services like memory allocation and garbage collection, concurrency support, networking, and implementations of built-in types and functions.

The Go runtime is compiled into every Go binary. This is different from languages that use a virtual machine, which must be installed separately to allow programs written in those languages to function. Including the runtime in the binary makes it easier to distribute Go programs and avoids worries about compatibility issues between the runtime and the program.

In some systems, that runtime comes separately. In go that is included in the application binary and that has positive operational cost implications. It keeps sysadmins and devs happy.

Have you thought about why many of the successful tools we use for developing software systems these days are written in go? Here are a few of my favorite ones: prometheus, nomad, NATS.io, Red Panda, Tailscale, Caddy.

I'd argue that one of the reasons (and there are many others) is that go generates single binaries for your programs. In fact, most of those tools use that feature as a selling point.