Open-Source Wikis

/

Go

/

How to contribute

/

Patterns and conventions

golang/go

Patterns and conventions

Go's house style is famously prescriptive. This page captures the conventions that this repository follows and that reviewers will enforce on CLs. They go beyond the public "Effective Go" guide.

Formatting

  • gofmt is non-negotiable. Every .go file is formatted with gofmt. The pre-commit hook installed by git codereview hooks runs it; CLs that aren't gofmt-clean are rejected.
  • Tabs for indentation, spaces for alignment. This is what gofmt produces.
  • Line length is unlimited in source. Wrap long argument lists naturally; do not break a line just because it crosses 80 columns.
  • Comment lines wrap at ~76 columns so godoc and reviewers can read them comfortably.

Naming

  • MixedCaps, never snake_case or SCREAMING_CAPS. Even constants.
  • Exported names start with an uppercase letter. Unexported start lowercase. There are no other visibility levels.
  • Package names are short, lowercase, single words. Avoid util, common, or helpers. The package's name is the import path leaf.
  • Receiver names are short. One or two letters keyed off the type name. The same receiver name across all methods of a type. Don't use self, this, or me.
  • Errors: values named err; variables named errFoo for sentinels (io.EOF is the famous exception); types named FooError.
  • Tests: TestFoo, BenchmarkFoo, ExampleFoo, FuzzFoo. The harness is built in src/testing/.
  • Generated code: files containing // Code generated by ... DO NOT EDIT. are exempt from formatting/style review and lint.

Documentation comments

  • Every exported declaration has a doc comment. The first sentence starts with the name being documented:
    // Read reads up to len(p) bytes into p. It returns ...
    func (f *File) Read(p []byte) (n int, err error) { ... }
  • Package comments live in a single file (often doc.go) and start with // Package foo provides ....
  • Use plain prose, not "see [link]" — godoc cross-links automatically by name.
  • Doc comments may use simple Markdown-like syntax in modern Go (headings, lists, links) — see the go/doc/comment package.

Error handling

  • No exceptions. Errors are values. Functions that can fail return (T, error).
  • Error checks come first:
    x, err := foo()
    if err != nil {
        return err
    }
    use(x)
  • Wrap with context using fmt.Errorf("...: %w", err). Use errors.Is and errors.As to inspect.
  • Sentinel errors are exported variables (io.EOF, os.ErrNotExist). Compare with errors.Is(err, io.EOF).
  • Don't add useless context. fmt.Errorf("error reading file: %w", err) is redundant when err already says "open foo.txt: no such file." Add information the caller doesn't have.
  • Don't log and return. Log or return, not both — the caller will log.

Inside the runtime, errors are different: most paths use panic for fatal conditions and direct status codes for expected ones. See src/runtime/error.go.

Internal packages

internal/ is enforced by the build system: only the parent package and its descendants can import a package under .../internal/.... The standard library uses src/internal/ heavily for shared helpers (e.g., internal/abi, internal/byteorder, internal/race, internal/sync, internal/poll).

Use internal/ whenever code is needed in multiple packages but should not be exposed to users.

//go: directives

Go's compiler honors a number of pragma-like comments. The most common in this repo:

Directive Meaning
//go:nosplit No stack-grow prologue (low-level runtime only)
//go:noinline Don't inline this function
//go:linkname local remote Bind unexported symbol from another package (mostly runtime ↔ stdlib)
//go:noescape Tell compiler this assembly function does not escape its arguments
//go:nowritebarrier / //go:nowritebarrierrec Forbid write barriers (runtime / GC code)
//go:build linux && amd64 Build constraint
//go:embed file.txt Embed file contents into a string or []byte
//go:generate go run gen.go Run a generator on go generate
//go:fix inline (and others) New //go:fix directives drive the go fix workflow

//go:linkname is the runtime's escape valve. Use it sparingly and only when there is no public API alternative.

Build constraints

The new form is //go:build expr. The old form // +build is mirrored on the same file but is being phased out. gofmt keeps them in sync.

Common patterns:

  • //go:build !windows
  • //go:build amd64 || arm64
  • //go:build go1.21
  • //go:build cgo

File-name suffixes (_linux.go, _amd64.go, _test.go) are also build constraints, applied automatically.

Concurrency idioms

  • Don't communicate by sharing memory; share memory by communicating. Channels and sync primitives are both fine; pick the simpler one.
  • sync.RWMutex is rarely worth the overhead. Plain sync.Mutex is faster for short critical sections.
  • select { default: } for non-blocking channel ops.
  • context.Context is the first parameter of every blocking or long-running call. Never store a context.Context in a struct.
  • go func() requires an exit story. A goroutine that never returns is a leak.
  • Don't use time.Sleep for synchronization. Use channels, sync.Cond, or sync.WaitGroup.

Testing idioms

  • Subtests with t.Run for table-driven tests.
  • t.Cleanup(fn) for setup/teardown instead of defer.
  • t.Helper() in helper functions so failures point at the call site.
  • Golden files in testdata/. A -update flag is conventional for regenerating them.
  • internal/testenv has MustHaveExternalNetwork, MustHaveCgo, MustHaveExec, etc. Use them so tests skip cleanly on restricted builders.
  • Avoid hard-coded ports. Use net.Listen("tcp", "localhost:0") to get an OS-assigned port.

Imports

Imports are formatted by goimports (a superset of gofmt). The standard convention is three groups separated by blank lines:

import (
    "fmt"
    "os"

    "golang.org/x/sys/unix"

    "github.com/example/foo"
)

In this repo, only the first two groups exist (no third-party imports allowed in the standard library; golang.org/x/... is vendored under src/vendor/).

Cross-references

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Go wiki | Factory