Organizing Go code David Crawshaw

Packages 2

Go programs are made up of packages All Go source is part of a package.

Every file begins with a package statement.

Programs start in package main. package main import "fmt" func main() { fmt.Println("Hello, world!") } For very small programs, main is the only package you need to write. The hello world program imports package fmt . The function Println is defined in the fmt package. 3

An example package: fmt // Package fmt implements formatted I/O. package fmt // Println formats using the default formats for its // operands and writes to standard output. func Println(a ...interface{}) (n int, err error) { ... } func newPrinter() *pp { ... } The Println function is exported. It starts with an upper case

letter, which means other packages are allowed to call it. The newPrinter function is unexported. It starts with a lower

case letter, so it can only be used inside the fmt package. 4

The shape of a package Packages collect related code. They can be big or small,

and may be spread across multiple files. All the files in a package live in a single directory. The net/http package exports more than 100 names. (18 files)

The errors package exports just one. (1 file) 5

The name of a package Keep package names short and meaningful.

Don't use underscores, they make package names long. io/ioutil not io/util

not suffixarray not suffix_array Don't overgeneralize. A util package could be anything. The name of a package is part of its type and function names.

On its own, type Buffer is ambiguous. But users see: buf := new(bytes.Buffer) Choose package names carefully. Choose good names for users. 6

The testing of a package Tests are distinguished by file name. Test files end in _test.go . package fmt import "testing" var fmtTests = []fmtTest{ {"%d", 12345, "12345"}, {"%v", 12345, "12345"}, {"%t", true, "true"}, } func TestSprintf(t *testing.T) { for _, tt := range fmtTests { if s := Sprintf(tt.fmt, tt.val); s != tt.out { t.Errorf("...") } } } Test well. 7

Code organization 8

Introducing workspaces Your Go code is kept in a workspace. A workspace contains many source repositories (git, hg). The Go tool understands the layout of a workspace.

You don't need a Makefile . The file layout is everything. Change the file layout, change the build. $GOPATH/ src/ github.com/user/repo/ mypkg/ mysrc1.go mysrc2.go cmd/mycmd/ main.go bin/ mycmd 9

Let's make a workspace mkdir /tmp/gows GOPATH=/tmp/gows The GOPATH environment variable tells the Go tool where your workspace is located. go get github.com/dsymonds/fixhub/cmd/fixhub The go get command fetches source repositories from the internet and places them in your workspace. Package paths matter to the Go tool. Using "github.com/..."

means the tool knows how to fetch your repository. go install github.com/dsymonds/fixhub/cmd/fixhub The go install command builds a binary and places it in $GOPATH/bin/fixhub . 10

Our workspace $GOPATH/ bin/fixhub # installed binary pkg/darwin_amd64/ # compiled archives code.google.com/p/goauth2/oauth.a github.com/... src/ # source repositories code.google.com/p/goauth2/ .hg oauth # used by package go-github ... github.com/ golang/lint/... # used by package fixhub .git google/go-github/... # used by package fixhub .git dsymonds/fixhub/ .git client.go cmd/fixhub/fixhub.go # package main go get fetched many repositories.

go install built a binary out of them. 11

Why prescribe file layout? Using file layout for builds means less configuration.

In fact, it means no configuration.

No Makefile , no build.xml . Less time configuring means more time programming. Everyone in the community uses the same layout.

This makes it easier to share code. The Go tool helps build the Go community. 12

Where's your workspace? It is possible to have multiple workspaces, but most people just use one. So where do you point your GOPATH ? A common preference: This puts src , bin , and pkg directories in your home directory. (Convenient, because $HOME/bin is probably already in your PATH .) 13

Working with workspaces Unix eschews typing: CDPATH=$GOPATH/src/github.com:$GOPATH/src/code.google.com/p $ cd dsymonds/fixhub /tmp/gows/src/github.com/dsymonds/fixhub $ cd goauth2 /tmp/gows/src/code.google.com/p/goauth2 $ A shell function for your ~/.profile : gocd () { cd `go list -f '{{.Dir}}' $1` } This lets you move around using the Go tool's path names: $ gocd .../lint /tmp/gows/src/github.com/golang/lint $ 14

The Go tool's many talents $ go help Go is a tool for managing Go source code. Usage: go command [arguments] The commands are: Worth exploring! Some highlights: build compile packages and dependencies get download and install packages and dependencies install compile and install packages and dependencies test test packages There are more useful subcommands. Check out vet and fmt . 15

Dependency management 16

In production, versions matter. go get always fetches the latest code, even if your build breaks. That's fine when developing. It's not fine when releasing.

We need other tools. 17

Versioning My favorite technique: vendoring. For building binaries, import the packages you care about

into a _vendor workspace. GOPATH=/tmp/gows/_vendor:/tmp/gows For building libraries, import the packages you care about

into your repository. Rename the imports to: import "github.com/you/proj/vendor/github.com/them/lib" Long paths, but trivial to automate. Write a Go program! Another technique: gopkg.in, provides versioned package paths: gopkg.in/user/pkg.v3 -> github.com/user/pkg (branch/tag v3, v3.N, or v.3.N.M) 18

Naming 19

Names matter Programs are full of names. Names have costs and benefits. Costs: space and time

Names need to be in short term memory when reading code.

You can only fit so many. Longer names take up more space. Benefits: information

A good name is not only a referent, it conveys information. Use the shortest name that carries the right amount of information in its context. Devote time to naming. 20

Name style Use camelCase , not_underscores .

Local variable names should be short, typically one or two characters. Package names are usually one lowercase word. Global variables should have longer names. Don't stutter. bytes.Buffer not bytes.ByteBuffer

not zip.Reader not zip.ZipReader

not errors.New not errors.NewError

not r not bytesReader

not i not loopIterator 21

Doc comments Doc comments precede the declaration of an exported identifier: // Join concatenates the elements of elem to create a single string. // The separator string sep is placed between elements in the resulting string. func Join(elem []string, sep string) string { The godoc tool extracts such comments and presents them on the web: 22

Writing doc comments Doc comments should be English sentences and paragraphs.

They use no special formatting beyond indentation for preformatted text. Doc comments should begin with the noun they describe. // Join concatenates… good // This function… bad Package docs go above the package declaration: // Package fmt… package fmt Read the world's Go docs on godoc.org. E.g. godoc.org/code.google.com/p/go.tools/cmd/vet 23

Questions? 24