System Design — the distributed-systems interview, from first principles
The classic backend system-design interview: design a URL shortener, a news feed, a chat service, a rate limiter. The questions look different but they all reduce to the same handful of levers — latency, throughput, consistency, fault tolerance, and scale — and the same handful of patterns for moving them. This track derives those patterns from one starting fact, so you can re-derive any design in the room instead of pattern-matching to a memorised diagram.
The one idea this whole track turns on
Start from the machine that needs no distributed systems at all: one server with one database. It is simple, it is strongly consistent (one copy of the truth), and an in-process call is nanoseconds. It has exactly two problems, and every technique in this track exists to solve one of them:
- It can't scale. One box has a finite CPU, finite RAM, finite disk, and a finite network card. When load or data outgrows it, you must spread across many boxes.
- It will fail. One box is a single point of failure — a disk dies, a kernel panics, a datacenter loses power — and when it's gone, you're at zero.
So you add more machines. The instant you do, you have a distributed system, and you have bought three new problems you did not have before: the machines must coordinate (agree on who does what and what's true), they are separated by a network that is slow and unreliable (the speed of light is a hard floor; packets drop), and their copies of state can disagree (consistency). The famous CAP theorem is just the formal statement that you cannot wish the network away.
How the track is structured
Strict linear. Each lesson assumes only the ones before it. We start with the measuring stick (what are we even optimising?), pin down the system's contract and its data, scale the easy tier (stateless), then spend the bulk of the track on the genuinely hard part — scaling state — before assembling everything into performance, reliability, an architecture, and a full design.
| Stage | Lessons | What you can do after |
|---|---|---|
| The measuring stick | 01–02: the method & napkin math, latency / throughput / queueing | Drive a design from requirements → estimates → bottleneck. Back-of-envelope QPS, storage, and bandwidth. Explain why P99 ≫ mean and why a queue at 80% load is fine but at 99% explodes. |
| The contract & the data | 03–04: API design, data modeling & storage engines | Turn a prompt into the 3–5 endpoints that matter (REST / gRPC / GraphQL, idempotent writes, pagination, versioning) and a data model driven by access patterns — and know why a B-tree, an LSM-tree, and an index behave the way they do, because the rest of the track assumes it. |
| Scaling the stateless tier | 05–06: horizontal scaling & load balancing, caching | Scale the cheap part. Choose an LB strategy, keep replicas stateless, and use a cache as the read-path lever — without getting bitten by stampedes and stale data. |
| Scaling state — the hard part | 07–10: partitioning, replication, consistency & CAP, consensus | Shard data with consistent hashing, replicate it for durability and reads, reason precisely about which consistency model you're offering, and use consensus where you genuinely need agreement (and avoid it where you don't). |
| Decoupling & reliability | 11–13: async messaging, distributed transactions, fault tolerance | Break the synchronous critical path with queues, get correctness across services without 2PC (sagas, outbox, idempotency), and make the system degrade-never-fail with redundancy, circuit breakers, and a fallback ladder. |
| Performance & operations | 14–16: optimisation playbook, rate limiting & the API edge, observability | Make it fast on purpose — profile, then attack the dominant term (Amdahl) — protect the front door with a rate limiter and gateway, and run it in production with SLOs, error budgets, and the three pillars of telemetry. |
| Recognise & synthesise | 17–19: system architecture, archetypes, capstone | Choose an architecture (monolith vs services, sync vs event-driven) and defend the boundaries, classify any prompt into one of the recurring system shapes, then walk a full design end-to-end under interview constraints — reaching for each pattern by name and defending the trade. |
What an interviewer is actually testing
| Skill | Strong | Weak |
|---|---|---|
| Drive from requirements, not buzzwords | Asks "read:write ratio? consistency requirement? scale?" first, then estimates QPS and storage, and lets those numbers pick the components. | Opens with "I'll use Kafka, Cassandra, and Redis" before knowing the load or the consistency need. |
| Name the trade, not just the pattern | "I'll shard by user_id — it co-locates a user's data so the timeline read is one shard, but it makes cross-user queries scatter-gather, and a celebrity is a hot shard." | "I'll add a cache / add a queue / shard it" with no statement of what it costs. |
| Estimate with numbers | "1M DAU × 50 reads/day ≈ 580 req/s average, ~5× peak ≈ 3k req/s; each row ~1 KB, 100 GB/yr — fits on one replicated Postgres, no sharding yet." | "It needs to be web-scale" with no figure, so over-engineers for traffic that doesn't exist. |
| Reason about failure | "What happens when this dependency is down, this region is gone, this message is delivered twice?" — and has an answer (degrade, failover, idempotency key) for each. | Designs only the happy path; treats the network as reliable and machines as immortal. |
The lessons
What this track does NOT cover
Out of scope on purpose — they live in other tracks:
- ML-specific serving & training systems (inference replicas, KV cache, distributed training topologies). See ml_system_design.
- Recommender / ads serving (candidate generation, ranking, the recsys reliability layer). See search_ads_recsys.
- GPU kernels & low-level performance. See GPU Kernels for ML Engineers (CUDA interview coding in Part V) and Triton (Part VI).
- Data-structures & algorithms coding. See python_coding.
This is the substrate underneath all of them. The recsys high-availability lesson, the ML serving lessons, and the inference-at-scale lessons all assume the partitioning, replication, consistency, and fault-tolerance vocabulary built here.
How to use this
- Linearly the first time. Lessons 01–02 are the measuring stick; 03–04 fix the API contract and the data model the rest of the track leans on; lessons 07–10 (scaling state) are the load-bearing core. Skipping them makes the consistency and consensus reasoning feel like memorisation rather than derivation.
- Re-derive the trade on paper. For each pattern, write the one sentence: "this buys ___, it costs ___." If you can't, you don't yet own it.
- Touch the widget. Each lesson has an interactive calculator — queueing latency, quorum overlap, availability nines, cache hit-rate economics, B-tree vs LSM amplification, Amdahl's ceiling. They turn an abstract trade into a number you can feel.
- Read the "interview prompts" box. Those are the questions you'll actually be asked. The parenthetical answer shows the depth that distinguishes a hire from a strong-hire.