Guide contents

Lesson 2 of 129

System Design Interview Framework

A framework for a system design interview is a fixed order of steps that keeps a 45 to 60 minute discussion structured. The order used here has four steps: requirements, estimation, high-level design, and deep dive. Each step produces an artifact that the next step depends on, so skipping a step usually causes rework later.

flowchart LR
    R["1. Requirements"] --> E["2. Estimation"]
    E --> H["3. High-level design"]
    H --> D["4. Deep dive"]
    D -. "new constraint" .-> H
    H -. "scope unclear" .-> R

Time budget

For a 45 minute round:

Step Minutes Output
1. Requirements 5 Functional list, non-functional targets, non-goals
2. Estimation 3 to 5 QPS, storage, bandwidth, read/write ratio
3. High-level design 10 to 15 API, data model, architecture diagram
4. Deep dive 15 to 20 Detailed design of 2 to 3 hard components
Wrap-up 3 to 5 Bottlenecks, failures, extensions

For a 60 minute round, extend the deep dive. The proportions matter more than the exact numbers: design and deep dive receive most of the time, and requirements never take more than a few minutes.

Step 1: Requirements

Goal: fix what is being built before designing it.

  • Functional requirements. What the system does, expressed as user-visible operations. Examples: "a user can create a short link", "a user can open a short link and be redirected".
  • Non-functional requirements. Quality targets: latency, availability, consistency, durability, scale, security. See functional and non-functional requirements.
  • Scope control. Choose the two to four features that matter most, and state which are out of scope.
  • Scale hints. Ask for daily active users, read/write ratio, data retention, and geographic distribution.

Write the agreed list where it stays visible. It is referenced again during estimation and when trade-offs are argued.

Step 2: Estimation

Goal: determine the order of magnitude of load and data, because that decides whether a single database suffices, whether caching is needed, and whether storage must be partitioned.

Compute in this order:

  1. Requests per day, converted to average requests per second (divide by 86,400, the number of seconds in a day, or by 10^5 for quick mental arithmetic).
  2. Peak QPS, commonly assumed to be 2 to 10 times the average, with the multiplier stated.
  3. Read QPS and write QPS from the read/write ratio.
  4. Storage per record times records per day times retention period.
  5. Bandwidth: QPS times payload size, for ingress and egress.
  6. Memory for a cache, if the design uses one: for example the hot 20 percent of daily data.

The full method and reference numbers are in back-of-envelope estimation. The result should be a few numbers that change the design, not a complete table.

Step 3: High-level design

Goal: a working end-to-end design that satisfies the functional requirements, at box-and-arrow level.

  1. API. List the main endpoints or RPCs with parameters and return values. This confirms the functional scope.
  2. Data model. Identify entities, key fields, relationships, and access patterns. Choose a storage type and give the reason (for example, relational for transactions, key-value for lookup by key at high volume).
  3. Architecture diagram. Clients, DNS or CDN, load balancer, stateless services, cache, database, queues, and background workers, as needed.
  4. Data flow. Trace the write path and the read path through the diagram for the main use cases.

Keep components generic at this step. Detailed choices such as partitioning schemes come in the deep dive.

Step 3 to 4 transition

Before the deep dive, state which two or three components are hardest or most critical, and ask the interviewer whether they want to go there or elsewhere. The interviewer often has a preference, and this check avoids spending time on the wrong area.

Step 4: Deep dive

Goal: show depth on the parts of the design where the problem is actually hard.

For each chosen component:

  • State the sub-problem and the constraint that makes it hard.
  • Present at least two alternatives.
  • Compare them on the requirements and the estimates.
  • Pick one and state what is given up.
  • Describe failure behavior: what happens when a node, network link, or dependency fails.

Typical deep-dive topics include partitioning and hot keys, cache consistency, ordering guarantees, fan-out strategy, idempotency and retries, and unique ID generation.

Wrap-up

Use the last minutes to identify remaining risks: the single points of failure, the bottleneck at 10 times the estimated load, monitoring and alerting, and extensions such as multi-region deployment. Mentioning these unprompted shows the design has been reviewed critically.

Worked mini example: URL shortener

Requirements. Functional: create a short URL from a long URL; redirect a short URL to the long URL. Non-functional: redirect latency low (tens of milliseconds), high availability for redirects, links should not collide. Out of scope: analytics, custom aliases.

Estimation. Assume 100 million new URLs per day and a read/write ratio of 10:1.

  • Writes: 100,000,000 / 86,400, about 1,160 writes per second.
  • Reads: about 11,600 redirects per second.
  • Storage: 500 bytes per record times 100,000,000 per day times 365 days times 5 years is about 91 TB, so data must be partitioned or stored in a scalable store.
  • Short code length: 7 characters from a 62-character alphabet give 62^7, about 3.5 trillion codes, which exceeds 182 billion URLs created in five years.

High-level design.

flowchart LR
    C["Client"] --> LB["Load balancer"]
    LB --> S["Stateless URL service"]
    S --> CA[("Cache")]
    S --> DB[("Key-value store: code to URL")]
    S --> ID["ID generator"]
  • API: POST /urls {long_url} returns {short_code}; GET /{short_code} returns an HTTP redirect.
  • Data model: code (primary key), long_url, created_at. Access is always by code, so a key-value store fits.
  • Read path: check the cache, then the store on a miss, then populate the cache.
  • Write path: obtain a unique ID, encode it in base 62, store the mapping.

Deep dive. Code generation (counter with base-62 encoding versus hashing with collision checks), cache sizing (cache only the hot subset of links, since 11,600 reads per second concentrate on a small fraction of codes), and choosing between 301 and 302 redirects (a 301 is permanent and can be cached by browsers, which reduces load but hides repeat clicks from the service, so click analytics would need a 302).

Wrap-up. Single point of failure in the ID generator, hot links, expiry of old links.

Interview questions

  • Why estimate before drawing the design? The estimates decide structural questions: one database or many partitions, whether a cache is required, whether a queue is needed to absorb bursts. A design drawn first cannot be checked against load.
  • What if the interviewer changes a requirement mid-way? Return to the affected step, update the requirements and estimates, and adjust only the components that change. The framework is iterative, as the back-edges in the flow show.
  • How is depth chosen in the deep dive? Pick components where the load estimate or a requirement makes the problem hard, and confirm the choice with the interviewer.
  • What is the first thing to produce in the high-level design? The API, because it fixes the functional scope, and then the data model, because access patterns drive storage choice.