Lessons
Generics: type parameters and constraints
Type parameters [T any], type constraints (any, comparable, custom interfaces with ~), generic functions and types, and when not to use generics.
What to look for:
- Type parameters go in square brackets: func Map[T, U any](s []T, f func(T) U) []U
- comparable: types that support == (needed for map keys, sets)
- ~int means "int or any type whose underlying type is int" — the tilde is structural
- Generics add complexity — use them for utilities (Map, Filter, Set); prefer concrete types in business logic
Testing: table-driven tests and benchmarks
Testing package, t.Run for subtests, table-driven test pattern, t.Helper, benchmarks with b.N, go test flags, and httptest for HTTP handlers.
Prerequisite: Practitioner Track
What to look for:
- Table-driven: []struct{name, input, want} — the standard Go test pattern
- t.Run("subtest", func(t *testing.T) {...}) — gives each case its own name and failure isolation
- b.ResetTimer() if setup is expensive; b.ReportAllocs() to measure allocations
- httptest.NewRecorder() + httptest.NewServer() for testing HTTP handlers without a real server
Go modules and dependency management
go.mod, go.sum, go get, go mod tidy, replace directives, versioning (v2+), and the module proxy.
Prerequisite: Lesson 1
What to look for:
- go mod init module/path creates go.mod — every Go project needs one
- go.sum is a security file — commit it; never edit manually
- go mod tidy removes unused dependencies and adds missing ones
- Major version v2+ requires a /v2 suffix in the module path — this is a Go convention
Performance: escape analysis and pprof
Stack vs heap allocation, escape analysis (go build -gcflags="-m"), sync.Pool, pprof CPU and memory profiling, and reading flame graphs.
Prerequisite: Lesson 2
What to look for:
- go build -gcflags="-m" shows which variables escape to heap — heap allocations cost GC pressure
- sync.Pool: reuse short-lived objects (e.g. byte buffers) to reduce allocation in hot paths
- pprof: import _ "net/http/pprof" and hit /debug/pprof/profile to get a 30s CPU profile
- Benchmark first, optimise second — Go is fast by default; premature optimisation harms readability
Production patterns: graceful shutdown and middleware
signal.NotifyContext for OS signal handling, graceful server shutdown, middleware chains with http.Handler, structured logging with log/slog, and CORS.
Prerequisite: Lessons 3–4
What to look for:
- Graceful shutdown: srv.Shutdown(ctx) drains in-flight requests; give it a deadline context
- Middleware: func(http.Handler) http.Handler — chain them with a simple compose function
- log/slog (Go 1.21): structured logging with slog.Info("msg", "key", value)
- Always set timeouts on http.Server: ReadTimeout, WriteTimeout, IdleTimeout — never use default zero
After this track: You have the Go fundamentals to work on real projects. Good next steps: build a CLI with cobra, an HTTP API with net/http or chi, or explore the Go standard library at pkg.go.dev/std.
Track quiz
4 questions to check your understanding.
What does the ~ in ~int mean in a Go type constraint?
What does go build -gcflags="-m" show you?
In Go table-driven tests, what is t.Run used for?
Why should you always set timeouts on http.Server?