Back to Learn

The System Design Playbook

Pattern recognition, like LeetCode - but for system design. Hear a signal in the requirements, reach for the right architecture.

Every entry below is a phrase you might hear an interviewer say (or that you should say to confirm requirements), paired with the canonical pattern it points to. Click any topic link to drill into the deep-dive.

Latency

How fast a single request is served - read latency, write latency, perceived speed.

When you hear

read latency under 100ms

Reach for

DB indexes + Cache the read path (e.g. Redis, cache-aside)

DB read is ~30ms; Redis ~1ms. At 90% hit rate the mean drops 10ร—.

Deep dive
When you hear

Same data fetched many times between writes

Reach for

Cache (cache-aside is the default)

Read-heavy workloads are exactly what caches were built for; load shedding matters more than latency at scale.

Deep dive
When you hear

Result can be a few seconds stale

Reach for

Cache + TTL

Stale-tolerant = caching wins

Deep dive
When you hear

Users are from different regions

Reach for

CDN for static assets + regional read replicas

Cross-continent RTT is ~150ms; edge POPs cut that to ~20ms.

Deep dive
When you hear

Real-time push to clients (chat, live cursors)

Reach for

WebSockets

Bidirectional, low overhead after handshake. SSE if it's one-way; polling is wasteful.

Deep dive
When you hear

Mobile screen needs data from 5 services

Reach for

Backend-for-Frontend (BFF) aggregation

5 mobile RTTs over cell network = 750ms+. One server-side fan-out collapses to 1 RTT.

Deep dive
When you hear

Free-form text search has to feel instant

Reach for

Inverted index (Elasticsearch, or Postgres full-text search)

`LIKE '%foo%'` is a full table scan; an inverted index is sub-millisecond.

Deep dive

Async / Not-Urgent

Work that doesn't need to complete before responding to the user.

When you hear

Send confirmation email after checkout

Reach for

Async queue (SQS / RabbitMQ / Kafka) + worker

Don't block the checkout response on a slow downstream. Emails are best-effort, durable in the queue, retry-on-failure.

Deep dive
When you hear

Generate thumbnails / re-encode video on upload

Reach for

Trigger on upload โ†’ enqueue โ†’ worker pool

Heavy compute that can take seconds-to-minutes shouldn't hold the upload connection open.

Deep dive
When you hear

Service A places an order; B, C, D should react

Reach for

Event-driven architecture (use pub/sub (e.g. Kafka) to publish OrderPlaced, consumers react)

Decouples producer from consumers; A doesn't need to know who listens.

Deep dive
When you hear

Spiky traffic - must not drop requests during a spike

Reach for

Queue as a buffer + workers consume at fixed rate

Queue absorbs the spike; workers smooth processing and apply backpressure.

Deep dive
When you hear

Service writes to DB AND must publish an event

Reach for

Outbox pattern (write business row + outbox row in one transaction) or CDC (Change Data Capture)

Dual-writes (DB + Kafka in app code) drift on partial failure. Outbox guarantees both committed atomically.

Deep dive
When you hear

Multi-step workflow across services that may need rollback

Reach for

Saga pattern (sequence of local txns + compensations)

Distributed transactions (2PC) block under coordinator failure. Sagas trade atomicity for liveness.

Deep dive

Consistency

Whether reads see writes immediately, eventually, or somewhere in between.

When you hear

Money / inventory / safety-critical writes

Reach for

Strong consistency + DB transactions + locks + idempotency

Bank balances, last-seat-on-flight, payment idempotency - no room for "almost atomic."

Deep dive
When you hear

User edits profile, reloads, must see the new value

Reach for

Read-your-writes (sticky to primary, or version stamps)

Read replica lag breaks the user's mental model. Stick that user's reads to the primary for N seconds after a write.

Deep dive
When you hear

Recommendations can be a few seconds stale

Reach for

Eventual consistency (read replicas, async events)

Pick consistency per operation. Strong consistency everywhere is expensive and unnecessary.

Deep dive
When you hear

What happens during a network partition?

Reach for

Decide CP vs AP per workload

