Over the last year, I’ve been slowly teaching myself Go. As a Python programmer who previously studied Java and Perl (veeeery briefly), I wanted to know what learning Go would teach me about programming and problem solving in general (à la the Blub Paradox). However, as I’ve continued learning Go, I’ve become increasingly curious about some of the unique features of the language (e.g. automatic memory management and Goroutines), and how they might help me to solve classes of problems I haven’t yet encountered. But… before we get to all that, this is just a quick post that goes over some of the basics of getting started with Go, including notes on installation, the go tool, and workspaces.
Notes on Installing Go (Assuming OSX)
When you download and open the Go distribution, and follow the installation prompts, the package installs the Go distribution to
/usr/local/go and puts the
/usr/local/go/bin directory in your PATH environment variable. Check by opening up your bash profile:
cd ~ open .bash_profile
After installation, you should see a new line:
# Golang export PATH=$PATH:/usr/local/go/bin
The Go Tool
The current distribution of Go comes packaged with the go tool, a command line interface for performing common tasks like running, building, and installing code, and also retrieving public packages and necessary dependencies from distributed version control systems like GitHub.
Some commands include (in the below examples, imagine that
add.go is an example source file that has
package main as the first line, and
ballast is a local Go package, potentially with multiple files):
go run add.goruns the code from the hypothetical
add.gofile. It uses a temporary directory to build, execute, and clean up, but does not produce an executable artifact. Note: this can be useful for development.
go build: assuming our
add.gofile is package
go build add.goexplicitly compiles the file to produce an executable that can be deployed and run without the go tool.
go buildputs the executable in the current directory.
go install add.goalso compiles
add.goand produces an executable, but puts it in $GOPATH/bin.
go get github.com/rebeccabilbro/ballastwill clone the
ballastrepo from GitHub user
rebeccabilbroonto our local machine, placing it inside $GOPATH/src, in a local folder
src/github.com/rebeccabilbro/ballast. It will also automatically build and install
ballastinto $GOPATH/pkg, storing a package object
ballast.ain a folder
pkg/darwin_amd64/github.com/rebeccabilbro. Note: the
darwin_amd64part is an automated way of capturing semantically which operating system and processor architecture were used in the local build/install process.
go fmt src/github.com/rebeccabilbro/ballastautomatically reformats code (e.g. spacing, line breaks, etc) in all the files in the hypothetical
ballastpackage to conform with current idiomatic practice.
go helpwill list out all the go tool commands, while
go help <command>will provide more information about that command, as well as any optional flags.
Code Organization in Go
The next step is to establish your Go “workspace”. But… what’s a workspace? The idea of a workspace is one of the things that makes the practice of writing Go code a bit different than with other languages. When I’m writing Python code, it can go anywhere.
So maybe I’ll have something like:
~ └─ random_python_script.py └── Desktop | └── another_random_script.py └── stuff | └── yellowbrick | | └── yellowbrick | | | └── __init__.py | | | └── anscombe.py | | | └── base.py | | | └── bestfit.py | | | └── classifier | | | | └── __init__.py | | | | └── base.py | | | | └── boundaries.py | | | └── ... | | └── ... | └── ... | ...
.py files are all over the place - some in standalone scripts and others in packages with
__init__.py files, and everything still runs fine!
Go imagines a different approach to code organization, the workspace.
Your Go Workspace (GOPATH)
A Go workspace is a directory hierarchy to house the Go source code for a project. It will also end up containing the package objects and command binaries that the compiler produces from your source code. Technically, workspaces can live anywhere, and you could even have multiple ones, but that’s not considered a best practice in the Go community.
Let’s create a workspace called
goplaces inside my
~$ cd ~ ~$ cd Projects ~$ mkdir goplaces # create workspace dir ~$ export GOPATH=/Users/rebeccabilbro/Projects/goplaces # make Go tool aware of workspace
Where to Put Your Source Code
Now let’s create a folder to store the source code (
src) for my Go projects. By convention, we create a subfolder for the remote version control system we will be using to host the code, which theoretically for me might include both personal projects hosted on GitHub and work projects hosted on Gitlab, e.g.:
~$ cd goplaces ~$ mkdir src/github.com/rebeccabilbro ~$ mkdir src/gitlab.com/rbilbro
We create folders with the same names as my Github and Gitlab usernames because when I
go get packages from other developers that are publicly hosted, the go tool will create subfolders named after their usernames to store those packages in.
Where Go Puts Things
Remember in the part above where we were talking about
go install? Assuming the package we’re installing is package
go install compiles it and produces an executable that it will put in $GOPATH/bin. So let’s create a directory to store those executable commands:
~$ mkdir bin
And also add the GOBIN to our path, which will tell Go explicitly where to put the results of
~$ export GOBIN=/Users/rebeccabilbro/Projects/goplaces/bin
Lastly, we’ll create a directory to store package objects
~$ mkdir pkg
Note: the workplace subdirectories
bin will be created automatically by the go tool when they are needed, but it’s useful to create them explicitly so that we understand their purposes and have all our paths set correctly.
An Example Workspace
So here’s an example of what a workspace might look like:
goplaces └── bin | └── ballast # example executable, result of installing ballast from src └── pkg | └── darwin_amd64 | | └── github.com | | | └── bbengfort # package objects from `go get`-ing bbengfort's source code | | | └── capillary.a └── src | └── github.com | | └── rebeccabilbro | | | └── axiomatic # in dev mode (`go run` only, so no `/bin` executables) | | | | └── raise.go | | | | └── resolve.go | | | └── ballast # a finished project, installed via `go install` | | | | └── add.go | | | | └── add_test.go | | └── bbengfort # another user's source code retrieved via `go get` | | | └── capillary | | | | └── pump.go | | | | └── ... | └── gitlab.com | | └── rbilbro | | | └── dumbledore # project made for work | ...
What About GOROOT?
It used to be necessary to set a lot of other paths manually in addition to GOPATH. Following changes made to the Go distribution & installation package, we no longer need to set GOROOT. The correct value is already embedded in the Go tool. More about that here.
Ok, that’s all for now!
- Getting Started (from the official docs)
- How to Write Go Code (from the official docs)
- Go Start
- Writing, building, installing, and testing Go Code screencast
- Organizing Go Code
- Organizing Go Code to Support Go Get
- Setting up a Go Development Environment
- Filesystem Structure of a Go Project
- Go Project Layout
- go install vs go build
- Go Programming