skip to content
Sandip's Blog
Table of Contents

1. Testing

  • *_test.go, TestXxx(t *testing.T)
  • Table-driven tests with t.Run subtests
  • t.Helper(), t.Cleanup(), t.TempDir(), t.Setenv()
  • t.Parallel()
  • TestMain
  • Golden files
  • httptest.NewServer / httptest.NewRecorder
  • Mocking by interfaces (hand-written fakes beat generated mocks when possible)
  • testify (optional), go-cmp for diffs
  • Coverage: go test -coverprofile=c.out && go tool cover -html=c.out
  • Integration tests with testcontainers-go
  • testing/synctest for concurrent code (newer Go)

Fuzzing

  • func FuzzXxx(f *testing.F), go test -fuzz=.

Benchmarks

  • func BenchmarkXxx(b *testing.B), b.Loop() / for i := 0; i < b.N; i++
  • -benchmem, -count, benchstat for comparing runs
  • Avoid compiler optimizing away results

2. Profiling and performance

  • pprof: CPU, heap, goroutine, block, mutex profiles
  • net/http/pprof in running services
  • go tool pprof -http=:8080 cpu.prof
  • go tool trace: execution tracer
  • Escape analysis: go build -gcflags="-m"
  • Reduce allocations: preallocate slices (make([]T, 0, n)), reuse buffers, sync.Pool, strings.Builder
  • Struct field ordering and padding
  • Avoid premature optimization: measure first
  • PGO (profile-guided optimization)

Visual: the performance workflow

flowchart TD
  A["Write a benchmark"] --> B["Measure: go test -bench -benchmem"]
  B --> C["Profile: pprof CPU and heap"]
  C --> D{"Hotspot found?"}
  D -- "yes" --> E["Change ONE thing"]
  E --> F["Re-run benchmark, compare with benchstat"]
  F --> D
  D -- "no" --> G["Stop. Good enough."]

Rule: measure first, optimize second.

3. Runtime internals (for true mastery)

  • Garbage collector: concurrent tri-color mark-and-sweep, GOGC, GOMEMLIMIT
  • Goroutine stacks (growable)
  • The scheduler: G, M, P, work stealing, preemption
  • How maps, slices, strings, interfaces, and channels are laid out in memory
  • runtime package: NumGoroutine, ReadMemStats, GC
  • Read: A Guide to the Go Garbage Collector (go.dev/doc/gc-guide)

Practice

  1. Write benchmarks comparing += vs strings.Builder vs bytes.Buffer
  2. Take a slow function, profile it with pprof, and cut allocations by half
  3. Fuzz a parser and fix what it finds
  4. Reach 80%+ meaningful coverage on one of your projects

Previous: Go Mastery 4: Standard Library and Tooling
Next: Go Mastery 6: Backend and Production Go

Back to the roadmap