Case Studies Basics
11 examples to get you started with Case Studies - 8 basic and 3 intermediate.
Prerequisites
- Install Go 1.26.x or later from go.dev/dl.
- Clone or browse this site's
site/go/case-studies/pages alongside your own module. - Optional:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestfor comparing lint posture to reference builds. - Skim Learning from Production Go Systems for how case studies differ from tutorials.
Basic Examples
1. Identify the Operational Contract
Before reading code, list SLOs, deploy target, and external dependencies for the story.
# REST reference build contract (example)
- Target: Kubernetes Deployment behind Ingress
- SLO: p99 < 100ms for read endpoints at 500 RPS
- Dependencies: Postgres, OTel collector, Prometheus scrape- Every reference build assumes a contract. Find it in the intro and Summary sections.
- Map the contract to packages you expect:
cmd/,internal/, migrations, Helm or manifest snippets. - If the contract is unstated, write your own before copying patterns.
Related: Learning from Production Go Systems - Why case studies matter
2. Trace Request Flow on Paper
Draw inbound protocol to outbound dependencies before opening implementation files.
Client -> Ingress -> chi middleware -> handler -> service -> store -> Postgres
|-> slog + trace span
|-> /healthz /readyz- Reference builds are vertical slices. Flow diagrams expose missing timeouts or probes early.
- Note where context propagates and where errors convert to HTTP or gRPC status codes.
- Compare your service's diagram to the case study's Related links for gap analysis.
Related: Reference Build: Cloud-Native REST Microservice - Full HTTP slice
3. Map Package Boundaries
List which packages may import which others in the reference layout.
// Allowed direction in typical reference builds:
// cmd/api -> internal/http -> internal/service -> internal/store
// internal/service must not import cmd/apiinternal/means "not a public module API." Reference builds keep integration at the edges.- Look for interfaces at store and client seams for test doubles.
- God-package before states violate this graph; after states restore acyclic imports.
Related: Before/After: Refactoring a God Package - Boundary repair story
4. Extract Observability Checklist
Copy signal requirements, not dashboard JSON.
// Minimal RED-style metric names to hunt for in a reference build
var (
httpRequests = prometheus.NewCounterVec(/* ... */)
httpDuration = prometheus.NewHistogramVec(/* ... */)
)- Structured logs should use
slogwith request IDs in HTTP builds. - Health endpoints split liveness (process up) from readiness (dependencies OK).
- Traces should span inbound and outbound calls in cloud-native examples.
Related: Production Go: Logs, Metrics, Traces & Signals - Signal vocabulary
5. Read Tests as Design Documentation
Find table-driven tests and integration build tags first.
func TestServiceCreateUser(t *testing.T) {
tests := []struct {
name string
input CreateUserInput
wantErr bool
}{
{name: "valid email", input: CreateUserInput{Email: "a@b.co"}},
{name: "empty email", input: CreateUserInput{}, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// ...
})
}
}- Reference builds mock via interfaces, not monkey-patching globals.
httptestrecords handler contracts without spinning a real port.- Operator and WASM stories add envtest or WASM smoke steps - note CI wiring.
Related: Table-Driven Tests and Subtests - Test style used across builds
6. Compare CLI Release Posture
Study how cobra commands, config, and artifacts align.
# Signals of production CLI hygiene in reference builds
goreleaser release --clean
cosign sign-blob --key kms://... dist/myctl_linux_amd64.tar.gz
myctl version --output json- Multi-command trees separate
version,serve, andmigrateconcerns. - Viper merges flags, env, and config file with explicit precedence.
- Release pipelines attach SBOM or checksums where the story targets enterprise users.
Related: Reference Build: Production CLI with cobra - End-to-end CLI slice
7. Study gRPC Backpressure Hooks
Locate flow control and streaming patterns in data-plane stories.
func (s *server) StreamEvents(req *pb.SubscribeRequest, stream pb.Events_StreamEventsServer) error {
for evt := range s.bus.Subscribe(req.GetTopic()) {
if err := stream.Send(evt); err != nil {
return err // client disconnect or flow control
}
}
return nil
}- High-throughput builds document client-side limits and keepalive settings.
- pprof and benchmark sections belong in the same narrative as RPC design.
- Note where JSON gateways are intentionally absent to protect throughput.
Related: Reference Build: High-Throughput gRPC Data Plane - Streaming slice
8. Note Deploy and Probe Artifacts
Collect Dockerfile, probe paths, and graceful shutdown handlers.
readinessProbe:
httpGet:
path: /readyz
port: 8080
periodSeconds: 5- REST reference builds wire
/healthzand/readyzseparately. - Multi-stage images compile with
CGO_ENABLED=0for static binaries. - Graceful shutdown listens for
SIGTERMand drains in-flight requests.
Related: Health, Readiness & Liveness Probes - Probe semantics
Intermediate Examples
9. Walk a Profiling Narrative
Replay benchmark case study steps against your staging metrics.
go test -bench=. -benchmem ./internal/api/...
curl -s localhost:6060/debug/pprof/profile?seconds=30 > cpu.prof
go tool pprof -top cpu.prof- Start from a latency SLO breach, not from random micro-optimizations.
- Compare alloc_space and wall profiles before changing JSON or SQL layers.
- Record p50/p99 before and after each change; one fix rarely solves every tail.
Related: Benchmark Case Study: JSON API Latency - 200ms to 20ms p99 story
10. Audit Operator Reconcile Idempotency
For Kubernetes operator reference material, trace spec → status loops.
func (r *WidgetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var widget examplev1.Widget
if err := r.Get(ctx, req.NamespacedName, &widget); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// compare generation, patch status, requeue on transient error
return ctrl.Result{}, nil
}- Webhooks validate defaults; reconcilers patch status, not spec, on errors.
- envtest runs controller logic without a real cluster for fast feedback.
- OLM bundle shipping is part of the operational contract, not an appendix.
Related: Reference Build: Kubernetes Operator End-to-End - CRD to bundle
11. Evaluate WASM Host/Guest Contracts
Read TinyGo module exports alongside wazero host embedding.
// Host loads guest; guest exports _start or WASI main
mod, err := runtime.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().
WithStdout(os.Stdout))- Size budgets and syscall allow-lists are part of the security story.
- CI runs WASM smoke tests on every PR to catch broken exports.
- Even non-WASM teams learn strict ABI thinking from this build.
Related: Reference Build: WASI Edge Module with wazero Host - Edge module slice
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).