Weekly Review — Month 6 · Week 4 (Days 162–168)¶
📅 The Week in One Line¶
Built the capstone end to end — linkr, a REST+gRPC URL shortener with Postgres, a Redis cache, full observability, a real test pyramid, docs/ADRs — and tagged v1.0.0.
✅ What I Completed¶
- Day 162 — Capstone architecture & setup (ports-and-adapters, composition root)
- Day 163 — REST (chi) + gRPC (protobuf) APIs over one shared service
- Day 164 — Postgres (pgx) persistence behind a port + Redis cache-aside
- Day 165 — Observability (slog/metrics/traces) + deploy (distroless/health/shutdown)
- Day 166 — Integration tests (testcontainers + httptest, build-tagged)
- Day 167 — README, ADRs, OpenAPI, demo script
- Day 168 — Month 6 review + tag
v1.0.0(graduation) - Mini-project: linkr capstone shipped and tagged
v1.0.0 - Exercises solved: 3 (
shortcode,linkstore,lrucache) — allgo test+-racegreen
💡 Lessons Learned¶
- The whole month composes: layering (W4) makes the W1 observability and W2 deploy bolt on as middleware without touching the core.
- "Accept interfaces, return structs" + a single composition root is what made the capstone testable and the memory→Postgres swap a one-liner.
- Cache correctness is a write-side problem: invalidate on every mutation or serve stale data.
- The test pyramid is an economics decision — cheap unit tests run constantly; build-tagged integration tests guard the real wiring without slowing the inner loop.
- Docs are a forcing function: a
make demothat breaks is a doc bug you can detect.
💪 Strengths (what clicked)¶
- Designing around ports/adapters now feels automatic — I reach for the interface-the-consumer-owns first.
- Mapping one neutral sentinel error to per-transport codes (HTTP 404 /
codes.NotFound) is clean and second nature. httptest.Server+ table-driven cases for fast, real HTTP tests.
🧩 Weaknesses (what's still fuzzy)¶
- pgx pool sizing and statement caching under real load — I reasoned about it but didn't measure.
- Trace sampling strategy at scale (tail-based) beyond "sample 100% in the demo."
- gRPC interceptors — I know they're the middleware analogue but wrote fewer of them than HTTP middleware.
🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)¶
- Q: (W1) What ties a log line, a metric sample, and a span together for one request?
A
A shared correlation/trace id carried in context; middleware mints/extracts it, the slog handler stamps every line, and the tracer uses it as the W3C traceparent trace-id.
2. Q: (W2) Name the SIGTERM→drain sequence for a graceful HTTP shutdown. A
signal.NotifyContext(SIGINT, SIGTERM) cancels a context → flip /readyz to not-ready → call srv.Shutdown(ctx) with a bounded timeout to drain in-flight requests → treat http.ErrServerClosed as success.
3. Q: (W3) Why use the route pattern (/links/{code}) as a metric label instead of the concrete path? A
Concrete paths create unbounded label cardinality, exploding Prometheus memory. The pattern is a small fixed set, keeping the time series bounded.
4. Q: (W4) Where must the Repository interface be declared, and why? A
In the consumer (the service) package. Go's implicit satisfaction lets the consumer state the minimum it needs; adapters implement it without the consumer importing them, keeping dependencies pointing inward.
🎯 Action Items¶
- Load-test linkr (k6 from W3) and record real p99 + cache hit-rate numbers in the README.
- Add gRPC interceptors mirroring the HTTP observability middleware.
- Add a
TestMainpackage-level Postgres container to speed integration tests. - Write the
v1.1.0issue: vanity codes + per-link analytics.
🚀 Next Week Goals¶
- Journey is complete at
v1.0.0. "Next week" = maintenance mode: keep the spaced-repetition deck warm, polish the portfolio, and start a small open-source contribution applying these patterns.
📊 Metrics¶
| Hours | Days hit | Exercises | Commits | Avg confidence |
|---|---|---|---|---|
| 9 | 7/7 | 3 | 7 | 3.⅗ |
Suggested commit: docs(journal): week 4 review (capstone shipped, v1.0.0)