Files
2026-09-16 10:27:58 -03:00

3.0 KiB

Code Style

  • Follow standard Go conventions: gofmt, goimports, and golangci-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.As for matching, not string comparison.
  • Reserve panic for unrecoverable programmer mistakes, not runtime errors.

Concurrency

  • Pass context.Context as the first argument to any blocking or I/O function.
  • Never store a Context in a struct. Never use context.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.Run for clarity and coverage.
  • Use the standard testing package. Reach for testify only 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 _test packages for black-box testing.
  • Benchmark with testing.B before optimizing anything.

Dependencies & Modules

  • Keep go.mod tidy — run go mod tidy before committing.
  • Minimize external dependencies; prefer the standard library.
  • Pin versions explicitly and review dependency updates carefully.

General

  • Measure before optimizing. Use pprof for 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/rand for all randomness that touches security; never math/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.