Day 167 — Capstone: Docs, Demo & ADRs¶
Month 6 · Week 4 · ⬅ Day 166 · Day 168 ➡ · Journal index
🎯 Learning Objective¶
Make linkr legible to other humans: a README that gets someone running in two minutes, Architecture Decision Records that explain the why, and a short demo that shows it working.
📚 Topics¶
- READMEs that earn a star · ADRs (context → decision → consequences)
go doc/ doc comments · OpenAPI for the REST API · a scripted demo
📖 Reading / Sources¶
- Go blog — Godoc: documenting Go code
- Go — Doc comments guide
- Michael Nygard — Documenting architecture decisions (ADRs)
- OpenAPI Specification
📝 Notes¶
- A README's job: what it is, why it exists, how to run it in one command, and how it's built — in that order. Lead with
docker compose upand acurlthat works → [[readme]]. - Doc comments are the API docs: every exported identifier starts with its name (
// Service coordinates link shortening…).go doc ./internal/linkrenders them; so does pkg.go.dev → [[doc-comments]]. - ADRs capture a decision's context, the decision, and its consequences at the time it was made — immutable, numbered (
docs/adr/0001-ports-and-adapters.md). They answer "why did we do it this way?" for future me → [[adr]]. - My ADRs for linkr: (1) ports-and-adapters layering, (2) Postgres as source of truth + Redis cache-aside, (3) dual REST+gRPC transports, (4) build-tagged integration tests. Each lists the alternatives I rejected and why.
- OpenAPI describes the REST surface so clients can generate SDKs and I get a Swagger UI for free; the gRPC surface is self-describing via the
.proto. - A demo is a forcing function: a
make demotarget that boots the stack, shortens a URL, resolves it, and prints the metrics — if the demo script breaks, the docs are wrong. - Doc the operational facts too: env vars (link to the 12-factor config from [[day-152]]), the
/healthzvs/readyzcontract, and how to read the dashboards.
💻 Code Examples¶
A doc comment is documentation and a usage contract:
// Package link is the domain core of linkr: the Link entity, the Service that
// enforces business rules, and the Repository port that storage adapters
// implement. It imports no transport, SQL, or cache packages by design.
package link
// Resolve returns the URL for code and records a hit. It returns a wrapped
// ErrNotFound (matchable with errors.Is) when no such code exists. A failure to
// record the hit does not fail the resolve.
func (s *Service) Resolve(ctx context.Context, code string) (string, error) { /* ... */ }
Run go doc ./projects/linkr/internal/link to render it — the same text appears on pkg.go.dev.
ADR skeleton (Markdown, one file per decision):
# 2. Postgres as source of truth, Redis as cache-aside
Date: 2026-12-09
## Status
Accepted
## Context
Reads vastly outnumber writes; resolves must be fast and DB-cheap.
## Decision
Postgres holds canonical links; a Redis cache-aside layer fronts reads with a
10m TTL and is invalidated on every write.
## Consequences
+ Fast reads, DB shielded. - Must invalidate on write; brief staleness window
on TTL. Alternative rejected: write-through cache (more complex, no clear win).
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
| Re-read all Week-4 solution doc comments for the "starts-with-name" rule | ✅ | exercises/month-06/week-4 |
| Draft 4 ADRs for linkr (layering, storage, transports, testing) | ✅ | projects/linkr/docs/adr |
🐛 Mistakes Made¶
- First README opened with the architecture diagram — readers bounce before they run anything. Reordered: working
curlfirst, internals last. - Wrote a doc comment as
// This function resolves…→ broke the "start with the identifier name" convention that tooling relies on. Fixed to// Resolve …. - Treated an ADR like a wiki page and edited an old decision. ADRs are immutable; supersede with a new numbered one instead.
❓ Open Questions¶
- Generate OpenAPI from code annotations or hand-write the spec? (Hand-written stays accurate for a small API and doubles as design docs.)
🧠 Active Recall (answer without looking)¶
- Q: Why must a Go doc comment begin with the identifier's name?
A
Because tooling (go doc, pkg.go.dev, gopls) associates the comment with the identifier and renders it as a sentence; starting with the name produces grammatical output ("Resolve returns…") and is the documented convention go vet-adjacent tools assume.
2. Q: Why are ADRs immutable once accepted? A
An ADR records the context and reasoning as it existed when the decision was made. Editing it rewrites history and loses the "why." When circumstances change you write a new, numbered ADR that supersedes the old one, preserving the trail.
🪶 Feynman Reflection¶
Code says what the system does; docs and ADRs say why — and the why is what future-me (and a reviewer, and an interviewer) actually needs. A README is the front door, doc comments are the in-place manual, and ADRs are the decision log that keeps me from re-litigating settled choices. The demo is the proof that all three are honest.
🕳️ Knowledge Gaps¶
- Generating client SDKs from OpenAPI/proto and publishing them — out of scope for the capstone but worth a future spike.
✅ Summary¶
linkr is now documented and demonstrable: a run-first README, name-leading doc comments rendered by go doc, four immutable ADRs explaining the key decisions, an OpenAPI spec, and a scripted make demo.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 168: Month 6 review, week retro, and tag
v1.0.0— graduation.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦🟦⬜⬜⬜ | 🟦🟦🟦🟦⬜ |
Suggested commit: docs(linkr): README, ADRs, OpenAPI, and demo script (day 167)