Golang Code Quality

A focused checklist to review Go code for readability, security and performance, helping you ship reliable and production-ready pull requests.

What We Cover in the Go Analysis​

Here’s what this checklist helps you review before approving a pull request.

ChatGPT said:

Code & Design Quality – idiomatic Go style, clear structure, and maintainable logic
Security & Performance – validated inputs, safe crypto/TLS, efficient concurrency and scalable execution
Reliability & Observability – robust error handling, structured logging, metrics and tracing for production readiness
Data & Integration – safe migrations and transactions, stable APIs, and clean configuration management

Golang Code Review Checklist

Export this Checklist as Markdown

Use these points as a starting guide to automate code reviews with your agent.

Names follow Go conventions (mixedCaps/PascalCase; no underscores; package = short, lower).

Files, packages, and directories are cohesive; no “kitchen-sink” packages.

One top concept per file; large files split logically.

Functions are small, single-purpose; parameters < ~5; return values are meaningful.

Avoid cleverness; prefer straightforward, readable code.

Comments explain why, not what; exported identifiers have complete doc comments.

Keep imports minimal and grouped; standard, third-party, local order; goimports clean.

Avoid long parameter lists and boolean flags; prefer options/config structs.

Consistent error message style (lowercase, no punctuation), actionable context included.

No dead code/ commented-out blocks/ TODOs without linked issues.

Prefer range loops; correct use of value vs pointer iteration (no address of loop variable bug).

Avoid interface{} when generics or concrete types suffice.

Prefer zero values over explicit initialization where idiomatic.

Use time.Duration for time, not naked ints; units correct.

Use defer for cleanup close to acquisition; mindful of defer cost in hot paths.

Avoid panic in library code; reserve panic for truly unrecoverable programmer errors.

Use context.Context as first param when operations are cancelable/timeout-bound.

Avoid embedding types when it leaks APIs unintentionally; prefer explicit forwarding when needed.

Understand copy vs reference semantics (slices, maps, channels, strings).

Use errors.Is/As for error matching; sentinel errors exported appropriately.

Choose pointer vs value receivers intentionally (mutability, size, nil-safety, interface satisfaction).

Generic functions/types used where they improve clarity/safety; constraints precise.

Interfaces are small and consumer-owned; avoid large “god” interfaces.

Do not export types or methods unnecessarily; keep API surface minimal.

Validate inputs at boundaries; invariants enforced internally.

Avoid nil maps/slices if appended/assigned into; ensure init paths are clear.

Return concrete types; accept interfaces for flexibility (DI via interface).

Use time.Time vs *time.Time consciously; zero-time semantics documented.

Goroutine lifecycles are bounded; no leaks on cancel/error/return.

All goroutines respect context cancellation; pass context down call chain.

Channel usage clear: directions (chan<-, <-chan) and buffering justified.

No send/receive on closed channels; close occurs on producer side only.

select used to avoid blocking; default cases avoided unless truly needed.

Shared data guarded (mutex, RWMutex) or confined to a goroutine; no data races.

Avoid using WaitGroup incorrectly (no copying, Add before goroutine start).

Avoid busy loops; backoff/timers/tickers are cleaned up; time.Ticker.Stop() called.

Avoid unbounded concurrency; use worker pools/semaphores where needed.

No context.TODO in production paths; use context.Background() only at roots.

Appropriate data structures (map vs slice vs set/bitmap) for access patterns.

Minimize allocations in hot paths; reuse buffers (bytes.Buffer, sync.Pool) when justified.

Avoid copying large structs; pass pointers where appropriate.

Pre-allocate slices with correct capacity; avoid repeated reallocation.

Avoid reflect/interface{} on critical paths; avoid fmt in tight loops.

String/[]byte conversions minimized (use strings.Builder, bytes).

Profiling guides optimizations; no premature micro-optimizations.

Streaming I/O preferred over loading whole files/blobs into memory.

Consider time.AfterFunc vs creating many timers; reuse time.Timer where needed.

Errors handled explicitly; no silent ignores (_ = x without reason).

Wrap errors with context (fmt.Errorf("doing X: %w", err)); avoid losing stack/context.

Distinguish expected vs exceptional errors; no log-spam or double-logging.

Logging is structured; keys consistent; no PII/secrets in logs.

Metrics cover key paths (latency, throughput, errors, saturation).

Tracing spans propagate context; attributes/events capture useful detail.

Health/readiness endpoints reflect actual dependencies; include dependency checks.

Backoff with jitter for retries; retry only idempotent operations.

Circuit breakers/timeouts used for remote calls; deadlines respected.

Input validation and canonicalization performed; reject by default.

Use parameterized queries; no string-built SQL; migrations reviewed.

Secrets never hardcoded; loaded from secure store; redacted in logs.

