git:20260510.fe97ca3 to git:20260905.88628fb

58 added, 44 removed. Audit A to A.

---
name: programming-go
title: "Go Development"
description: "Idiomatic Go architecture, concurrency design, and standard-library-first patterns. Auto-activates in Go projects."
license: Apache-2.0
- compatibility: "Requires Go toolchain (go 1.21+)."
+ compatibility: "Requires the Go toolchain selected by the project."
domains: developer
rules:
- file(go.mod)
- content(golang)
---
+ ## Overview
+
+ Write explicit Go with small packages, inspectable errors, and bounded concurrency. Research baseline: stable Go 1.27, checked 2026-09-05. Read `go.mod`, `go.work`, toolchain directives, build tags, and CI before introducing newer APIs. Use a supported toolchain, but preserve the module's language compatibility unless an upgrade is requested. Recheck official releases when updating this guidance.
+
## Mental model
- Go optimizes for code that ten people can maintain for ten years. Simplicity, explicitness, and a small standard vocabulary matter more than cleverness. Resist the urge to import patterns from Java, Ruby, or TypeScript — interfaces, generics, and inheritance hierarchies that feel natural elsewhere produce unidiomatic Go.
+ Keep control flow and ownership visible. Ordinary functions, structs, and explicit dependency wiring solve most problems. Add an interface, generic abstraction, goroutine, or dependency when it removes a concrete coupling or limitation; don't create infrastructure for hypothetical reuse.
- ## Architecture
+ ## Recent features and compatibility
- - Package boundaries reflect capabilities, not layers — `auth`, `billing`, `inventory`, not `controllers`/`services`/`repositories`
- - Define interfaces in the consuming package, not where the type that implements them lives — keeps producers free of test-driven interface noise
- - Accept interfaces, return concrete types — callers get flexibility, you keep options open
- - An interface with one implementation is usually premature; wait for the second before extracting
- - Avoid framework-style "container" packages — a `main` that wires dependencies explicitly beats hidden service locators
+ | Version | Useful change and boundary |
+ |---------|----------------------------|
+ | 1.22 | Loop variables declared by the loop have per-iteration semantics; preexisting variables assigned by the loop still share storage. `ServeMux` supports method and wildcard patterns. |
+ | 1.23 | Range-over-function iterators and `iter`, `slices`, and `maps` helpers can replace custom collection plumbing. |
+ | 1.25 | `sync.WaitGroup.Go` couples task startup with completion accounting; the function must not panic. `testing/synctest` supports deterministic concurrent tests. |
+ | 1.27 | Methods may declare type parameters. Interface methods still cannot, and generic methods cannot implement interface methods. `encoding/json/v2` and `encoding/json/jsontext` are available without the former experiment requirement. |
- ## Errors are values
+ Go 1.27 JSON v2 rejects duplicate object names and invalid UTF-8 by default. Migration changes wire behavior; inspect the documented differences and test existing payloads. The original `encoding/json` API remains supported. SIMD packages are still experimental; do not treat them as ordinary stable APIs.
- - Errors are returned, not thrown — every error path is visible in the signature
- - Wrap with `%w` to preserve the chain: `fmt.Errorf("loading %s: %w", path, err)`
- - Sentinel errors (`var ErrNotFound = errors.New(...)`) for predictable conditions; check with `errors.Is`
- - Typed errors with fields when callers need to inspect details; check with `errors.As(&target)`
- - Don't wrap when adding no information; don't ignore — handle, log with context, or return
+ ## Packages, types, and interfaces
- ## Concurrency design
+ - Keep a package cohesive and its exported surface small. `internal/` limits imports to the subtree rooted at its parent directory; it does not mean strictly “same module.” Preserve the existing layout when it serves the task.
+ - Define a small interface at the consumer when substitution is needed; don't export an interface for every concrete implementation. Return concrete values unless hiding representation is part of the API.
+ - Use generics when the same algorithm works across types. `sync.Pool` is not `sync.Pool[T]`; verify signatures instead of inventing typed variants.
+ - Prefer useful zero values where possible; use constructors for required invariants. A typed nil pointer inside an interface is a non-nil interface: return an explicit `nil` on success for `error` results.
+ - Treat slices as views over possibly shared storage. Copy before retaining data that the caller may mutate or reuse. Do not copy mutexes, wait groups, or other synchronization values after use.
- - Don't reach for goroutines first — sequential code is easier to read and reason about
- - Every goroutine needs an exit story: a context, a closed channel, or a `WaitGroup` — leaks compound silently
- - `context.Context` is the first parameter of any function that does I/O, blocks, or starts goroutines; never stored in a struct
- - Channels coordinate ownership transfer; mutexes guard short critical sections — pick the simpler one for the job
- - `errgroup.Group` for "do N things in parallel, fail if any fails"; `sync.WaitGroup` for fire-and-collect
- - Close channels from the sender side only; receivers detect closure via the two-value receive
- - Shared mutable state crosses fewer goroutines than you think — copy values, send messages, or use immutable snapshots
+ ## Errors and boundaries
- ## Standard library first
+ - Return errors with operation context; use `%w` when callers should inspect the cause. Check with `errors.Is` or `errors.As`, not error-string matching.
+ - Choose exported sentinel or typed errors only for recovery decisions callers need. Wrapping exposes a cause as part of your API; don't expose implementation errors accidentally.
+ - Handle or return failures. Log where the request/job is finally handled, avoiding duplicate logs at every layer. Don't turn invalid configuration, malformed input, or failed I/O into successful zero values.
+ - Close response bodies and files promptly; check write and close errors where they affect durability. Put per-item cleanup in a helper instead of accumulating loop-scoped `defer` calls until a long function exits.
+ - Set HTTP timeouts and body limits appropriate to the operation; pass request contexts through network and database calls. Reuse clients and transports.
- - HTTP: `net/http` with `http.ServeMux` (1.22+ supports path params) — frameworks are rarely necessary
- - JSON: `encoding/json` with struct tags; for performance-sensitive paths reach for `json.Decoder` streaming
- - Logging: `log/slog` for structured logs — replaces third-party loggers in new code
- - `io.Reader` / `io.Writer` are the universal data interfaces — write functions in terms of them, not `[]byte` or `string`
- - `context`, `errors`, `slices`, `maps`, `cmp` cover most utility needs
+ ## Concurrency and lifecycle
- ## Generics — sparingly
+ - Every goroutine needs an owner, completion/error handling, and a way to finish. A `WaitGroup` waits; it does not cancel work. Bound parallel work and queues.
+ - Pass `context.Context` explicitly as the first parameter for operations with cancellation/deadlines. Don't store request contexts in long-lived structs; call returned cancellation functions to release resources.
+ - Choose a mutex for simple shared state and channels for coordination or ownership transfer. The sending owner closes a channel after its final send; multiple producers need coordinated closure.
+ - Use `errgroup` when coordinated work needs error propagation and cancellation. Its context only helps if blocking operations observe cancellation.
- - Generics are for containers and algorithms (`slices.Sort`, `sync.Pool[T]`), not for "abstracting" business logic
- - A non-generic helper that takes `any` plus a type assertion is usually worse than two specific functions — but two specific functions are usually fine
- - Type parameters on methods are not allowed; design around it
+ ## Example
- ## Project layout
+ Preserve parse errors and reject values outside the domain:
- - `cmd/<name>/main.go` for each binary; one `main` package per binary
- - `internal/` for packages not importable outside the module — use it liberally to keep the public API small
- - `pkg/` only when publishing a reusable library; private services don't need it
- - Module path matches the repo's import path; one module per repo unless there's a strong reason otherwise
- - Flat over nested — deep package trees fight Go's import-by-name idiom
+ ```go
+ func parseWorkers(raw string) (int, error) {
+ n, err := strconv.Atoi(raw)
+ if err != nil {
+ return 0, fmt.Errorf("parse worker count: %w", err)
+ }
+ if n < 1 {
+ return 0, fmt.Errorf("worker count must be positive")
+ }
+ return n, nil
+ }
+ ```
- ## Testing
+ This function uses the standard `fmt` and `strconv` packages.
- - Table-driven tests with `t.Run(tc.name, ...)` — the canonical Go pattern
- - `t.Cleanup` over `defer` for fixtures; `t.TempDir`, `t.Setenv` auto-clean
- - Test the public API of a package; reach into internals only when an invariant can't be observed from outside
- - Hand-written fakes beat mock frameworks for clarity; `httptest.Server` for HTTP boundaries
- - Always run with `-race` in CI; data races are the most common Go bug
+ ## Checklist
+
+ - [ ] Language features and standard-library symbols match the module's declared version.
+ - [ ] Errors, nil interfaces, shared slices, cleanup, and cancellation preserve the contract.
+ - [ ] New concurrency has bounded work and a defined shutdown path.
+ - [ ] When authorized, use project formatting, vet, focused tests, and race tests on supported targets. Exercise invalid inputs and concurrent shutdown; report skipped checks.
+
+ ## References
+
+ - [Release history](https://go.dev/doc/devel/release), [Go 1.27](https://go.dev/doc/go1.27), and [Go 1.25](https://go.dev/doc/go1.25).
+ - [Language specification](https://go.dev/ref/spec) and [Go code review guidance](https://go.dev/wiki/CodeReviewComments).
+ - [Context lifecycle](https://pkg.go.dev/context), [synchronization contracts](https://pkg.go.dev/sync), and [JSON v2](https://pkg.go.dev/encoding/json/v2).