Owning projects
Design doc template
Context, goals and non-goals, the proposed design, real alternatives, then risks and rollout. Cut empty sections.
Templates vary by company. Cut empty sections.
Concept
A non-goal is a thing you are deliberately not doing. It stops silent expectations. "We are not unifying the mobile and web product models" is as useful as the latency target.
Walking through the sections
Context
One or two paragraphs: what exists today, what hurts, and why now. Link to the ticket, the dashboard, the customer complaint. Assume a smart engineer who has never touched this system.
Goals and non-goals
Goals are measurable outcomes ("p99 read latency under 50 ms for the product detail API at current QPS"). Non-goals stop scope creep.
Proposed design
Data model, APIs, request path, and failure modes — at the level a reviewer can challenge. Prefer diagrams. Call out what you are not inventing (reuse existing auth; write to the existing events topic).
Alternatives considered
At least two real options, including "do nothing" or "buy a vendor" when those are serious. For each: gain, loss, why you rejected it. No alternatives reads like advocacy.
Trade-offs, risks, rollout
Name the hard trade-offs. List risks with mitigations. Sketch flag, dual-write, canary, rollback. Open questions get their own section.
Worked example: caching a slow product API
Context. Product detail API: ~8,000 reads/s, writes ~40/s. p50 ~25 ms; p99 ~180 ms on cold Postgres rows during promotions. Target: p99 under 50 ms in six weeks.
Goals. p99 ≤ 50 ms at current QPS; stale catalog fields ≤ 5 minutes; Redis rollback under 10 minutes.
Non-goals. Caching personalized recommendations; multi-region active-active cache; replacing Postgres.
Proposed design. Cache-aside Redis in the product service. Key product:v1:{id}, JSON payload ~2 KB, TTL 300 s with ±30 s jitter. On write, DEL the key after the DB commit (delete, do not set — avoids write/write races with stale readers). Alert if hit rate < 60% for 15 minutes or Redis errors > 1% of requests.
Alternatives.
| Option | Pros | Cons | Verdict |
|---|---|---|---|
| Do nothing; tune Postgres indexes | No new dependency | Already indexed; load is read amplification | Rejected |
| Read replicas | Spreads read load | Does not help hot-key latency | Rejected for this goal |
| CDN for anonymous HTML | Great for public pages | Logged-in API needs session-aware data | Out of scope |
| Cache-aside Redis | Proven pattern; optional dependency | Stale window; new failure mode | Chosen |
Math for reviewers. At 8,000 QPS and an assumed 80% hit rate: hits cost ~0.5 ms, misses cost ~0.5 + 15 ms DB ≈ 15.5 ms.
effective latency ≈ 0.80 × 0.5 + 0.20 × 15.5
= 0.4 + 3.1
= 3.5 ms averageThat average is not p99, but it shows the DB only sees ~1,600 QPS of product reads instead of 8,000. Validate with a canary, not napkin math alone.
Risks. Cache stampede on popular keys after TTL expiry → singleflight in-process. Redis outage → fail open to Postgres. Stale price for up to TTL → acceptable for this catalog.
Rollout. Flag off → 1% canary → 10% → 50% → 100%. Rollback = flag off. The stale-data budget, fail-open, and rejected read replicas are now in the open — those three prevent months of silent disagreement.
Common mistakes
- No alternatives. Reviewers smell advocacy and dig in harder.
- Goals without numbers. "Make it faster" is not a goal a reviewer can challenge.
- Hiding open questions in paragraphs. Put them in their own section.
Check yourself
A design lists only the chosen approach. What is missing?
At least two real alternatives, including do-nothing when that is serious, each with a reason you rejected it.
Why does the example delete the cache key on write instead of setting a new value?
Delete avoids a write/write race where a stale reader overwrites a fresher value.
Key takeaways
- Context, goals, non-goals, design, alternatives, risks, rollout — cut what does not apply.
- Non-goals and rejected alternatives are how you stop silent disagreement.
- Quantify: QPS, payload size, latency, blast radius. Adjectives do not survive review.
- The worked numbers show the shape of the win. A canary proves it.
Further learning
Related
Design docs and RFCs
Writing design docs that get to a good decision quickly — structure, alternatives, review, and when a one-pager is enough.
When to write a design doc
Skip the doc for small reversible work. Write one when the blast radius is large, the approach is unclear, or you need buy-in.
Writing design docs for reviewers
Lead with the decision on the first screen. Support it with diagrams and numbers. Ask for scrutiny, not applause.