Crypto uses crypto/* primitives correctly; no home-rolled crypto.

TLS verified (server name, roots); certificate pinning/rotation considered.

HTTP handlers defend against common vulns (CSRF where stateful, XSS, SSRF).

http.Server timeouts set (ReadHeaderTimeout, ReadTimeout, WriteTimeout, IdleTimeout).

Validation on JSON/YAML/proto decoding; DisallowUnknownFields where helpful.

File operations sandboxed; path traversal prevented; safe temp files (os.CreateTemp).

Authorization checks centralized and enforced; least privilege for OS/network/DB.

Use golang.org/x/* security updates; dependencies scanned and pinned.

Idempotency keys for retried external operations.

Sagas/outbox or other patterns used for cross-service consistency.

Time handling is UTC internally; time zones only at the edges.

Resource cleanup on shutdown (listeners, tickers, goroutines) via context.

Disk and network failures simulated/considered; exponential backoff with jitter.

At-least/at-most/exactly-once semantics documented and enforced where relevant.

Patterns reduce complexity/duplication, not add ceremony.

Factories/Builders for complex object creation; no telescoping constructors.

Strategy/Policy to replace if/else pyramids; Mediator for decoupled request handling (with care).

CQRS only where read/write models diverge meaningfully; events have clear ownership and delivery guarantees.

Anti-patterns avoided: service locator, anemic domain (unless choosing transactional script explicitly), God objects.

Pyramid balanced: fast unit tests, focused integration tests, a few E2E.

Tests deterministic; no sleeps except with require.Eventually-style helpers.

Table-driven tests with subtests; edge cases and error paths covered.

Fakes over mocks when possible; interfaces small and testable.

Concurrency tests include race detector (-race) in CI.

Golden files stable and human-reviewable; regeneration process documented.

Benchmarks for hotspots; regression tests for perf bugs.

Property-based tests (where valuable) validate invariants.

Coverage thresholds meaningful; critical packages near 80–90% where feasible.

go vet, golangci-lint (curated linters) clean; false positives suppressed locally with comments.

gofmt/goimports enforced; ineffassign, misspell, errcheck addressed.

Security linters (gosec, vulncheck) run; findings triaged.

-race run in CI for tests and selected integration paths.

Build tags documented and covered in CI matrix.

Generated code checked in only when appropriate; // Code generated … DO NOT EDIT. present.

HTTP clients reuse http.Client with tuned timeouts; no per-request client creation.

Servers set sane limits (body size, headers, concurrency); gzip/deflate handled safely.

JSON encoding uses omitempty wisely; numbers decoded safely (no precision loss).

gRPC: context deadlines, interceptors for logging/metrics, message size limits.

Versioning strategy defined (semver for APIs); backwards compatibility policy enforced.

OpenAPI/Protobuf specs source-of-truth; handlers adhere to contracts; validation enforced.

Idempotent methods use correct HTTP verbs; GET is safe; proper status codes returned.

Pagination, filtering, sorting implemented consistently and safely.

Transactions used correctly; isolation levels chosen and documented.

Migrations reversible and tested; DB schema in version control.

Indexes align with query patterns; query plans reviewed for hotspots.

Scan/encode errors handled; sql.Null*/custom nullable types used correctly.

For ORMs, N+1 avoided; eager vs lazy loading explicit; batch operations considered.

Serialization formats stable; forward/backward compatibility verified.

Data retention/TTL policies applied; PII lifecycle respected.

Clear boundaries between packages (domain, transport, persistence, app).

Dependency direction points inward; no cycles; internal packages used properly.

Public APIs minimal; internal details hidden; adapters thin.

Configuration isolated; no global mutable state; DI via constructors.

Feature modules cohesive; avoid cross-package reach-through.

Docs/README per package explain purpose and constraints.

Prefer composition over inheritance; small structs with embedded behavior where appropriate.

Functional options for constructors to avoid long parameter lists.

Adapter/Facade to isolate external deps; repository pattern when it simplifies testing.

Worker pool / pipeline patterns for concurrency; channels used judiciously.

Strategy/state patterns via interfaces or function types when it improves clarity.

Avoid over-engineering; patterns earn their keep.

Module name stable; go.mod tidy; go.sum committed.

Minimal dependencies; avoid heavy frameworks; choose well-maintained libs.

Replace directives used only for dev; not left in production.

Versions pinned (no v0.0.0-… unless necessary); updates tracked.

Internal forks documented; license compliance verified.

Reproducible builds; -trimpath/-buildvcs considered; version/commit injected via -ldflags.

Multi-arch builds if needed; CGO usage explicit; static linking when appropriate.

Makefile/Taskfile with common targets (test, lint, build, bench, docker).

CI matrix covers OS/arch/tags; caches used appropriately.

Artifacts signed/checksummed; SBOM generated if required.

Startup and shutdown hooks implemented; graceful termination tested.

Single source for config; precedence defined (env > file > defaults).

Validation on load; fail fast on invalid config.

Secrets via environment/secret store; never in repo.

Feature flags typed, centralized, and evaluated efficiently; defaults safe.

Config/watchers shut down cleanly; dynamic reload documented if supported.

Health/readiness/startup probes correct; dependencies gated behind readiness.

Structured logs suitable for aggregation; correlation IDs propagated.

Resource usage predictable; memory/CPU limits respected under load.

Graceful shutdown within Kubernetes terminationGracePeriodSeconds.

Containers run as non-root; least privileges; fs read-only when possible.

Config via env/Downward API; no baked secrets; 12-factor friendly.

Clear commands, flags, and help; sensible defaults; examples provided.

Errors actionable and concise; exit codes meaningful.

Do not prompt in non-interactive contexts; --yes/--force patterns consistent.

Output formats support (text/json); stable for scripting.

Shell completion/man pages generated when applicable.

unsafe, reflect, or atomic used only with strong justification and benchmarks.

Memory alignment and lifetime rules respected; no pointer aliasing violations.

CGO boundaries minimized; error handling and resource ownership clear.

Sync/atomic operations paired correctly; no torn reads/writes.

Build tags for experimental code isolated and documented.

Turn this checklist into automated reviews

Let Kody automatically check quality, security and performance in every pull request—cloud or self-hosted, in under 2 minutes.