CHAPTER 33 · QUALITY & SHIPPING

Documentation & the Go Toolchain

Two loosely-related topics packed into one chapter: how Go packages document themselves, and a rapid-fire tour of the rest of the go CLI you haven't met yet.

Learning objectives

  • Write idiomatic Go doc comments.
  • Use example functions as executable docs.
  • Read docs offline with go doc.
  • Recognize and use: go vet, go fmt, goimports, go work, go generate, go install.

Doc comments

Any comment immediately preceding a top-level declaration (no blank line between) becomes its documentation:

// Package mymath provides small utilities for integer arithmetic.
//
// The package is meant as a tiny example and is intentionally minimal.
package mymath

// Add returns a + b. It panics on overflow.
func Add(a, b int) int { return a + b }

Conventions:

  • Package comment on the package line in one file (often doc.go).
  • Doc comments start with the identifier name: "Add does ...", "ErrNotFound is ...".
  • Plain sentences, no Javadoc-style tags like @param.
  • Indent code blocks with a tab; they render as code.

Example functions as docs

func ExampleAdd() {
    fmt.Println(mymath.Add(2, 3))
    // Output: 5
}

Already seen in Chapter 31. Two benefits: example runs as a test (catches doc rot), and it appears formatted in the generated documentation on pkg.go.dev, copy-pasteable for readers.

go doc: offline package docs

go doc fmt                       # package overview
go doc fmt.Println               # specific function
go doc -all net/http             # everything in a package
go doc -src fmt.Println          # include source

Handy when you're on a plane or just want the terminal to give you the answer without opening a browser.

pkg.go.dev

The hosted version. Every public Go module auto-publishes here, with rendered docs, examples, versions, cross-references, and a module proxy cache. When someone else's library is good, it's because they wrote good doc comments and their pkg.go.dev page is lovely to browse.

The go toolchain, rapid tour

You've already used these throughout the course. Here's the bird's eye view of what's left.

go vet

A static analyzer built into the toolchain. Catches:

  • Bad Printf format strings (%d with a string).
  • Unreachable code.
  • Copying of sync.Mutex.
  • Shadowed errors (with extra flags).
  • Many more.
go vet ./...

Runs automatically as part of go test. You should run it explicitly in CI.

go fmt & goimports

Go's one-true formatter. Your editor (Chapter 3) runs it on save. From the CLI:

go fmt ./...
goimports -w .                   # also manages the import block

go work: workspaces

Already mentioned in Chapter 18. Briefly: when you're developing two modules simultaneously, create a workspace file so Go uses your local copies:

go work init ./myapp ./mylib
go work use ./anothermod

go.work isn't committed, your workspace is local.

go generate

A convention for running code generators. Put a magic comment in a Go file:

//go:generate stringer -type=Weekday

Then go generate ./... runs every such command. Common generators: stringer (produces String() string for enums), mockgen (interface mocks), protoc (Protocol Buffers).

go install path@version

Install a CLI tool globally:

go install golang.org/x/tools/cmd/goimports@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
go install github.com/cyrus2281/learn-go@latest       # your own tool

Binary lands in $GOPATH/bin (usually ~/go/bin), which should be on your $PATH.

Check your understanding

Practice exercises

EXERCISE 1

Document your mymath package

Take a Go package you've written in earlier chapters. Add a package-level doc comment (in a doc.go file), doc comments on each exported identifier, and at least one ExampleXxx. Then run go doc -all . to see the generated docs.

Show sketch
// Package mymath provides small utilities for integer math.
//
// This package is a toy and is intentionally minimal.
package mymath

// Add returns the sum of a and b.
func Add(a, b int) int { return a + b }

// Sub returns a - b.
func Sub(a, b int) int { return a - b }

In a separate example_test.go (same package):

func ExampleAdd() {
    fmt.Println(mymath.Add(2, 3))
    // Output: 5
}

Further reading

Professional-grade Go, shipping ready.