Banking โ†’ CP (reject writes during partition). Social feed โ†’ AP (accept, reconcile later).

Deep dive
When you hear

Two users hit Buy on the last seat at the same time

Reach for

Row-level lock (`SELECT FOR UPDATE`) or optimistic locking (`UPDATE ... WHERE qty > 0 AND version = $oldVersion`)

Race conditions on shared state need either a lock or an atomic compare-and-set.

Deep dive
When you hear

Client retries on timeout - must not double-charge

Reach for

Idempotency key on the request

Server stores key + cached response; retries with the same key return the cached result.

Deep dive

Scale & Throughput

Handling more users, more requests, more data.

When you hear

Single Postgres can't take 200K QPS

Reach for

Tune queries โ†’ cache โ†’ read replicas โ†’ shard (in that order)

Most "DB is overloaded" is a missing index. Sharding is a major complexity jump - earn it.

Deep dive
When you hear

Write-heavy workload at petabyte scale (activity feeds, IoT, logs)

Reach for

Wide-column store with LSM-tree (Cassandra)

LSM appends are sequential and 10โ€“100ร— faster than B-tree updates for sustained ingest.

Deep dive
When you hear

Service is at 80% CPU on a single instance

Reach for

Scale horizontally (LB + stateless service + shared state in Redis)

Vertical hits a ceiling and is a SPoF. Stateless + LB scales linearly.

Deep dive
When you hear

Adding a cache node remaps almost all keys

Reach for

Consistent hashing (with virtual nodes)

`hash % N` shifts ~80% on Nโ†’N+1; consistent hashing moves only ~K/N.

Deep dive
When you hear

Public API; one user is hammering an expensive endpoint

Reach for

Rate limiting (token bucket, distributed via Redis)

Protects backend; gives fair-share between tenants; predictable failure mode (429 + Retry-After).

Deep dive
When you hear

Twitter timelines for 200M DAU including celebrities with 100M followers

Reach for

Hybrid fan-out (push for normal users, pull for celebrities)

Push-only writes 100M timeline entries per celebrity tweet. Pull-only is too slow for users following thousands.

Deep dive

Durability & Reliability

Don't lose data; survive failures.

When you hear

99.99% uptime target

Reach for

Multi-AZ deployment + auto-failover + health checks

99.9 = 8.7 hrs/year, 99.99 = 53 min/year. Eliminate single points of failure first.

Deep dive
When you hear

Service A fails - must not cascade into a B/C/D outage

Reach for

Circuit breaker + timeout + bulkhead

Without it, slow downstream queues up requests in A and starves the whole system.

Deep dive
When you hear

Worker crashed mid-message - message must not be lost

Reach for

At-least-once queue (Kafka, SQS) + idempotent consumers

Visibility timeout returns the message; consumer dedupes by event ID.

Deep dive
When you hear

Need a complete audit trail of every change

Reach for

Event sourcing or CDC

Append-only event log = full history; current state derived by replay.

Deep dive
When you hear

Writes must be durable across regions

Reach for

Synchronous cross-region replication

Async loses recent writes on regional failure. Sync is slower but lossless - pick based on RPO.

Deep dive

Access Pattern

Recognize the data-access shape; pick the index/store that fits it.

When you hear

Find drivers/restaurants/users near point X

Reach for

Geospatial index (Redis GEO for in-memory, PostGIS for relational)

Naive distance scan is a full-table scan; geohash/quadtree/R-tree make it O(log n).

Deep dive
When you hear

Free-form text search with relevance / fuzzy / autocomplete

Reach for

Inverted index (Elasticsearch, or Postgres full-text search at <100GB)

Relational `LIKE` doesn't scale and has no relevance scoring or fuzzy matching.

Deep dive
When you hear

Infinite-scroll feed; page 1000 takes 8 seconds

Reach for

Cursor (keyset) pagination

Offset scans+discards N rows. Cursor is O(1) at any depth and stable under inserts.

Deep dive
When you hear

Structured data with relationships - orders, payments, users

Reach for

Relational DB (Postgres)

Joins, ACID, ad-hoc queries. Holds up to ~10TB and ~100K QPS. Don't reach for NoSQL by reflex.

