# Go Tooling — Derived Application > Applies Atelier's domain principles to Go tooling specifically. > Derives from `domains/` docs; introduces no new P-rules (D-063). > See `languages/go.md` for the language first-principles stub. ## go vet and golangci-lint (DevOps P2 Automation, C2 Clarity) - **`go vet` is the stdlib baseline:** it catches `printf` format mismatches, lock-copy-by-value, and unreachable code. Run on every build. - **`golangci-lint` aggregates vet + dozens of linters:** enable `errcheck` (no `_ = err`), `govet`, `staticcheck`, `ineffassign`, `unused`, `gofmt`, `goimports`. Each enabled linter has a one-line `# reason:` in `.golangci.yml`. - **`errcheck` enforces `errors/P2` (fail loudly):** a discarded error is a silent failure. `errcheck` fails the build on `_ = doX()`. - **`goimports` over `gofmt`:** `goimports` adds missing imports and removes unused ones, in addition to formatting. The format is not debated in review (Clarity C2). ```yaml # .golangci.yml linters: enable: - errcheck # reason: Errors P2 — no swallowed errors - govet - staticcheck - ineffassign - unused - gofmt - goimports linters-settings: errcheck: check-blank: true # fail on _ = fn() ``` ## go test -race (Concurrency P6 No Silent Races) - **`go test -race` in CI, always:** the race detector instruments memory accesses and fails on data races. It is the primary enforcement of `concurrency/P6` (no silent races). - **`-race` adds overhead; run it in a separate CI job:** the race build is ~2x slower; keep the fast unit-test job and add a race job. - **`-race` requires tests that actually exercise the concurrent path:** a test that calls `Get`/`Set` serially finds no race. Write tests that spawn goroutines hitting the same map. - **Applies `concurrency/P6`:** a race detected is a bug fixed; a race undetected is a heisenbug in production. The detector is the safety net. ```bash # CI race job go test -race -count=1 ./... ``` ## Module Discipline (DevOps P1 Reproducibility) - **`go mod tidy` on every change that touches imports:** removes unused deps and adds missing ones. A `go.mod` with stale entries breaks reproducibility. - **`go.sum` committed and verified:** `go mod verify` checks the checksums of the module cache against `go.sum`. A drifted `go.sum` is a supply-chain signal. - **Pinned major versions in `go.mod`:** `require github.com/x/y v1.2.3` pins the minor; a `v1.2.4` patch may auto-update. For applications, consider a `go.mod` proxy that pins to exact commits. - **`go mod vendor` for hermetic CI:** vendoring `vendor/` into the repo means CI builds without network. The trade-off is repo size; the win is reproducibility (DevOps P1). ```bash # CI build gate go mod tidy go mod verify go build ./... go test -race ./... ``` ## Reproducible Builds (DevOps P1 Reproducibility, C3 Simplicity) - **One Go toolchain version, pinned:** `goenv` or `asdf` pins the Go version per repo; a `.go-version` file declares it. A CI job that uses "latest" Go drifts. - **`CGO_ENABLED=0` for static binaries:** a static binary runs in a scratch container with no libc dependency. Set in CI for all release builds. - **`-trimpath` and `-ldflags='-s -w'` for reproducible output:** strips the build path from the binary and removes debug info. Two builds of the same commit produce byte-identical binaries. ```bash # Reproducible release build CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o app ./cmd/app ``` ## Documentation in the Pipeline (Documentation P1 Documentation is Code, DevOps P9 Documentation in the Pipeline) - **`go doc` from comments:** package comments and exported-symbol comments are the API docs; `go doc` and `pkg.go.dev` render them. Missing comments on exported symbols fail `revive`/`golint` (Documentation P1). - **`// Example` functions are run by `go test`:** an `ExampleUser` function with `// Output:` is a tested artifact; a stale output fails the build. - **`README.md` and `docs/` are built by `mkdocs` or similar:** the pipeline validates links and renders; a broken link fails CI (Documentation P1). ```go // GetUser fetches a user by id. // // Example: // // u, err := GetUser(id) // if err != nil { ... } func GetUser(id UserId) (*User, error) { /* ... */ } func ExampleGetUser() { u, err := GetUser("abc") fmt.Println(u, err) // Output: not found } ``` ## Cross-References - `domains/devops/ci-cd.md` — the pipeline gates that host vet/lint/test. - `domains/devops/first-principles.md` — DevOps P1 Reproducibility, P2 Automation. - `domains/concurrency/first-principles.md` — Concurrency P6 No Silent Races (`-race`). - `domains/documentation/first-principles.md` — Documentation P1 Documentation is Code. - `languages/go-types.md` — the type rules staticcheck enforces reference this doc. - `languages/go-testing.md` — the `go test` flags (`-race`, `-count`) detailed here.