Day 139 — Docs & ADRs¶
Month 5 · Week 4 · ⬅ Day 138 · Day 140 ➡ · Journal index
🎯 Learning Objective¶
Make the project legible: idiomatic godoc comments, a task-oriented README, and Architecture Decision Records (ADRs) that capture why the design is what it is.
📚 Topics¶
- Go doc comments (
doc.go, package/exported-symbol conventions) - README structure (quickstart, run, architecture diagram)
- ADRs: context → decision → consequences; lightweight, append-only
📖 Reading / Sources¶
- Go Doc Comments (official guide)
- Effective Go — Commentary
- Michael Nygard — Documenting Architecture Decisions (ADRs)
- adr.github.io — ADR templates & tooling
📝 Notes¶
- Doc comments are godoc. A comment immediately above a package/func/type, starting with the symbol's name, becomes its documentation (
go doc, pkg.go.dev). Write full sentences; the first sentence is the summary line → [[godoc]]. - Put a package overview in a
doc.go(or atop the primary file) for anything non-trivial — what the package is for and how to use it. Document the contract (preconditions, who closes what, goroutine-safety), not the obvious mechanics → [[package-docs]]. - Document exported identifiers only as API; unexported helpers get short inline comments for the next reader. A
// Deprecated:paragraph is a recognized convention tooling surfaces → [[exported-api]]. - A README is task-oriented: one-line what-it-is, quickstart (
go run ./cmd/server), how to send a request (grpcurl), config/env, an architecture sketch, and how to run tests. Optimize for someone who has 90 seconds → [[readme]]. - ADRs record a single decision: Context (forces at play), Decision (what we chose), Status (proposed/accepted/superseded), Consequences (trade-offs accepted). They're short (~1 page), numbered, append-only — supersede rather than edit, so history is preserved → [[adr]] [[decision-record]].
- ADRs answer the question code can't: why this and not the alternative? — e.g. "why Redis lists and not a real broker," "why hexagonal layering," "why at-least-once + idempotency." Future-you (and reviewers) stop re-litigating settled choices → [[design-rationale]].
💻 Code Examples¶
// Package queue provides an at-least-once background job queue backed by a Redis
// list. Producers enqueue jobs with Push; a worker pool drains them with retry,
// exponential backoff, and a dead-letter queue for jobs that exhaust their
// budget. All exported methods are safe for concurrent use and take a
// context.Context as their first argument for cancellation and deadlines.
//
// Delivery is at-least-once, so handlers MUST be idempotent (dedupe on Job.ID).
package queue
<!-- docs/adr/0003-redis-list-as-broker.md -->
# 3. Use a Redis list as the job broker
Status: Accepted — 2026-11-11
## Context
We need a simple, durable-enough background queue without operating Kafka/RabbitMQ.
Traffic is modest; at-least-once delivery is acceptable if handlers are idempotent.
## Decision
Use a Redis list with BRPOPLPUSH into a processing list for reliable pop, plus a
dead-letter list for exhausted jobs.
## Consequences
+ Tiny operational surface; one dependency we already run.
+ Reliable-enough delivery with a reaper for stuck processing entries.
− No native consumer groups/ordering guarantees; we own retry/DLQ logic.
− Revisit (supersede this ADR) if throughput outgrows a single Redis.
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
Write a doc.go package overview for the queue package |
✅ | (project docs) |
| Author ADR-0001 (hexagonal) … ADR-0003 (Redis broker) | ✅ | (project docs/adr) |
🐛 Mistakes Made¶
- Wrote a doc comment that didn't start with the symbol name → it rendered oddly and
go doccouldn't associate it. Started comments withPackage queue …/Push …. - First ADR mixed three decisions into one file. Split them so each record is a single, supersedable choice.
❓ Open Questions¶
- Do I keep ADRs in-repo (
docs/adr/) only, or also publish a rendered index — and is an ADR linter worth it?
🧠 Active Recall (answer without looking)¶
- Q: What four sections make up an ADR, and why are ADRs append-only?
A
Context (the forces/constraints), Decision (what was chosen), Status (proposed/accepted/superseded), and Consequences (trade-offs accepted). They're append-only so the historical reasoning is preserved; a changed decision is recorded by adding a new ADR that supersedes the old one, not by editing it.- Q: What makes a Go comment show up as godoc, and what should the first sentence be?
A
It must directly precede the package/type/func/var declaration (no blank line) and begin with the identifier's name. The first sentence is the summary shown in listings, so it should be a concise, full-sentence description of what the symbol does.🪶 Feynman Reflection¶
Docs are three layers for three readers. Godoc is for the developer calling your API right now — it states the contract. The README is for the newcomer with 90 seconds — run it, send a request, see the shape. ADRs are for the maintainer six months later asking "why on earth did we pick Redis?" — they freeze the reasoning so settled debates stay settled.
🕳️ Knowledge Gaps¶
- Generating example tests (
Example_*) that double as runnable, verified godoc examples.
✅ Summary¶
I can document a Go project at three levels: contract-stating godoc comments and a doc.go overview, a task-oriented README, and numbered, append-only ADRs that capture the design rationale future maintainers need.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 140: Month 5 review, spaced-repetition recall, and tag the release
v0.5.0.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦⬜⬜⬜⬜ | 🟦🟦🟦🟦⬜ |
Suggested commit: docs(project): godoc, README & architecture decision records (day 139)