Course
System Design — Complete Course
Work unit-by-unit: learn the framework, then drill the classic problems. Staff bar = architecture ownership with explicit trade-offs.
Software engineering · architecture · 5 units
Unit 1: Unit 1 — Requirements & capacity estimation
Every design starts with requirements: functional (what it does) and non-functional (scale, latency, availability, consistency, cost). Then estimate: users → DAU → requests/sec → data size → storage/bandwidth. Back-of-envelope math (2^10≈10^3, 1 req/s ≈ 86k/day, a server handles ~10k req/s) turns vague scale into concrete numbers that drive the architecture. Always state assumptions explicitly.
Teach: the estimation drill
Estimate QPS for a Twitter-like feed: 500M MAU, 50% DAU = 250M. Each user reads ~20 posts/day → 5B reads/day ≈ 58k reads/s peak (×3 spike ≈ 175k). Each post ~1KB → 5TB/day reads, ~500GB/day writes if 100M posts. These numbers tell you: reads dominate → cache + read replicas; writes are append-heavy → message queue + async fan-out. Always sanity-check units and round to powers of ten.
Exercises
- Estimate QPS for a URL shortener — 100M users, 10% DAU, each shortens 2 URLs/day and clicks 10/day. Estimate write QPS, read QPS, and storage for 10 years.
- Cache hit ratio and server count — 1M QPS reads, 90% cache hit, one cache node serves 50k QPS. How many cache nodes?
Practice problems
- Estimate a chat app's QPS + storage
- Estimate a video platform's bandwidth
- Turn requirements into numbers for a payments system
Unit 2: Unit 2 — Scaling: load balancing, caching, data partitioning
Scale vertically (bigger box) until cost/limits bite, then horizontally. Horizontal scaling needs stateless app tiers behind a load balancer, a shared cache for hot data, and a data layer that partitions. Shard by a key that matches your access pattern; replicate for read scaling and availability. Cache at every layer (CDN → app cache → DB cache) but design invalidation. The classic ladder: LB → stateless apps → cache → read replicas → sharding → queue for async.
Teach: the scaling ladder
Start single box. When it saturates: (1) add a load balancer + stateless app replicas; (2) add a cache for the hot read path; (3) add read replicas; (4) shard the database by the natural key; (5) move slow/async work to a queue. Each step has a cost and a failure mode — say them. Consistent hashing minimizes rebalancing when shards change. Cache invalidation is the hard part: TTLs are simple, write-through is consistent but slower, write-behind is fast but can lose data on crash.
Exercises
- Choose a sharding key — A messaging app stores conversations. How do you shard so reads are local?
- Cache invalidation strategy — A profile service: reads are 100x writes. How do you keep the cache consistent?
Practice problems
- Design a sharded key-value store
- Cache-aside for a read-heavy profile API
- Consistent hashing for cache nodes
Unit 3: Unit 3 — Consistency, replication & distributed systems
Distributed systems trade consistency for availability and latency. CAP: under a partition you choose consistency (CP) or availability (AP). Know the consistency models — strong, linearizable, eventual, read-your-writes — and when each is acceptable. Replication: single-leader (simple, strong-ish), multi-leader, leaderless (Dynamo). Consensus (Raft/Paxos) orders writes across replicas. Distributed transactions: 2PC (blocking) vs Saga (compensation).
Teach: CAP is about partitions, not a pick-any-two
CAP applies during a network partition: you must choose consistency (refuse stale reads, CP) or availability (serve possibly-stale data, AP). PACELC adds the normal case: Else, Latency vs Consistency. A payment ledger wants CP; a news feed wants AP. State your consistency requirement per data type — read-your-writes for profiles, eventual for likes. Consensus (Raft) gives strong ordering but costs latency; use it only where ordering truly matters.
Exercises
- CP or AP for a payment system? — A payment service must never double-spend. Under a partition, CP or AP?
- Saga for a multi-step order flow — Order = reserve inventory → charge payment → notify. A step fails mid-way. How do you stay consistent?
Practice problems
- Design a CP vs AP decision matrix
- Saga for a booking flow
- Leader election with Raft concepts
Unit 4: Unit 4 — Reliability, failure & observability
Assume components fail. Design for it: timeouts with retries + exponential backoff + jitter, circuit breakers to stop hammering a dead dependency, bulkheads to isolate failure, idempotency keys so retries are safe, and the outbox pattern so DB writes and events stay consistent. Observability (metrics, logs, traces) with SLOs and error budgets tells you when you're actually degrading. 'Let it fail loudly and recover structurally' beats silent partial failure.
Teach: retries must be idempotent
A retry without idempotency duplicates the side effect (double charge, double order). Give every mutating request an idempotency key; the server dedupes by key. Add exponential backoff + jitter so retries don't thundering-herd the recovering service, and a circuit breaker so you stop retrying a dead dependency. The outbox pattern: write the event to a DB table in the same transaction as the state change, then a relay publishes it — no lost events and no dual-write inconsistency.
Exercises
- Design idempotent payment retry — A payment call times out. Retrying might double-charge. Design the fix.
- DB write + event must be atomic — You update a row and publish an event. If the publish fails, they diverge. Fix it.
Practice problems
- Retry + circuit breaker for a flaky dependency
- Outbox for an order event
- Define SLOs + error budget for a checkout API
Unit 5: Unit 5 — Design drills (classic problems)
Drill the canonical problems so the framework is automatic: requirements → estimation → API → data model → high-level architecture → deep dives → trade-offs and failure modes. The classics: URL shortener, rate limiter, chat system, notification service, news feed, distributed cache, ID generator. For each, be ready to defend every choice with a trade-off and a failure mode.
Teach: the news-feed fan-out decision
Push (fan-out on write): when a user posts, write to each follower's inbox. Reads are O(1) but writes explode for celebrities. Pull (fan-out on read): build the feed at read time by merging followed users' recent posts — reads cost more but writes are cheap. Real systems hybridize: push for normal users, pull for high-follower accounts, with a cache of recent posts. This one decision is the heart of the interview — show you can weigh it.
Exercises
- Design a URL shortener — Shorten long URLs, redirect, and support analytics. Estimate and design.
- Design a distributed rate limiter — Limit each user to 100 req/min across many API servers.
- Design a chat system — 1:1 and group chat with presence and offline delivery.
Practice problems
- Design a notification service
- Design a distributed cache
- Design a task scheduler / robot-dispatch service