Skip to content

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

📝 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 up and a curl that works → [[readme]].
  • Doc comments are the API docs: every exported identifier starts with its name (// Service coordinates link shortening…). go doc ./internal/link renders 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 demo target 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 /healthz vs /readyz contract, 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 curl first, 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)

  1. 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)