Case Studies Best Practices
A condensed summary of the 25 most important habits for reading, applying, and authoring production Go case studies drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important habits for reading, applying, and authoring production Go case studies drawn from every page in this section.
State the operational contract first: List SLOs, deploy target, and dependencies before copying code from a reference build so patterns map to your constraints.
Trace vertical slices: Follow request, data, and deploy flows end to end instead of reading packages in alphabetical order.
Extract decisions, not folder trees: Record boundaries and observability contracts in ADRs; avoid cargo-culting module paths from another org.
Separate liveness and readiness: Health endpoints must differ so orchestrators drain traffic only when dependencies fail, not when the process is merely busy.
Keep cmd entrypoints thin: main should wire config, observability, and servers while business rules live in internal/service and internal/store.
Set explicit HTTP server timeouts: ReadHeaderTimeout, read/write timeouts, and idle timeouts prevent slowloris and hung clients from accumulating goroutines.
Tune database/sql pools: Set MaxOpenConns, MaxIdleConns, and ConnMaxLifetime from instance size and database limits before chasing encoder micro-optimizations.
Propagate context per query: Apply context.WithTimeout on each SQL call so one slow statement cannot inherit a vague global deadline only.
Correlate logs and traces: Inject request IDs and trace IDs into slog handlers so incidents join metrics, logs, and spans without manual grep gymnastics.
Enforce gRPC backpressure: Return ResourceExhausted or shed load when subscriber buffers fill instead of letting in-memory buses grow without bound.
Compile gRPC modules once: Reuse CompiledModule or equivalent server warm-up paths; avoid per-request recompilation on hot paths.
Bind pprof to admin interfaces: Never expose debug/pprof on public listeners; capture profiles during controlled load tests only.
Layer cobra and viper cleanly: Load config in PersistentPreRunE, pass cmd.Context() into IO, and keep command packages free of SQL or SMTP details.
Guard write-mode CLI commands: Require --yes or interactive confirmation for destructive subcommands when stdin is not a TTY.
Patch operator status only: Reconcilers update status subresources and conditions; avoid fighting users by mutating spec except via webhooks.
Set owner references on operands: Kubernetes child objects need controller references so deletes garbage-collect Deployments and related resources.
Run envtest before live clusters: Controller and webhook logic should pass fast envtest suites on every PR without minikube cost.
Cap WASM guest capabilities: WASI hosts should allow-list syscalls, bound memory, and enforce per-invocation deadlines for untrusted modules.
Version host-guest ABIs: Smoke tests must assert export names and ABI metadata so TinyGo upgrades do not silently break wazero hosts.
Characterize before refactor: Lock HTTP golden responses and critical service behavior tests before splitting a god package.
Split store before handlers when SQL is tangled: Moving queries behind interfaces first removes the worst coupling in large internal/app packages.
Count queries per request: N+1 patterns often hide as many fast child spans; fix SQL shape before swapping JSON libraries.
Benchmark with -benchmem: Track allocs/op on handler hot paths and fail CI on regressions, not only wall-clock ns/op.
Profile under realistic load: Capture CPU and alloc profiles during sustained RPS; idle profiles mislead optimization priorities.
Revisit stories after toolchain upgrades: Re-benchmark and re-read operator/webhook compatibility when Go minors, gRPC, or controller-runtime versions change.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 19, 2026