Learning Diary: Ultimate Go Notebook by William Kennedy
Background
I tend to read a technical book twice before I can convince myself that I've actually read it. The first time is a cover-to-cover read to absorb the shape of the ideas. The second time is slower — with a codebase open next to the book, writing notes and translating every concept into running code.
This post is to share the notes and code I've written while working through William Kennedy's Ultimate Go Notebook. This was inspired by the idea of learning in public, and I hope you can learn a thing or two from my notes.
A few disclaimers:
- This is not a substitute for the book. Kennedy's explanations carry far more than my notes can. You will rob yourself of a lot of useful knowledge if you use these posts as a replacement for the book.
- Every concept I write about is applied to CloudMeta — a multi-tenant cloud resource metadata collector with a channel-based extraction pipeline, PostgreSQL storage, and a REST API. All code examples come from this real codebase, not playground snippets. Each post has two kinds of examples: a concept-clear example that isolates the idea in a minimal program, and a practical example that shows the same idea inside CloudMeta where real tradeoffs apply.
- These notes were written primarily for my own understanding. I had no intention of sharing them at the beginning. As such, you might find some mistakes — I've tried to get rid of those, but it's possible I missed some. If you find any, please reach out via email.
- Lastly, these posts will differ from the more expository deep-dive posts I'll also publish on this blog. If you manage to gain from my learning diary, that's great. If you come across a topic you want to understand more deeply, you can leverage the numerous resources online — or reach out to me to write about it.
Part One — Foundations
- Chapter 1 — Design Philosophy & Mental Models Kennedy's 8 design pillars applied to real code. The
validatorAdapterpattern. Theinit()self-registration plugin. - Chapter 2 — Memory, Values & the Type System (Part 1) Zero value guarantees. Stack vs heap. Escape analysis with
-gcflags -mon real functions. - Chapter 2 — Memory, Values & the Type System (Part 2) GC semantics. Constants and IOTA. Building a proper
ResourceKindenum. - Chapter 3 — Data Structures & CPU Cache Mechanics (Part 1) How CPU cache lines work. Why
[]Resourceoutperforms[]*Resource. Benchmark at 100,000 elements. - Chapter 3 — Data Structures & CPU Cache Mechanics (Part 2) Maps and iteration order. UTF-8 and rune vs byte.
map[T]struct{}as a set.
Part Two — Language Mechanics
- Chapter 4 — Methods, Interfaces & Embedding Value vs pointer receivers. Auditing every receiver in CloudMeta. Compile-time interface checks.
- Chapter 5 — Software Design & Composition (Part 1) Don't design with interfaces — discover them. How
ExtractorWithClosewas discovered, not planned. - Chapter 5 — Software Design & Composition (Part 2) Idiomatic error handling. The full
StorageErrorchain from database driver to HTTP response.
Part Three — Concurrency
- Chapter 6 — Goroutines & the Go Scheduler The GMP model. Goroutine leak patterns and how to avoid them. Tracing a real pipeline.
- Chapter 6 — Synchronisation: Mutex, RWMutex & Atomics Protecting an in-memory cache. Double-check locking. Why
defer mu.Unlock()is not optional. - Chapter 6 — Channel Patterns in Production Nine channel patterns traced through a real extraction pipeline. Fan-out, fan-in, done, drop.
Part Four — Testing, Generics & Performance
- Chapter 7 + 8 — Testing & Benchmarks Table-driven tests. Benchmarks with
-benchmem. Going from 0% to meaningful coverage. - Chapter 9 — Generics
Pool[In, Out],Filter[T],Repository[T]. When generics clarify — and when they obscure. - Chapters 10–13 — Profiling, Tracing & Stack Traces Reading a real heap profile. Finding a
json.Marshalallocation firing 200 times per second. Before and after.