System design questions look endlessly varied, but take one apart and it is almost always built from a handful of paths: an upload path, a read path, a background-processing path, a push path. Each kind of path has a fixed shape, a fixed hard part, and a fixed set of standard moves. And at every hard part you make a choice that has to be defended out loud.
This framework organizes both halves into one structure. Patterns tell you what the system is made of; tradeoffs tell you how to choose at each joint. The goal is a single capability: handed a question you’ve never seen, you can say which known patterns it’s made of, how they connect, and what to discuss when you go deep — and you can defend every choice along the way.
Every other system design page on this site plugs into it. Walkthroughs are worked examples of patterns; concept references are layer-3 mechanisms; the 9-week plan is the order to learn them in.
The problem
Two failures dominate senior system design rounds, and they look unrelated.
The first is memorizing systems instead of shapes. You prepared News Feed, Chat, and URL Shortener. The interviewer asks you to design a satellite fleet manager, or an online judge, or a feature-flag service. None of your prepared systems match, so you start from a blank page — and spend fifteen minutes rediscovering things you already know, because you filed them under “News Feed” instead of under “one write that must be read in many other places.”
The second is “it depends.” Interviewers hear it thirty times a day. The candidates who pass don’t stop there — they name what it depends on, commit to one side, and say what they’re giving up. Candidates who fail list options without committing, or pick a side without naming the cost. Under interview pressure, with working memory full, most engineers revert to the failing version.
These are the same problem at two altitudes. The first is not knowing where the hard parts are; the second is not knowing how to talk once you’re there. A senior answer needs both: decomposition gets you to the right joints fast, and tradeoff reasoning is what you say at each joint.
Important
Key takeaway: Patterns are visible; decisions must be derived. The question says “users upload videos” — it never says “there’s a skew problem here.” So you decompose with patterns first, then go deep with decisions, and you make every decision legible with the same four steps: axes, context, cost, commit.
The framework: four layers
| Layer | What it is | The question it answers | How you use it |
|---|---|---|---|
| 0 · Building blocks | Load balancer, stateless services, cache, database, log / queue, object store, CDN, ID generation | Which boxes do I draw by default? | Present in every design; no recognition needed |
| 1 · Path patterns | Ten path shapes, plus one extension (expensive compute) | Which paths is this question made of? | Recognize from signals in the prompt; draw the diagram |
| 2 · Decisions | Seven recurring decisions: five inside a path, two between paths — each argued with the four tradeoff steps | What do I have to choose on each path, and how do I defend it? | Your deep-dive checklist; most senior signal comes from here |
| 3 · Concepts | Concrete mechanisms: consistent hashing, sagas, watermarks, fencing tokens… | How is this decision actually implemented? | Called on when the interviewer pushes for detail |
Two rules govern the whole thing:
- A pattern describes a path, not a whole system. Don’t say “Instagram is a feed question.” Say “Instagram has a large-object upload path, a fan-out path, a read path, and a search path.” Composition falls out naturally.
- Patterns are seen; decisions are derived. You can spot a pattern from the wording of the prompt. You can’t spot a decision — you have to ask the question that reveals it (“what does the follower distribution look like?”).
Layer 0: Building blocks
These appear in almost every design, and each has a default way to scale. Draw them without justifying why they exist; spend your words on the paths.
| Block | Default scaling | Go deeper |
|---|---|---|
| Load balancer + stateless services | Scale horizontally; services hold no state | Load Balancing & Service Discovery |
| Cache | Cache-aside; size by memory (working set), not by QPS | Caching Patterns |
| Database (relational / KV / wide-column) | Choose by access pattern, partition by key, add replicas | SQL vs NoSQL · Database Indexing · Storage Engines |
| Partitioning and replication | Partition key + leader/follower or leaderless | Partitioning · Replication · Consistency Models |
| Log / queue | Scale by partition; consume with consumer groups | Queue vs Log · Queue Delivery Semantics |
| Object store + CDN | Blobs are immutable; the CDN is the read path | CDN & Edge Delivery · CDN walkthrough |
| ID generation | Range allocation or Snowflake-style | Unique ID Generation |
| APIs, auth, resilience | REST / gRPC, token auth, timeout + retry + circuit breaker | API Design Patterns · Authentication & Authorization · Resilience Patterns |
Note
Interview signal: When the question is a building block — design a distributed KV store, Kafka, Memcached, a distributed lock, an ID generator — you are being asked to open one block up. The content is then partitioning, replication, quorums, version vectors, repair, and consensus (Quorums & Conflict Resolution · Anti-Entropy · Consensus), all answered inside one component. These questions get more common above senior level. The Distributed Key-Value Store walkthrough is the model answer for this category; the Distributed Database, Queue, Lock, and Cache walkthroughs are the rest of it.
Layer 1: The ten path patterns
| # | Pattern | Signals in the prompt | Standard shape | Dominant decisions | Example systems |
|---|---|---|---|---|---|
| P1 | Key lookup | Fetch by ID; reads vastly exceed writes; data rarely changes | Multi-tier cache + KV store; the write path guarantees ID correctness | C, D | URL shortener, product page, profile page |
| P2 | Retrieval & ranking | Search, recommend, nearby, autocomplete, compare prices; can’t fetch by key | Index + funnel: retrieve → rank → filter; or scatter-gather across sources | A, D | Search, recommendations, nearby drivers, typeahead, flight search, RAG retrieval |
| P3 | Write-then-derive | Written once, must be read elsewhere, in another shape | Source of truth + events → async materialized views (fan-out, indexes, counts) | A, C | Feed fan-out, search indexing, CDC |
| P4 | Event aggregation | Count, stats, leaderboards, trends, monitoring, alerts; events vastly outnumber queries | Log → windowed aggregation → summary store; batch reconciliation | D, C | Ad clicks, metrics, top-K, trending, leaderboards |
| P5 | Contention | Limited slots, stock, or quota; “must not oversell”; bidding; rate limits | Shed traffic tier by tier + atomic decrement / single writer + holds with a TTL | E, G | Flash sale, ticketing, rate limiter, auction, driver locking |
| P6 | Workflow / saga | Checkout, payment, state machines; spans services; must roll back | Durable state machine / orchestrator + idempotent hops + compensations | G, F | Orders, payments, trip lifecycle, agent loops |
| P7 | Background jobs | Background, scheduled, batch, crawl, transcode, retry | Durable queue / scheduler + worker pool + leases + retries and a DLQ | G, E | Crawler, job scheduler, notification sending, transcoding, online judge |
| P8 | Real-time connections | Live, presence, push, chat, co-editing, live comments | Gateways that only hold sockets + routing registry + durable store as truth | B, G | Chat, presence, live comments, collaborative docs |
| P9 | Large objects | Files, images, video; upload, download, sync | Content split from metadata + chunks and content addressing + commit content before pointer + CDN | F, C | Video platform, file sync, photo upload |
| P10 | Control plane | Config, deploy, release, firmware, feature flags, experiment config; “bring a fleet to some state” | Versioned desired state + agents reporting actual state + reconcile loop + staged rollout with rollback | F, G | Device / IoT fleet management, deploy systems, config service, experimentation platform |
| Ext. | Expensive compute | Model inference, GPUs, per-token billing | Admission control + continuous batching + KV / prefix cache + routing | E, A | LLM serving |
Boundaries people confuse
- P1 vs P9. Both are “immutable content, skewed popularity, the cache is the architecture.” P1 reads small keys, and the hard parts are ID correctness and caching. P9 moves large files, and the hard parts are the upload pipeline, the processing pipeline, and metadata consistency.
- P3 vs P4. P3 turns one write into many views (1 → N). P4 turns many events into a few numbers (N → 1).
- P5 vs P6. P5 is many requests fighting over one thing. P6 is one request crossing many services. A flash-sale checkout has both: grabbing the stock is P5; payment and shipping after the decrement is P6.
- P6 vs P7. P6 cares about cross-service correctness (compensate, stay consistent). P7 cares about the throughput and scheduling of many tasks (who does it, when, and what happens on failure).
- P8 vs P10. P8 delivers messages to clients that are online. P10 makes devices converge on a state; a device can be offline for days, and when it returns it catches up on state, not on a replay of every message.
P1 · Key lookup
- Signals: fetch by ID or short key; read:write above 100:1; data barely changes after creation.
- Core tension: the read path is enormous, so the cache is the architecture — but correctness lives on the write path: no two URLs may ever share a short code.
- Standard moves:
- Estimate first, and arrive at “no database serves this read rate directly.” That number justifies the CDN, application cache, and KV tiers.
- Generate IDs from a range-allocated counter plus base62, which removes collisions by construction — instead of check-then-insert with retries.
- Size the cache by the memory of the working set, not by QPS.
- Immutable data almost never needs invalidation; set the TTL a little below the expiry.
- Push side effects like click analytics onto an async event stream (it becomes a P4 path) so they never slow the main path.
- Cost: a brief inconsistency window after writes — usually fine for this kind of product.
- Traps: treating the ID scheme as a detail; a cache outage that turns into a stampede because you never mentioned request coalescing.
- Follow-ups: Why 302 rather than 301? What happens to an app server’s ID range when it crashes? What happens when Redis dies at peak?
- Anchor: URL Shortener — a 100:1 read ratio; the cache is the architecture.
- Read next: Caching Patterns · Unique ID Generation
P2 · Retrieval & ranking
- Signals: search, recommend, nearby, autocomplete, compare; the result can’t be fetched by key — it has to be found inside a large set.
- Core tension: the corpus is too big to score every item, so it must be a funnel — and each stage has a different job and a different metric. Blur them and things break.
- Standard moves:
- Justify the funnel with arithmetic: 100M items × per-item scoring cost is far beyond the latency budget.
- Judge retrieval by recall (wide, overlapping sources); judge ranking by precision (fresh features).
- Apply visibility (permissions) at retrieval time, not after ranking — otherwise you waste compute and risk returning an empty page.
- Define each feature once, materialize it in two places, to prevent training-serving skew.
- Shard search by document; control tail latency with hedged requests and partial results.
- “Nearby” is retrieval on a spatial index — a geohash query scans 9 cells, not 1.
- When the sources are external (airlines, hotels), retrieval becomes scatter-gather: parallel requests, timeouts, partial results, and short-TTL caching.
- Cost: several stages to maintain separately; recommenders carry feedback-loop bias that you hedge with exploration.
- Traps: “just use Elasticsearch”; treating retrieval as a worse ranker; filtering visibility only after ranking; scanning one geo cell.
- Follow-ups: What is training-serving skew? A private post leaked to a non-friend — how? Why nine cells?
- Anchor: News Feed’s follow-up “switch from chronological to relevance”: merge the candidates first, then add a scoring layer.
- Read next: Post Search · Recommendation System · Full Ranking System · Geospatial Matching · Inverted Index · Two-Stage Ranking · ANN Indexes · Geospatial Indexing
P3 · Write-then-derive
- Signals: one write must become visible elsewhere, or queryable in another shape — a new post lands in followers’ feeds, a product update lands in the search index, one relationship must be queried from both directions.
- Core tension: write cost scales with fan-out, and fan-out follows a power law. Design for the average and you will fall over on the single most extreme user.
- Standard moves:
- Ask for the distribution of the skew, not the average.
- Keep the write path to the authoritative record plus one event; fan out in async workers.
- Push for ordinary users at write time, pull for extreme users at read time, and merge-and-dedupe at read time.
- Use a log-based stream, because replay is how you repair a fan-out bug.
- Model data around the queries: every hot query is a single-partition read, which is why one relationship is often stored as two inverse tables.
- Cost: two paths and a threshold policy to maintain; a new read-side hot spot (the celebrity account being pulled).
- Traps: designing for the average user; storing ranking scores in the inbox (rank at read time); forgetting to dedupe after the merge.
- Follow-ups: What happens when a celebrity posts? Why two follow tables? A user posts, refreshes, and doesn’t see their own post — why?
- Anchor: News Feed — one post, fanned out asynchronously into every follower’s inbox.
- Read next: NoSQL Hot Key Mitigation · SQL vs NoSQL Schema Design · Queue vs Log
P4 · Event aggregation
- Signals: counts, stats, leaderboards, trends, monitoring, alerts; a flood of events in, a few summary numbers out.
- Core tension: freshness versus correctness. A fast streaming path can answer “roughly what is it now” but can be silently wrong; billing needs “what is true.”
- Standard moves:
- Give each goal its own owner: the streaming path owns freshness; a batch path over the immutable raw log owns correctness and may overwrite the stream’s results (Lambda). Or keep only the stream and correct by replaying the log (Kappa).
- Inside the stream, handle event time, watermarks, and late data.
- Exactly-once comes from dedup, atomic checkpoints, and a transactional sink together — and say that it ends where side effects leave the framework.
- Hot keys get two-phase aggregation: salt to spread, then merge.
- When exact isn’t required, use approximate structures (Count-Min Sketch + Space-Saving for top-K).
- A time-series system’s capacity limit is the number of series (cardinality), not the number of samples — cap cardinality at ingest.
- Cost: two paths to maintain and keep in agreement.
- Traps: a single Kafka-to-database pipe; claiming exactly-once without stating its boundary; an alerting path that fails silently itself.
- Follow-ups: What about late events? One ad takes 10% of all traffic — now what? Why is cardinality the bottleneck of a metrics system?
- Anchor: Ad Click Aggregation — a firehose of click events, aggregated by time window into counts.
- Read next: Metrics & Monitoring · Top K · Consecutive Activity Aggregation · Stream Processing · Approximate Counting · Time-Series Storage
P5 · Contention
- Signals: limited slots, stock, or quota; “must not oversell”; many requests fighting for the same thing at once; bidding; rate limits.
- Core tension: the hard part is contention, not throughput. Correctness isn’t a switch you flip — it’s the result of where you put the atomic operation, the key, and the TTL.
- Standard moves:
- Make most requests lose at the cheapest tier: CDN, bot checks, gateway, admission tokens / virtual queue — and only then the sharded inventory.
- Use an atomic, guarded decrement, never read-then-write.
- Use holds with a TTL, so a crash can’t lock the resource forever.
- When strict ordering matters (auction bids), serialize through a single-writer actor.
- Acquire multiple resources in a fixed order to prevent deadlock.
- Choose the direction of failure: for zero-tolerance stock, undersell rather than run async replication with failover; for a rate limiter, decide whether Redis going down means fail-open or fail-closed.
- Cost: one heavily protected hot spot; some requests are rejected.
- Traps: database row locks at a million QPS; reading the counter, then writing it (two gateways both see “1 left”); holds without a TTL.
- Follow-ups: Two customers race for the last item — who wins? A Redis shard fails over right after selling out — what happens? The rate limiter’s Redis dies — now what?
- Anchor: Flash Deal — most requests are turned away in the first few tiers, before they ever touch inventory.
- Read next: Rate Limiter · Auction · Rate Limiting Algorithms · Distributed Lock · Distributed Locks & Fencing · Isolation & MVCC
P6 · Workflow / saga
- Signals: checkout, payment, refund, trip lifecycle; one business operation spans several services; a failure midway must roll back.
- Core tension: partial failure across services. You can’t lock every service in one big transaction, but the outcome must be consistent.
- Standard moves:
- Across services, use a saga rather than 2PC: a chain of local transactions, each with a compensating action.
- Persist the orchestrator’s state — it is itself a state machine.
- Retry first, compensate last; put non-compensable steps (shipping, charging an external account) at the end.
- Carry an idempotency key, derived from the business operation, on every hop.
- Use an outbox to solve the dual write between “update the database” and “publish the message.”
- Reconcile periodically with external systems (payment gateways), because they can’t promise exactly-once.
- Agent loops share this shape: checkpoint every state transition; put an approval gate before irreversible actions.
- Cost: eventual consistency; complex compensation logic; idempotency keys to store.
- Traps: “just use a distributed transaction”; orchestrator state held in memory; compensations that aren’t idempotent themselves.
- Follow-ups: The compensation fails — then what? The payment gateway times out but actually charged the card — then what? The orchestrator crashes midway — then what?
- Anchor: Order Processing — payment, inventory, shipping, notification; any step can fail and must be compensated.
- Read next: Distributed Transaction Patterns · Agent Orchestration · Idempotency & Outbox
P7 · Background jobs
- Signals: background tasks, scheduled tasks, batch processing, crawling, transcoding, sending notifications, judging submissions; “accept now, finish later.”
- Core tension: many tasks must run reliably on a limited worker pool — none lost, none harmfully run twice, and not dragged down by one large tenant or one batch of poison messages.
- Standard moves:
- Persist the task to a queue or scheduler before returning “accepted.”
- Workers claim tasks under a lease (visibility timeout); an expired lease returns the task to the queue; results carry a fencing token so a stale worker can’t overwrite them.
- Delivery is at-least-once, so task handling must be idempotent.
- Retry with exponential backoff plus jitter; past the limit, send to a DLQ.
- Separate queues by priority and tenant so low-priority work or a large tenant can’t starve everyone else (in notifications: critical alerts never wait behind marketing).
- Use a timing wheel or bucketed delay queues for scheduled and delayed tasks — not database polling.
- Multi-step jobs (transcode: split → transcode in parallel → write manifest) are a DAG, where every step is an independently retryable job.
- Cost: task-state storage; duplicate execution is always possible and can only be absorbed by idempotency.
- Traps: scheduling by polling
SELECT ... WHERE run_at < now(); leases without fencing, so two workers run the same task; retries without backoff, causing an avalanche; no DLQ, so one poison message blocks the whole queue. - Follow-ups: A worker crashes halfway through — what happens? A million tasks come due at the same instant — what happens? One tenant floods the queue — what happens?
- Anchor: Distributed Job Scheduler — the worker dies mid-task, its lease expires, and the task goes back to the queue.
- Read next: Notification System · Queue Delivery Semantics · Timing Wheels & Delay Queues · Distributed Locks & Fencing
Tip
Why it deserves its own practice: Background jobs rarely get top billing in a prompt, so prep material tends to scatter them across notifications, transcoding, and schedulers. But they’re one of the most frequent patterns in high-frequency questions — crawlers, schedulers, online judges, firmware rollouts. Practice them as a pattern, not as a side detail of other systems.
P8 · Real-time connections
- Signals: real-time, presence, push, chat, co-editing, live comments.
- Core tension: connections are stateful and bound to one server, but delivery routing has to be global. The real load is often “100M long-lived connections,” not message volume.
- Standard moves:
- Compare WebSocket, SSE, and long polling before choosing.
- Connection servers only hold sockets; a registry or pub/sub answers “which machine holds this user’s socket?”
- Delivery is at-least-once plus client-side dedup; an idempotency key turns it into exactly-once from the user’s point of view.
- Guarantee order only within a conversation: one conversation’s messages land on the same partition owner.
- The durable store is the truth; a push notification is only a wake-up signal. Offline users catch up from the store when they return.
- Co-editing: one owner worker per document as the single writer; the offline-editing requirement decides OT versus CRDT.
- Cost: the connection fleet, the durable delivery pipeline, and offline push are three tightly coupled systems.
- Traps: defaulting to WebSocket; treating push as the delivery mechanism; deploying connection servers by dropping every connection at once, causing a reconnect storm.
- Follow-ups: A user sends from two devices at once — how is order kept? A connection server restarts — what happens? A 10,000-member group chat — how does a message fan out?
- Anchor: Chat System — “which machine holds this user’s socket?”
- Read next: Collaborative Editor · Real-Time Connection Patterns · Load Balancing & Service Discovery
P9 · Large objects
- Signals: files, images, video; upload, download, sync, backup, transcode.
- Core tension: content and metadata have opposite personalities. Content is immutable and huge; metadata is mutable and needs transactional consistency.
- Standard moves:
- Split content and metadata into two systems and design them separately.
- Content-address content by hash and store it in fixed-size chunks — which buys resumable upload, dedup, delta sync, and cheap versions all at once.
- On upload, commit the content first and the pointer last, so a crash leaves garbage, not corruption.
- Processing (transcoding, thumbnails) is derived data, handed to P7 jobs; video transcodes in parallel by “segment × rendition,” then writes a manifest.
- Delivery runs through a CDN, and what you design is the miss stream: request coalescing, a shield tier, admit-on-second-hit.
- Express change as a new versioned URL; purge is for emergencies.
- File sync: what you design is sync bookkeeping (sync cursors, keep both copies on conflict), not just transfer.
- Cost: garbage collection gets hard — reference counts are spread across a sharded metadata tier, and GC has to coordinate across shards.
- Traps: “a blob store plus a CDN plus FFmpeg”; uploading a whole file in one POST; designing only the cache box; designing file transfer instead of file sync.
- Follow-ups: Walk the pipeline from upload to playback. How does CDN invalidation work? A million users request a brand-new object at once — what happens to the origin?
- Anchor: File Storage & Sync — content first, pointer last: a crash leaves garbage, not corruption.
- Read next: Video Streaming · CDN · CDN & Edge Delivery
P10 · Control plane
- Signals: config, deploys, releases, firmware updates (OTA), feature flags, experiment config; “bring a fleet of devices or machines to some state”; devices may be offline for long stretches.
- Core tension: the control plane has to reliably change the state of thousands of data-plane nodes — but nodes go offline, changes fail, bad changes must be reversible, and the control plane itself must never become the data plane’s point of failure.
- Standard shape:
- Desired state — versioned, stored in a small strongly consistent store; the single source of truth.
- Actual state — reported by agents; a derived view.
- Reconcile loop — diff the two and push nodes toward desired state; the loop is idempotent and safe to rerun at any time.
- Rollout controller — release in stages with a health gate between stages; a tripped gate halts and rolls back.
- Standard moves:
- Declarative, not imperative: ship “what the state should be,” not “run this command.” Lose one imperative command and state drifts.
- Bump a version on every change; resolve concurrent edits with a CAS on the version.
- Agents pull (long polling) by default, with push notifications as a hint; a returning device compares versions and catches up on the diff, not on a replay of history.
- Stage rollouts (1% → 10% → 50% → 100%) with health gates fed by data-plane metrics; nodes keep the last good version locally and roll back on failure.
- Static stability: if the control plane is down entirely, the data plane keeps running on the last valid config.
- When connectivity is intermittent (a satellite pass window), precompute the batch to send outside the window; inside the window, only transmit.
- Cost: there is always a convergence delay between the two states; staged rollouts slow releases down.
- Traps: sending commands one by one; releasing to the whole fleet at once; the data plane reading config from the control plane on every request, so a control-plane outage takes everything down; no rollback path.
- Follow-ups: A device comes back after three days offline — what does it get? Errors climb at the 10% stage — what happens? Two operators edit the same device’s config at once — what wins? The control plane goes down — what does the data plane do?
- Anchor: the satellite fleet example below — three days offline, and it catches up on the diff, not a replay.
- Read next: Consensus · Anti-Entropy · Resilience Patterns
Extension · Expensive compute
- Signals: model inference, GPUs, per-token billing, nondeterministic output.
- Core tension: the scarce resource is GPU memory, not request routing; cost scales with tokens, not requests.
- Standard moves: in LLM serving the budget is the KV cache, not the weights — so use continuous batching and a paged KV cache for utilization, and prefix caching with prefix-aware routing to cut prefill cost. Protect the GPUs with admission control and queuing (a variant of P5).
- The rest of an AI system is composition of patterns you already know:
- RAG = P2 (hybrid retrieval + rerank), with retrieval and generation evaluated separately.
- Agents = P6 (a checkpointed state machine) plus budgets, approval gates, and sandboxing.
- Vector database = the index inside P2, trading recall against latency against memory.
- Traps: static batching; tuning prompts when retrieval never found the answer; agent loops without a budget.
- Read next: LLM Serving · RAG System · Vector Database · Agent Orchestration · ANN Indexes
Layer 2: The seven decisions
Patterns give you the boxes. Decisions are where the interview is scored. Five decisions live inside a path; two live between paths and hold the composition together.
Five decisions inside a path
| # | Decision | The question to ask | Typical options | Anchor |
|---|---|---|---|---|
| A | Where the work happens | Compute at write time, read time, or async? Is it on the critical path? | Push / pull; precompute / compute on demand; sync / async | URL shortener: the redirect never waits for analytics — click events go onto a queue |
| B | Partitioning & ownership | Partition by what key? Who owns which piece of state? | By user / document / region / device; single-owner workers; stateful vs stateless | KV store: consistent hashing — adding a node moves only ~1/N of the data |
| C | Skew | Where is the power law? What do you do with the few extreme keys? | A separate path for the few; salting; tiered caches; two-phase aggregation | News feed: a handful of celebrities hold a disproportionate share of follows → pull them at read time |
| D | Correctness budget | How stale, how approximate, how provisional can the result be? | Strong / eventual / read-your-writes; approximate structures; stream first, correct with batch | KV store: under a partition, must writes succeed (AP) or be refused (CP)? |
| E | Ordering & contention | Which operations must be serialized? Who serializes them? | Atomic ops; single writer; conditional update / CAS; lease + fencing token | Rate limiter across machines: two gateways both see “1 left” → check-and-decrement must be atomic |
Two decisions between paths (the glue)
| # | Decision | The question to ask | Typical options | Anchor |
|---|---|---|---|---|
| F | Source of truth & derivation | Which data is the truth? What can be rebuilt from it? | Event log; outbox; materialized views; replay; version numbers | Ad clicks: the immutable raw log is the truth; every aggregate can be recomputed from it by batch |
| G | Failure, retry & overload | What happens on partial failure? What gets shed first under overload? Which way do you fail? | Idempotency keys; at-least-once; saga compensation; load shedding; priority isolation; fail-open / fail-closed | Order processing: the downstream processed it but the ack was lost → an idempotency key flows from the client through every hop |
Anchors come from the URL Shortener, Distributed Key-Value Store, News Feed, Rate Limiter, Ad Click Aggregation, and Order Processing walkthroughs. Remember the one point, and the decision comes back with it.
Important
Key takeaway: Patterns almost always connect through two things: events (a log or an outbox) and derived views. That’s why F and G are the keys to composition. Upstream writes the truth and emits an event; downstream consumes the event and builds a view. At every seam, the event must not be lost (outbox) and duplicate delivery must be harmless (idempotency).
Making a decision out loud: the four steps
Naming the decision isn’t enough; you have to argue it. Every decision above gets the same four steps. Do all four and you’ve done the reasoning; skip one and you haven’t.
- Name the competing axes — what you’re trading between.
- Explain the context that breaks the tie — what about this system favors one side.
- State the cost you’re accepting — what you lose, and why it’s tolerable here.
- Commit — pick a side and say it out loud.
Step 1: Name the competing axes
Not “pros and cons” — that’s a list, not a tradeoff. A tradeoff has two (occasionally three) properties where improving one degrades the other. The recurring pairs, and the decisions where each one usually shows up:
| Axis pair | What you’re choosing between | Usually under |
|---|---|---|
| Consistency ↔ Availability | Correct answers vs answers at all (under partition) | D |
| Latency ↔ Consistency | Fast reads vs up-to-date reads | D |
| Accuracy ↔ Latency | Precise answers vs fast, approximate ones | D |
| Write cost ↔ Read latency | Cheap writes (normalize, pull) vs fast reads (denormalize, push) | A |
| Latency ↔ Throughput | Fast individual requests vs high aggregate capacity | A |
| Coupling ↔ Latency | Independent services (network hop) vs in-process calls | B |
| Durability ↔ Write speed | fsync every write vs batch and risk loss | F |
| Correctness ↔ Availability under failure | Fail closed vs fail open | G |
| Cost ↔ Latency | Cheap infrastructure vs fast responses | C |
| Operational simplicity ↔ Optimality | Fewer moving parts vs the best possible performance | any |
The move: at a decision point, say “the tradeoff here is between X and Y” before you pick. That one sentence is the difference between “it depends” and structured reasoning.
Step 2: Explain the context that breaks the tie
Something about this system makes one side matter more. It almost always comes from one of five constraints — and most of them are exactly what the pattern’s signals already told you:
- Access pattern. Read-heavy (P1), write-heavy (P4), or bursty (P5). Decides whether you optimize the read path or the write path.
- Scale dimension. What is large — users, data volume, request rate, connections (P8), fan-out (P3)? The binding constraint shapes the choice.
- Failure tolerance. What happens if this component is wrong or slow? User- facing (intolerable) or internal (degradable)?
- Consistency requirement. Correct now (money, stock), eventually correct (a feed), or approximately correct (analytics)?
- Mutation rate. Low mutation → cache aggressively. High mutation → the cache becomes a consistency problem.
The move: “In this system, [context] means we should favor [side].” Context is what turns a preference into a decision.
Step 3: State the cost you’re accepting
Naming the cost — explicitly, out loud — is what separates SDE III answers from SDE II answers. SDE II picks a side and explains why it’s good. SDE III picks a side, explains why it’s good for this context, and names what breaks because of it. Every pattern card above lists the cost for exactly this reason.
The move: “The cost is [what we lose]. We accept it because [why it’s tolerable here].”
Step 4: Commit
The first three steps are analysis; this one is the deliverable. Candidates who stop at step 3 sound like they’re still deliberating. Say “so I’d go with X.” If an assumption is uncertain, commit conditionally — “assuming read-heavy, X; if it’s write-heavy, Z.” A conditional recommendation is still a recommendation. Refusing to pick is the only failing move.
Three decisions, argued
Decision A in a URL shortener (P1): where does the cache live?
- Axes: latency ↔ consistency. Edge caching skips the origin round-trip but is harder to invalidate; an application cache is a little slower but easy to invalidate.
- Context: short URLs are effectively immutable — created once, redirected forever. The usual argument against aggressive caching barely applies.
- Cost: a deleted URL keeps redirecting from cached copies until the TTL expires. Acceptable: deletion is an admin action, and a five-minute stale window on it is fine.
- Commit: cache at both tiers, with long TTLs.
Decisions A and C in a news feed (P3): push or pull?
- Axes: write cost ↔ read latency. Push makes every post N writes; pull makes every feed load N reads.
- Context: feeds are read about 100× more than posts are written, so pay the cost at write time — except that follower counts follow a power law (decision C).
- Cost: a 10M-follower post would be 10M writes. Acceptable for ordinary users because fan-out is async and the poster never waits; unacceptable for the tail.
- Commit: push for ordinary users, pull for the few above a follower threshold, merged and deduped at read time.
Decisions D and G in a rate limiter (P5): Redis or Postgres for the counters?
- Axes: latency ↔ durability. The limiter is on every request; but lost state means clients get a free burst.
- Context: at 100K requests/second the store must answer in under a millisecond, and rate-limit state is ephemeral — losing it means brief over-admission, not corruption.
- Cost: a Redis restart resets limits and lets clients burst for 5–10 seconds. Far cheaper than adding 10ms to every request forever. Say which way it fails (G): open, for a general API; closed, for an expensive or abuse-prone endpoint.
- Commit: Redis, with atomic check-and-decrement.
Layer 3: Concepts
Concepts are the mechanisms you reach for when an interviewer pushes past the decision: “how exactly would the fencing token work?” Don’t lead with them — lead with the decision and its cost, then go one level down when asked. A concept named without the decision it serves is name-dropping.
- Common System Design Decisions is the bridge between layer 2 and layer 3: the default answer for each recurring choice, and the trigger that should make you switch.
- Each concept reference on the site is one mechanism. The pattern cards above link the ones each pattern leans on.
How to apply it: the interview, phase by phase
The interview’s structure doesn’t change: clarify → requirements and estimation → high level → deep dive → wrap-up. The four layers aren’t another process; they tell you what to look for and what to do in each phase.
| Phase | What you do |
|---|---|
| 1 · Clarify | Scan the prompt for pattern signals; ask the question that decides the architecture (“what shape is the data?”, “what’s the source of truth?”, “what does the distribution look like?“) |
| 2 · Requirements & estimation | Estimate first (Capacity Estimation); use the numbers to say where the bottleneck is — this is the context you’ll cite in step 2 of every tradeoff |
| 3 · High level | Your first sentence names the paths: “I see N paths” — writes, reads, async work, connections — each matched to a pattern, with the hardest as the main line. Then draw them on layer-0 blocks, and use F and G to wire the seams (what’s the truth, how events flow, how failures retry) |
| 4 · Deep dive | Walk the main pattern’s dominant decisions one by one, each argued with the four steps; give each secondary pattern a sentence or two on the constraint it adds. Follow-ups land here |
| 5 · Wrap-up | Failure modes, what you skipped and why, operations (monitoring, alerting, rollout) |
Note
Interview signal: “List the paths, match the patterns” is not a separate step you announce. Nobody says “I will now match patterns.” You say the paths in the first sentence of the high-level design, and you start drawing.
Worked example 1: A satellite fleet manager (in detail)
Prompt (hypothetical): design a system that manages a large fleet of satellites (or satellite user terminals). Devices report telemetry; operators send commands and firmware; a satellite can only talk to a ground station during a pass window; the system monitors device health and alerts.
Nothing on this site is “a satellite system.” That’s the point.
High level, opening: list the paths, match the patterns
| Path | Pattern | Why |
|---|---|---|
| Operator sets desired state (mode, parameters, firmware version) → wait for a window → device converges | P10 Control plane (main line) | Desired state is the truth; devices can be offline for a long time |
| Firmware distribution and staged upgrades | P9 + P10 + P7 | The firmware image is a large object; the rollout is a control plane; each device’s upgrade is a job |
| Telemetry reports → time series + each device’s latest state | P4 + P3 | A firehose of writes, aggregated, and derived into a “current device state” view |
| Health detection and alerting | P4 | Rules / thresholds over the aggregates |
| Allocating ground-station antenna time windows | P5 + P7 | Antennas are scarce; windows are time-scheduled tasks |
High level: draw on the blocks, wire the seams
- Desired state lives in a small, strongly consistent store, with a version bump on every change (F).
- Before each window, a planner computes the command batch for that window from the diff between desired and reported state (A: the work happens outside the window).
- During the window, the ground station transmits the batch; the device executes and reports its new actual state and the sequence number of the last command it ran.
- Telemetry flows into a log, is aggregated by the stream and written to a time-series store, and also updates each device’s reported-state view (F: reported state is derived).
Deep dive: the main line (P10’s dominant F and G, plus B and E)
- B · Partitioning & ownership. Partition by device; each device’s command queue has exactly one owner, so two schedulers can never send one satellite conflicting commands.
- E · Ordering. Commands per device carry monotonically increasing sequence numbers; the device only executes numbers above its last executed one. Two operators editing one device’s desired state at once resolve with a CAS on the version — the later edit must build on the latest version.
- G · Failure and retry. Commands are naturally resent (packets drop inside a window), so they must be idempotent. A missed window rolls to the next. A device back after three days offline gets “the diff between current desired state and what it has” — not three days of replayed commands.
- G · Release safety. Firmware rolls out 1% → 10% → 50% → 100%, with a health gate between stages (error rates and reboot counts from telemetry); a tripped gate halts and rolls back. The device keeps the previous good image (A/B partitions) and falls back on its own if an upgrade fails.
- F · Static stability. If the whole control plane is down, devices keep operating on their last valid config. A management outage never makes the fleet uncontrollable.
One decision argued in full, to show the four steps landing on a new system: should the ground station push commands, or the device pull? Axes: freshness ↔ robustness to missed contact. Context: contact only happens in short, predictable windows, and devices may miss several. Cost: with declarative pull-on-contact, a change waits for the next window — minutes to hours of convergence delay. Acceptable, because the alternative (imperative push) corrupts state the first time a command is lost. Commit: declarative desired state, reconciled on every contact.
Deep dive, closing: a sentence or two per secondary pattern
- Telemetry (P4): cardinality is the capacity ceiling — estimate devices × metrics; and the alerting path itself needs monitoring.
- Antenna scheduling (P5 + P7): windows are predictable (orbits are known), so schedule them offline in advance; on conflict, prioritize (urgent commands > routine telemetry download).
Worked example 2: Ride-hailing
The same procedure on a familiar product, compressed to the opening and the decisions that matter:
| Path | Pattern |
|---|---|
| Drivers report location every few seconds → written into a geo index | P3 |
| A rider requests a ride → match nearby drivers | P2 (main line) |
| Lock the chosen driver | P5 (main line) |
| Trip → payment | P6 |
| Pricing, surge heat maps | P4 |
The deep dive goes to B (partition by geography), C (dense downtown cells are the hot spots), and E (one driver must never be held by two requests). The trap is spending the round on the map and never answering E. See the Geospatial Matching walkthrough for the P2 half in depth.
More decompositions
| Question | Paths → patterns | Main line | Key decisions |
|---|---|---|---|
| Photo sharing (Instagram-style) | Upload photo → P9; post into feeds → P3; read feed → P1; search → P2 | P3 | A (hybrid push / pull), C (celebrities pulled) |
| Ticketing | Event page → P1; search events → P2; grab a seat → P5 (TTL hold + virtual queue); checkout to payment → P6 | P5 | E (atomic seat hold), G (tiered load shedding) |
| Web crawler | URL frontier + fetch workers → P7; page storage → P9; dedup → F | P7 | B (partition by host, for politeness), F (URL and content dedup), G (retries and dead links) |
| Distributed job scheduler | Submit, fire when due, assign → P7 | P7 | E (lease + fencing so two workers never run one job), G (at-least-once + idempotency) |
| Trending topics | Post events → sliding-window top-K → P4 | P4 | C (hot topics), D (approximate counts are fine) |
| Online judge | Problem page → P1; submission → judging queue + sandboxed workers → P7; result back → P8 or polling; contest leaderboard → P4 | P7 | G (judge timeouts and retries), C (the submission spike at contest start); sandbox isolation is a layer-3 concept |
| Collaborative docs | Multi-user editing → P8; snapshots and the operation log → F | P8 | B (one owner worker per document), E (single writer orders operations), D (offline editing decides OT vs CRDT) |
| Experimentation platform | Experiment config pushed to every service → P10; assignment → P1 (deterministic hash, computed locally); metric stats → P4 | P10 + P4 | F (versioned config), D (freshness of results), G (config service down → use the last config) |
| Flight search | Scatter-gather across airlines → P2; fare cache → P1 | P2 | D (fares have short TTLs; reconfirm the price before booking), G (external timeouts → partial results) |
| Kafka / Memcached | Open a layer-0 block | The block itself | B, D, E, G — all answered inside one component |
Where it breaks
- When the question is the block. Design a consensus protocol, a storage engine, a distributed lock: there’s one component, no paths to compose, and the whole round is layer 3. Use the decisions as your checklist, but don’t force a path table.
- When a keyword misleads. “Real-time” in a dashboard prompt usually means seconds-fresh aggregates (P4), not sockets (P8). “Search” over a few thousand items may be a database index, not a retrieval funnel. Patterns are recognized from signals, then confirmed with a clarifying question — never matched on a single word.
- When you decompose too wide. Listing six paths and going shallow on all of them reads as a survey. Pick one main line, go deep on its dominant decisions, and give the rest a sentence each. If the interviewer wants a secondary path, they’ll pull you there.
- When the round is really about product or ML judgment. In ranking- quality or experimentation-design rounds, the hard part is metrics, labels, and evaluation, not paths. The framework gets you the serving architecture; it won’t pick your objective function.
- When it replaces mechanisms instead of organizing them. Saying “this is P5, decision E” without being able to walk an atomic guarded decrement is worse than not using the labels at all. The patterns tell you where to dig; layer 3 is the digging.
- The extension isn’t settled. AI system design is moving fast. Expensive compute is listed as an extension, not a pattern, on purpose: its standard moves are still shifting.
Related
- Plan: 9-Week System Design Interview Prep — the order to learn the patterns in; each week maps to one or two of them.
- Reference: Common System Design Decisions — the default answers for the recurring choices, and when to switch; the lookup table for layer 2.
- Walkthrough: Designing a News Feed — the foundation walkthrough: P3 as the main line, with decisions A and C argued in full.
- Guide: Last-Minute System Design Review Checklist — what to review in the final 24 hours; the pattern table above is the best single page to carry into it.
- Framework: An OO Design Interview Framework — the same “decompose, then decide” discipline applied to object-oriented design rounds.