3.0 KiB
3.0 KiB
Code Style
- Follow standard Go conventions:
gofmt,goimports, andgolangci-lint. - Keep packages small and focused. Name them short, lowercase, no underscores.
- Avoid unnecessary abstractions — prefer simple, readable code over clever code.
- Define interfaces at the point of use, not the point of implementation. Keep them small.
Error Handling
- Always handle errors explicitly — never ignore them with
_. - Wrap errors with context:
fmt.Errorf("doing X: %w", err). - Use
errors.Is/errors.Asfor matching, not string comparison. - Reserve
panicfor unrecoverable programmer mistakes, not runtime errors.
Concurrency
- Pass
context.Contextas the first argument to any blocking or I/O function. - Never store a
Contextin a struct. Never usecontext.Background()deep in business logic. - Always manage goroutine lifecycles — use
errgroup,sync.WaitGroup, or channels. - Protect shared state with mutexes or by confining it to a single goroutine.
Testing
- Write table-driven tests using
t.Runfor clarity and coverage. - Use the standard
testingpackage. Reach fortestifyonly when it genuinely reduces noise. - Prefer real implementations over mocks where feasible (e.g.,
httptest, in-memory stores). - Keep tests close to the code they test; use
_testpackages for black-box testing. - Benchmark with
testing.Bbefore optimizing anything.
Dependencies & Modules
- Keep
go.modtidy — rungo mod tidybefore committing. - Minimize external dependencies; prefer the standard library.
- Pin versions explicitly and review dependency updates carefully.
General
- Measure before optimizing. Use
pproffor profiling. - Log at boundaries (entry/exit of services), not inside every function.
- Prefer explicit over implicit — avoid
init()and global state.
Documentation
- Document every exported type, function, method, and constant — no exceptions.
- Follow Go doc conventions: start the comment with the name of the thing being documented.
- Package-level comments should explain purpose and usage, not implementation details.
Testing (expanded)
- Write tests as you write code — not after, not when asked. Tests are not optional.
- Every exported function and critical internal path must have at least one test.
- Cover edge cases, error paths, and boundary conditions — not just the happy path.
- Use
t.Helper()in shared test utilities to keep failure output pointing at the call site. - Integration tests live in
test/or behind a build tag (e.g.,//go:build integration).
Security
- Never log secrets, tokens, passwords, or PII — scrub them before logging.
- Validate and sanitize all external input; never trust data from outside the process boundary.
- Use
crypto/randfor all randomness that touches security; nevermath/rand. - Scan dependencies for known CVEs regularly (e.g.,
govulncheck). - Set strict timeouts on all outbound HTTP clients — never use the default zero-timeout client.