Next Steps in Go: Code Organization

October 27, 2013 Jared Carroll

My first steps in learning Go were simple “scripts”; programs compiled and immediately executed by the go command-line tool. This was a great way to quickly get started; kind of similar to using a REPL. However, I soon wanted to learn how to structure larger programs, create reusable libraries, and use third-party code. In this post, we’ll look at how Go code is organized into packages, the various commands to build and install them, and how to integrate third-party libraries.

Packages

All Go programs and libraries are defined in packages. Packages are named after the final part in their directory path. An import declaration is used to load a package.


package main

import (
  "net/http"
  "fmt"
  "io/ioutil"
)

func main() {
  resp, err := http.Get("http://www.google.com")
  if err != nil {
    panic(err)
  }

  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    panic(err)
  }
  fmt.Println(string(body))
}

The entry point for every Go program is the main function in the main package. This program imports three packages from the Go standard library. A package’s name is used to access its exported interface. In this example, http is used to access the package’s Get function.

Creating a Custom Package

The first step in creating a custom package is to create a workspace. A workspace is a directory hierarchy containing three subdirectories:

  • src – Go source code organized into packages
  • pkg – OS and architecture specific compilation artifacts
  • bin – executable Go programs

When you import a custom package, Go looks for its definition in each workspace listed in the GOPATH environment variable.

Let’s create a workspace and set the GOPATH.


% mkdir -p ~/Projects/golang/src

% export GOPATH=~/Projects/golang/

Our custom package will be defined in a src subdirectory.

~/Projects/golang/src/foo/foo.go


package foo

import (
  "fmt"
)

func Bar() {
  fmt.Println("bar")
}

% tree golang
golang
└── src
    └── foo
        └── foo.go

A Go package is named after its directory. Within its directory, it can be implemented in any number of arbitrarily named files. In this example, I chose to name our custom package’s only file after the package.

Importing a Custom Package

With this directory structure in place and the GOPATH set, we can now create a Go program that can import and use our custom package. This program will also be defined in a src subdirectory.

~/Projects/golang/src/fooer/fooer.go


package main

import (
  "foo"
)

func main() {
  foo.Bar()
}

% tree golang
golang
└── src
    ├── foo
    │   └── foo.go
    └── fooer
        └── fooer.go

Our next step is to build and install this program.

Building Go Code

Build Go code using the go command-line tool’s build command.

Building a program creates an executable file in the program’s directory. The executable file is named after its directory.


% pwd
/Users/jared/Projects/golang/src/fooer

% go build

% ls
fooer fooer.go

% ./fooer
bar

Building a custom package results in no build artifacts.

Installing Go Code

Install Go code using the go command-line tool’s install command.

Programs are installed in the workspace’s bin directory.


% pwd
/Users/jared/Projects/golang/src/fooer

% go install

% ls ../../bin
fooer

Custom packages are installed in an OS and architecture specific subdirectory in the workspace’s pkg directory.


% pwd
/Users/jared/Projects/golang/src/foo

% go install

% ls ../../pkg/darwin_amd64
foo.a

Add $GOPATH/bin to your PATH to make executing Go programs easier.

Integrating Third-Party Go Code

Integrate third-party Go code using the go command-line tool’s get command. Third-party code is downloaded and installed in the first workspace listed in the GOPATH.


% pwd
/Users/jared/Projects/golang/src

% go get -v code.google.com/p/freetype-go/freetype
code.google.com/p/freetype-go (download)
code.google.com/p/freetype-go/freetype/raster
code.google.com/p/freetype-go/freetype/truetype
code.google.com/p/freetype-go/freetype

% ls
code.google.com foo           fooer

% ls ../pkg/darwin_amd64/
code.google.com foo.a

Moving Beyond Scripts

Every programming language has its own way of organizing code. Knowing where a language is expecting code is a must when moving beyond simple scripts.

About the Author

Biography

Previous
Acceptance Testing with Page Objects
Acceptance Testing with Page Objects

An acceptance test suite goes through stages of complexity. Our first acceptance tests started off using a ...

Next
A Wrap-up of LAUNCH Mobile and Wearables
A Wrap-up of LAUNCH Mobile and Wearables

When noted entrepreneur and VC Jason Calacanis asked us to sponsor LAUNCH Mobile, it was an opportunity we ...