Skip to content

Weekly Review — Month 6 · Week 4 (Days 162–168)

Journal index · Roadmap › this week

📅 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) — all go test + -race green

💡 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 demo that 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)

  1. 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 TestMain package-level Postgres container to speed integration tests.
  • Write the v1.1.0 issue: 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)