Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Next Steps in Go: Code Organization

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.

Comments
  1. Ross says:

    Great post Jared, I’ve really been enjoying your series on Go! Quick question on code organization of multiple projects on the same machine:

    Do you create multiple workspaces (ie, one per project) -OR- a single workspace with a single src, pkg, bin directory tree for all projects?

    To put it another way, should my src directories look like this:

    ~/Projects/project_1/src
    ~/Projects/project_2/src

    – OR –

    ~/Projects/go/src/project_1
    ~/Projects/go/src/project_2

    The IntelliJ IDEA plugin seems to expect the former whereas golang.org seems to expect the latter.

    And, imho, the former seems a much nicer way to keep things organized.

  2. Jared Carroll says:

    @Ross,

    There doesn’t seem to be a consensus in the Go community on single vs. multiple workspaces. The IntelliJ Go plugin creates a separate directory for each project; so it must append each directory to the GOPATH. The Go docs (http://golang.org/doc/code.html) mention multiple workspaces, but then
    provide an example using multiple libraries, each organized in their own Git repository, in a single workspace.

    The single workspace feels like how Unix stores binaries in a few places /bin or /usr/bin for example. The multiple workspace equivalent would require adding more and more custom ‘bin’ directories to your PATH; which feels a little less elegant.

    I guess it comes down to personal/team preference. For a language that eliminated code formatting bikeshedding via `gofmt`, it’s disappointing there’s not a definite advantage to either way.

  3. Ross Hale says:

    Sounds like I’ll be sticking with multiple workspaces for now — despite the pain of GOPATH and package management. Thanks!

  4. Jeff Hui says:

    The preferred way (according to Andrew Gerrand) seems to be using one GOPATH with all the projects in the same workspace.

    https://groups.google.com/forum/#!topic/golang-nuts/dxOFYPpJEXo

    Although, I prefer separate workspaces :(

  5. Gerard says:

    Thanks for this! It really demostrated Golang’s custom package build process in a consise and simple example.

  6. Dagen Brock says:

    I’ve been putting all my GOPATH stuff in a “gorc” file. When I work on a project, I just run its gorc file. I suppose it might be a bit wonky, but I typically do all of my build/run commands from one small terminal in the corner, so I only have to run that once per project/session. I open other terminals to do all of my editing in vi.

    Thanks for the article. I do wish you touched a bit on what level of related functionality *should* go in one package, but I suppose that’s a matter of taste and style, and probably leads to religious arguments. ;)

  7. Tony says:

    Thank you writing this Jared. It worked perfectly!

  8. Yogesh says:

    I have Go project with multiple packages(containing one or more source files) into it.I am using IntelliJ IDEA and able to build the project and run it.

    However, I want to run multiple instances of the resulting binary in a distributed environment. So need a binary executable for the same. How can I generate single binary executable for the entire project?

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *