Go Observations

A Julia developer returns to Golang and is impressed by the simplicity and speed of the Go toolchain.

Erik Engheim
Feb 26 · 9 min read

I did a bunch of Go programming the past and even held conference talks on Go. But I have been away from Go for a while and did both Swift and Julia programming in the meantime.

Fortunately, Go has remained remarkably stable as a language since I first picked it up, so I don’t have to learn a lot of new things. Rather, it is more of a refresher. The key new thing for me to learn are Go modules as well as familiarizing myself with the tooling around the language. I feel this is where most development has happened.

Here are a few observations of things that are easy to forget but that are important to remember.

You Don’t Need Constructors Most of the Time

I noticed that I had gotten into the habit of adding constructor functions. This is unnecessary and just inflexible in Go.

Go does not have constructors in the language per se but there are conventions for making functions with the New prefix for making objects. This is how I initially made a constructor for a RigidBody. If you’re wondering what that is, it is basically something from physics to simulate how an object that is not elastic moves. You can think of it as a solid steel ball.

This, however, is totally pointless, because Go automatically initializes fields you don’t specify to zero. All you need to do is use named fields like this:

In this case, the Velocity and Elevation fields are set to zero, which is exactly what I wanted. Here are some other variations:

In other words, most of the time you don’t have to bother with constructor functions in Go. This is a lesson I keep having to relearn in Go. It is a language that has really been engineered to keep things as simple as possible and avoid layering and unnecessary abstractions.

Main function goes into the main package

This is an example of the source code file that contains the main() function. You cannot put main functions in any other package but the main package.

You Nest Multiple Packages Within a Module

The relation between packages and modules confused me a bit initially. Does the directory where I store my module have to be named the same thing as the module?

Nope, it doesn’t. Locally, I have my module in a directory called GoRockets. The project structure looks like this:

The start of my enginecluster.go file looks like this:

As you can see, I import the physics package. This is needed for my Mass method which uses the Kg unit defined in the physics package. However, this does not compute. At the time of this writing there is no github repository at github.com/ordovician/rockets/physics.

At first I thought I would have to write something like GoRockets/physics. But because we want to store this package eventually on Github and don’t want to have to go through and change all the source code, Go allows you to use placeholders. The magic happens in the go.mod file that defines my Go module. It looks like this:

The replace statement makes github.com/ordovician/rockets a placeholder for the current directory ./ where the go.mod file is located.

Of course, you can use this to make placeholders for any number of modules you develop locally. That way, your source code can look as if you have already put all these modules online. Once the packages have been pushed online, you can simply change the go.mod file.

One Package Per Directory, Except When…

In general, you can only have one package inside each directory or Go becomes unhappy with you. If you need another package, you can make a sibling or child subdirectory with the other packages.

There is an exception, however: files with names such as tanks_test.go or _foobar.go are not made part of the package. Files with names ending in _test.go are used when you run the command:

You can run this command inside any package directory. Hence you can easily run just a subset of package tests. You can even use this to build a package separately. For example, to build only the physics package:

Running Individual Tests

Go allows you to run an individual test function. Here is a simple test file called tanks_test.go:

I looked up how to run an individual test and I wrote something akin to:

But then I am like: “Did this even work?” I cannot tell if only one function was run or not. The trick here is to add the -v switch, which lists tests run:

Let us compare that with not specifying Medium.

Keep in mind that you are using regular expression matches, so you may accidentally write something that matches every test like this:

REPL Without a REPL Using Test Examples

We Julia developers really love our read-evaluate-print-loop, the REPL. It is the ability to write throwaway code quickly to try out things. How exactly do you do something comparable in Go?

If you are a Go developer, you may be asking why anybody would care to do that. It is not part of your normal routine or habit.

I elaborate on that here: Test-Driven vs REPL-Driven Development.

If you don’t want to wade through that whole article, then here is the key argument I make: Our brains are made for pattern-matching. They are made for reading more than they are made for writing.

You are much better at identifying what is in a picture than drawing it. You are better at reading a sentence in a new language, than uttering it or writing it correctly. The same applies to programming. It is easier to simply push some values into a function and look at what comes out and then decide whether it makes sense than it is to describe ahead of time what ought to come out.

Fortunately, I found a way to mimic my REPL style development in Go using what Go refers to as test examples. This is part of the unit testing system but with a twist. I wrote this example:

This doesn’t look like a test at all. There is no comparison of output values. However, Go checks if the output from your program matches what is written after Output:.

This allows me to fake REPL-style development. I simply write code that I want to test inside a function named ExampleXXX inside a file called xxx_test.go. Naturally, the Xs are just placeholders. Then I put in this comment at the end of the file:

When I do a go test -v it will show me the expected output from my print statements. And that is exactly what I wanted. It avoids forcing me to guess what the output should be like in a normal test. These are not really tests in the normal sense. You can think of them more as example code with regression tests. You just copy-paste the output that Go gives you and put into your source code. That may or may not be the correct output.

But this is where our big super duper pattern recognition brains kick into gear. By printing out the right kind of stuff you can get a sense of whether this looks right or not. I don’t do test-driven development (TDD) so this will instead help me devise sensible tests.

What do I mean by sensible tests? By looking at the output and making some reflections on what I’ve made, I can come up ideas on how to properly test correct behavior.

This is how how I do REPL-based development. I test out stuff in the REPL as I go and then I form ideas of how to write a proper test based on that.

It is worth noting that these test examples can also be used to document how your functions and methods work. For example, the name of the example ExampleSpaceVehicle_Launch() is not arbitrary. Rather, it indicates that it documents the Launch method of the SpaceVehicle type.

This way, you can document how your methods work with small code examples and add regressions tests on this that will tell you if the example code suddenly starts giving different output than expected.

You actually have stuff like this in Julia as well, but I found it almost useless in practice. I feel sorry about saying this since Julia is my favorite language. The problem is, however, that documentation generation is just too slow. In Go, running tests and creating documentation feels instant.

The Go guys have really done a fabulous job of getting all their stuff to run fast and allow for rapid iteration despite not having a REPL environment at your disposal.

Neat Documentation System

Making and viewing documentation for your custom made packages is super fast and easy. Just write:

Or whatever port number you like. This serves up a webpage with the Go documentation at:

Interestingly, this documentation will include both the Go standard library, any library you have downloaded, as well as the custom packages you are building all in one. Here is an example of the documentation that was generated for me. I have collapsed the standard library for easier reading.

Remember my modules file looks like this:

So what you see below the name of my Github account name ordovician is the name of the module rockets. This module contains the various Go packages I have made. The Go packages are really just subdirectories. In the parts subdirectory every file will contain the header:

This is so simple and straight forward that it can actually be a bit tricky to realize that this is all there is to it. No registration needs to be done. There are no elaborate XML or YAML configuration files to write for each package. It is all just convention-based.

And I need to repeat one more time. This stuff just runs fast. In Julia, you don’t want to keep rebuilding documentation frequently. In Go, it is instant and they make it so that the Go documentation server observes you code changes. Hence you can change your source code and hit refresh in your web browser and the documentation changes are immediately reflected.

Star Gazers

“If you want to master something, teach it.”

Erik Engheim

Written by

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Star Gazers

The place that enthusiastic and stargazer to everything.

Erik Engheim

Written by

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Star Gazers

The place that enthusiastic and stargazer to everything.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store