Deep dive
When you hear

Schema-flexible documents with nested fields

Reach for

Document store (MongoDB, DynamoDB document mode)

When the shape varies meaningfully per item and you don't need cross-document joins.

Deep dive
When you hear

Sub-millisecond key lookups, sessions, leaderboards

Reach for

Key-value store (Redis, DynamoDB KV)

Opaque-blob-by-key with O(1) access; Redis adds rich data structures (sets, sorted sets, streams).

Deep dive

Files & Blobs

Photos, videos, attachments, large user uploads.

When you hear

Users upload profile photos / videos / attachments

Reach for

Object storage (S3) + metadata in DB

Never put bytes in Postgres BLOBs - bloats the DB, slows backups, wastes cache.

Deep dive
When you hear

10K concurrent uploads of 50MB files saturating our app servers

Reach for

Pre-signed URLs - browser PUTs directly to S3

Your server only generates the signed URL; bytes never touch it.

Deep dive
When you hear

Static images and JS bundles slow for global users

Reach for

CDN (Cloudflare / CloudFront / Fastly)

Edge POPs serve cached assets close to the user; cuts latency 5โ€“10ร—.

Deep dive

API & Communication

Pick the right contract for who's calling.

When you hear

Public API for third-party developers

Reach for

REST + JSON (URL versioning, idempotency keys, cursor pagination)

Universal tooling, browser-friendly, HTTP caching, every language has an HTTP client.

Deep dive
When you hear

Service-to-service in a polyglot stack (Go/Java/Python)

Reach for

gRPC + protobuf

Schema-first, ~5โ€“10ร— smaller wire size than JSON, strongly typed stubs in every language.

Deep dive
When you hear

Mobile/web client needs to shape its own data

Reach for

GraphQL (single endpoint, typed schema, client-picked fields)

Solves over/under-fetching; pair with DataLoader to avoid the N+1 trap.

Deep dive
When you hear

Server-pushed notifications (one-way, browser-friendly)

Reach for

Server-Sent Events (SSE)

Simpler than WebSockets, runs over plain HTTP, browsers auto-reconnect.

Deep dive

Observability & Debugging

When customers say "the app is slow," how do you find out why?

When you hear

Customers say it's slow; one request crosses 6 services

Reach for

Distributed tracing (OpenTelemetry โ†’ Jaeger / Datadog)

Logs don't correlate across services. A trace shows the waterfall and exposes the long-pole span.

Deep dive
When you hear

On-call gets paged 5ร—/day on CPU > 80% but nothing's actually broken

Reach for

Alert on user-facing symptoms (error rate, p99 latency, SLO burn) - not resources

CPU at 80% is fine if latency is OK. Alert on "are users in pain right now?"

Deep dive

Auth

Who is the caller, and what are they allowed to do?

When you hear

Mobile app + backend API; users stay logged in for hours

Reach for

JWT access token (15 min) + refresh token (30 days, rotated)

Stateless API; short access TTL limits blast radius if leaked; refresh-rotation detects theft.

Deep dive
When you hear

Sign in with Google / Apple / GitHub

Reach for

OAuth 2.0 Authorization Code + PKCE

Industry standard; PKCE protects against code interception (essential for public clients).

Deep dive
When you hear

Service-to-service auth in a service mesh

Reach for

mTLS (handled by Istio / Linkerd)

Zero-trust internal traffic; cert rotation automated by the mesh.

Deep dive

Capacity & Sizing

Sanity-check that your design fits the scale before drawing boxes.

When you hear

How many QPS will this handle?

Reach for

`avg QPS = DAU ร— actions/day / 86,400`; peak โ‰ˆ 2โ€“3ร—

Compute it out loud before designing. If it's 100 QPS, single Postgres. If it's 100K QPS, sharding.

Deep dive
When you hear

How much storage for X users / Y events / Z retention?

Reach for

`writes/day ร— bytes/record ร— replication ร— retention`, +30% overhead

Rounds drive design choices: 4TB = single Postgres, 400TB = shard or NoSQL.

Deep dive