Chapter 23 / 24 · System Design

A worked design, end to end

Everything in one sitting: a real problem taken from requirements to a defensible architecture, out loud.

Everything in one sitting. This is the delivery framework used in design interviews — which is also, not coincidentally, a decent way to run a real design review. Then a problem worked through it, out loud.

The framework

Step~TimeYou produce
1 · Requirements5 minfunctional (what it does) and non-functional (scale, latency, availability, consistency) — three of each, written down
2 · Estimates5 minQPS, storage, read:write ratio — only the arithmetic that will change the design
3 · API + data model5 minthe 3–4 core endpoints and the tables/keys behind them
4 · High-level design10 minthe Stage 1 chain, drawn, every box justified by a requirement
5 · Deep dives15 minthe two or three places your numbers say it breaks — this is where the interview actually happens
6 · Failure & wrap5 minwhat dies first, what degrades, what you would build next

Worked: a URL shortener

Requirements. Functional: create a short link for a long URL; redirect; optional custom alias and expiry. Non-functional: reads dominate massively; redirects should be tens of milliseconds; 99.99% for redirects (the write path can be humbler); links must not vanish.

Estimates. Say 100 M new links/month ≈ 40 writes/s — trivial. At 100:1 read:write, redirects ≈ 4,000/s, spiking higher. Storage: 100 M/month × ~500 bytes ≈ 50 GB/year — one database, for years. The arithmetic has already shaped the design: this is a read problem with a tiny write problem attached.

API + data. POST /links → short code; GET /:code → 301. One table: code (PK), long_url, owner, created_at, expires_at. The interesting decision is the code itself: a base62 encoding of a sequence gives 62⁷ ≈ 3.5 trillion codes at 7 characters. Random codes need a uniqueness check; sequential codes are guessable and reveal volume; a common middle path is per-server pre-allocated ID ranges (no coordination on the hot path) encoded base62.

High level. Stage 1’s chain almost verbatim: DNS → LB → stateless app → cache → DB. Redirects: check cache (cache-aside), miss → DB → fill → 301. With a 90-day-skewed access pattern the hot set is a few GB — cache hit rate in the high 90s, so the DB sees tens of reads/s. A single replicated Postgres with a read replica clears every number with an order of magnitude to spare — say that out loud; earned simplicity is the strongest signal there is.

Deep dives, chosen by the numbers. (1) Hot keys: one viral link can be 50% of traffic — the Stage 2 answer: tiny in-process cache with 1 s TTL in front of Redis. (2) Analytics without slowing redirects: do not write counts on the redirect path; emit a click event to the Stage 5 log and aggregate downstream — the redirect stays read-only. (3) Cache stampede on expiry of a viral key: request coalescing. (4) If asked to 100× the scale: shard by hash of code (single-key lookups shard perfectly), promote the cache to a cluster, note that codes are immutable so replication lag is harmless — consistency was never the hard part here.

Failure story. Cache down → DB takes the full read load: survivable at these numbers, and the breaker + shed-load patterns from Stage 6 guard the spike. DB primary down → replica promotion; writes pause for seconds, redirects keep serving from cache. Degraded mode: redirects work while link-creation is down — which is exactly the availability asymmetry the requirements asked for.

What changes when the problem changes

The framework is stable; the deep dives move with the workload. A news feed is a fan-out problem (push on write vs pull on read, and the celebrity hybrid). A chat system is ordering + presence (per-conversation sequencing through one partition, delivery receipts as idempotent state). A ride-matching or ticketing system is contention (Stage 4’s locking and invariants, plus reservations with expiry). Classify the problem by which stage of this pathway it stresses, and you will know where the interview — or the production incident — is going to spend its time.