Practical Design Problems

How to Run a Practical Design Interview

Requirements, API, data model, main algorithm, scale and failure, trade-offs. A frame you can repeat for every design question that follows.

Lesson 0010 min read#method#interview

On this page

  1. Words used in this lesson
  2. The six-step frame
  3. Step 1: Clarify requirements
  4. Step 2: Estimate scale quickly
  5. Step 3: Define the API
  6. Step 4: Model the data and its access patterns
  7. Step 5: The core design
  8. Step 6: Scale, fail and trade off
  9. Common mistakes
  10. Interview questions
  11. Key takeaways
  12. What's next

In one line: a design interview is graded on how you think, not on whether you can copy a famous architecture. Follow the same six steps every time: clarify, estimate, define the API, model the data, build the core algorithm, then test it against scale and failure. Say your trade-offs out loud.

The other series in this track teach you the separate pieces. This series teaches you to put them together under time pressure into a small design you can defend. Examples are a URL shortener, a rate limiter, pagination, an upload pipeline and notifications. These are practical design problems. They have more detail than a boxes-and-arrows whiteboard drawing, and they are closer to what you would really build.

The big-picture version of this skill (load balancers, sharding, CAP) is in the System Design series. Here we go one level lower: IDs, collisions, headers, indexes and failure modes.

Words used in this lesson

Here are the main terms in plain words. Each one is explained again where it first matters.

  • API (Application Programming Interface) is a set of rules that lets one program ask another program to do something. For example, a phone app asks a server: "give me this user's orders".
  • Endpoint is one address of an API, such as POST /v1/links. Each endpoint does one job.
  • HTTP status code is a three-digit number in a server's answer that says what happened. 200 means OK, 404 means not found, 429 means too many requests.
  • Database is a program that stores data on disk and finds it again fast. PostgreSQL is a popular database that stores data in tables.
  • Index is an extra sorted list that helps a database find rows fast, like the index at the back of a book.
  • Primary key is the column (or columns) whose value is different for every row, so it identifies one row.
  • Cache is a small, fast store that keeps answers you already looked up, so you do not ask the slow database again. Redis is a popular cache. It keeps data in memory.
  • Replica is an extra copy of a database that answers reads. Sharding means splitting the data over several databases, so each one holds only a part.
  • Queue is a list of jobs where the first job added is the first one taken out. A program adds work to it, and another program does the work later.
  • Latency is how long one request takes. Throughput is how many requests the system handles each second. They are not the same: a system can be fast for one user but still too small for many users.

The six-step frame

TEXT
1. Clarify      What exactly are we building? Who uses it? What is out of scope?2. Estimate     How big? Requests per second, data per day, read:write ratio.3. API          What do clients call? Request, response, status codes, errors.4. Data model   What do we store, and how is it accessed? Keys and indexes.5. Core design  The central algorithm or component, with alternatives.6. Scale & fail What breaks at 10x? What if a dependency is down? Trade-offs.

Plan a rough time budget for a 45-minute round:

  • 5 minutes to clarify and estimate.
  • 10 minutes for the API and data model.
  • 15 minutes for the core design.
  • 10 minutes for scaling and failure.
  • 5 minutes to wrap up and ask questions.

Interviewers often want you to lead the talk through these steps.

Step 1: Clarify requirements

Never start drawing right away. Ask questions. Write the answers where the interviewer can see them.

Functional requirements (what the system does):

  • What are the core actions? ("Create a short link; follow a short link.")
  • Who are the users? Anonymous or logged in? One user or many tenants (separate customer groups)?
  • What is clearly out of scope? Say it out loud: "I will not cover billing or an admin UI."
  • Are there special features? Custom aliases, expiry, analytics, bulk operations?

Non-functional requirements (how well it does its job):

DimensionQuestions to ask
ScaleHow many users, requests per second, objects? How fast will it grow?
LatencyWhat is acceptable at p95/p99? (p95 is the time that 95 of every 100 requests beat. The slowest 5 take longer. p99 is the same idea for 99 of 100.) A redirect should take tens of ms. A report can take seconds
AvailabilityThe share of time the system works. What happens if it is down? Do we need 99.9% uptime (about 8.8 hours of downtime a year) or 99.99% (about 53 minutes a year)?
ConsistencyMust everyone see the latest write at once? Or is eventual consistency fine (everyone sees it after a short delay)?
DurabilitySaved data stays saved, even after a crash. Can we lose any data? (Payments: never. View counts: a few, maybe)
Read/write ratioA read-heavy design uses caches and replicas (extra copies of the database). A write-heavy design uses queues and sharding (splitting data across servers)
Security & abuseWho might misuse it? What must stay private?
Cost and teamIs this a startup with two engineers or a large platform? The right answer changes

Before you move on, say the requirements again in two lines. For example: "So: logged-in users create links, anyone can follow them, 100 million new links a month, 100 reads for each write, redirects under 50 ms, 99.99% availability."

Step 2: Estimate scale quickly

Back-of-the-envelope maths does not need to be exact. Its purpose is to find the right order of magnitude (do we need one server or a cluster?). It also shows that you can reason with numbers.

Numbers worth memorising

FactApproximation
Seconds in a day86,400 ≈ 10⁵
Seconds in a month / year≈ 2.5 million / ≈ 30 million
1 million requests per day≈ 12 requests per second (1,000,000 / 86,400)
100 million per day≈ 1,200 per second
Peak trafficAverage × 2 to 10 (use 3 to 5 if nobody tells you)
1 KB, 1 MB, 1 GB, 1 TB10³, 10⁶, 10⁹, 10¹² bytes
1 million rows × 1 KB≈ 1 GB
1 billion rows × 1 KB≈ 1 TB

Rough latencies: a memory read takes about 100 ns. A Redis round trip inside a data centre takes about 0.5 ms. A random SSD read takes about 100 µs. An indexed database query takes a few ms. A round trip between regions takes about 100 ms or more.

A worked estimate

"100 million new short links per month, reads are 100 times writes, keep links for 5 years."

TEXT
Writes:   100M / month ÷ 2.5M s/month        ≈ 40 writes per second   (peak ~200)Reads:    40 × 100                            ≈ 4,000 reads per second  (peak ~20,000)Storage:  100M × 12 months × 5 years = 6 billion links          × ~500 bytes per row               ≈ 3 TBCache:    80/20 rule (a rough pattern: about 20% of the items get about 80% of the reads).          Reads per day: 4,000 × 86,400 s     ≈ 350 million          Say about 100M different links are read in one day.          Cache the hottest 20%: 20M entries × 500 B ≈ 10 GB → fits in one Redis node's memoryBandwidth: 20,000 reads/s × 500 B            ≈ 10 MB/s  (trivial)

Now you can say the conclusions: "Writes are small, and reads are the problem. A cache removes most of the database load. 3 TB fits easily on a few database nodes." Interviewers want to hear exactly this kind of sentence.

Step 3: Define the API

Describe the contract (the agreed inputs and outputs) before the inner workings. This makes you concrete, and many design mistakes show up here.

  • Write down resource names, methods, request and response bodies, status codes, the error format, auth, pagination, and idempotency for creates. Idempotency means that sending the same request twice has the same effect as sending it once. See Backend, Lesson 02.
  • Note anything that affects the design. For example: "The redirect endpoint is public and extremely busy. The create endpoint needs login and has a rate limit."
HTTP
POST /v1/links                      → 201 Created, Location: /v1/links/abc123Content-Type: application/json{ "url": "https://example.com/very/long?x=1", "alias": "launch", "expiresAt": "2027-01-01T00:00:00Z" }GET  /abc123                        → 302 Found, Location: https://example.com/very/long?x=1GET  /v1/links/abc123/stats         → 200 { "clicks": 1204, "byDay": [...] }

Step 4: Model the data and its access patterns

An access pattern is how the data is read and written. Start there. Then choose the store and the keys.

  1. List the entities and how they relate (User, Link, ClickEvent).

  2. List the queries and how often they run. ("Look up by code: 20,000/s." "List a user's links: 1/s.")

  3. Choose the primary key and the indexes that serve the busiest queries.

  4. Choose the store. Say why:

    • Relational (PostgreSQL) is good for relationships, transactions and flexible queries.
    • Key-value or wide-column stores (DynamoDB, Cassandra) are good for huge numbers of simple lookups. A key-value store works like a big dictionary: you give a key and get back a value.
    • Redis is good for hot, small, short-lived data.
    • Object storage (such as Amazon S3) is good for large files (blobs, which are big chunks of bytes such as images or videos).
    • A search engine (such as Elasticsearch) is good for text search, where results are ranked by how well they match.

    Example: "PostgreSQL first. The access pattern is key-value, so we can shard or move to DynamoDB if volume demands."

SQL
CREATE TABLE links (  code        text PRIMARY KEY,              -- the hot lookup key  long_url    text NOT NULL,  user_id     uuid NOT NULL,  created_at  timestamptz NOT NULL DEFAULT now(),  expires_at  timestamptz);CREATE INDEX links_user_created ON links (user_id, created_at DESC);  -- "my links"

Step 5: The core design

Every problem has one or two hard parts. Examples are ID generation, the rate-limit algorithm, or the pagination cursor. Spend most of your time there:

  • Say what problem the hard part solves.
  • Show two or three alternatives and how each one works.
  • Compare them on correctness, complexity, cost and what happens when things fail.
  • Pick one and explain why. Also say when you would pick a different one.

Step 6: Scale, fail and trade off

Go through the system. At each part, ask "what breaks?":

  • One instance dies. Is there a single point of failure (one part that stops everything if it fails)? Add copies, and add health checks (small regular tests that tell a load balancer which copies still work).
  • A dependency is slow or down. Think about timeouts, retries with backoff (waiting longer after each try), circuit breakers (stop calling a broken service for a while), and fallbacks. Decide: fail open or fail closed? Fail open means the system keeps working without the check. Fail closed means it blocks requests when the check is not available.
  • Traffic grows 10 times. Where is the bottleneck: the database, the cache, or the network? Scale reads with replicas and caches. Scale writes with sharding or queues.
  • Hot keys. A hot key is one item that gets far more requests than the rest. It puts all the load on one shard or cache node.
  • Bad data and abuse. Use validation, rate limits, and checks for harmful input.
  • Duplicate or out-of-order messages. Use idempotency.
  • Observability (being able to see what the system is doing). Use metrics (numbers over time; the RED set is rate, errors and duration), logs (a written record of events), traces (the path of one request through all the services) and alerts (a message sent to a person when a number looks bad).
  • Consistency trade-offs. Where is stale data acceptable?
  • Cost and operations. How hard is it to run, deploy and debug?

How to present trade-offs

Here is a sentence pattern that works well:

"Option A gives us X but costs Y. Option B gives us Z but costs W. Given [requirement], I'd choose A. If [requirement changes], I'd think again and choose B."

Common mistakes

  1. Jumping straight into boxes and technologies without clarifying or estimating.
  2. Naming tools instead of giving reasons. ("We'll use Kafka," with no reason. Kafka is a tool that moves streams of messages between programs.)
  3. Ignoring non-functional requirements, and then designing something that cannot meet them.
  4. Over-engineering for Google scale when the numbers say one PostgreSQL instance is enough. State the numbers, then choose the right size.
  5. A single point of failure that you never mention.
  6. No talk about failure. "What if Redis is down?" needs an answer.
  7. Silence. If you do not explain your thinking, the interviewer cannot grade it.
  8. Treating the first design as final. Improve it, and welcome the interviewer's new limits.

Interview questions

What do you clarify first?

First I ask about the core user actions and the scope, including what is out of scope. Then I ask about the non-functional requirements: expected scale, read/write ratio, latency targets, availability, consistency and durability needs, security and abuse worries, and any special features. I say them again in a sentence or two so we agree before I design anything.

How do you estimate scale quickly?

I change business numbers into per-second rates. For example, a million requests per day is about 12 per second. Then I apply a peak factor. I work out storage as rows times bytes times retention time. I size caches with an 80/20 rule. The goal is the order of magnitude. It tells me if one machine is enough, or if I need caching, replicas or sharding.

How do you present trade-offs?

For each important decision, I name two or three options. I say what each one gains and costs against the requirements. I choose one and give a reason. Then I say which change in requirements would make me choose differently. This shows good judgement, not a memorised answer.

What is the difference between a high-level and a practical design interview?

High-level system design covers the broad architecture of a large product: load balancers, databases, sharding and queues. A practical design interview goes deeper into one component. It covers the ID scheme, the algorithm, the exact API, the schema and indexes, the headers, and what happens on failure. It is closer to what you would really build.

How do you decide between SQL and NoSQL in a design?

I decide from the access patterns and the requirements. Relationships, transactions and flexible queries point to a relational database. Huge numbers of simple key lookups, with predictable access and a need to scale out, point to a key-value or wide-column store. I start with the simplest option that fits the numbers. I also say how I would move to something else if the numbers grow.

What do you do when you do not know something in the middle of a design?

I say so. I state the assumption I will use, and I keep going. For example: "I'm not sure how that provider rate-limits, so I'll assume X. I'll design a retry with backoff that works either way." Clear assumptions and a solid design are better than bluffing.

Scenario: the interviewer says "design a system for a billion users" and nothing else. What do you do?

I slow down and clarify. What is the product? What are the core user actions? What is the mix of reads and writes? What are the latency and availability targets? What is out of scope? Then I estimate the scale from the numbers they give me, and I say my assumptions out loud. A billion registered users is not a billion users at the same moment. So I size the system from daily active users and per-second rates before I choose any components.

Scenario: halfway through, the interviewer adds a requirement that breaks your design (for example strong consistency). How do you respond?

I welcome it and say the new requirement again. Then I find exactly which parts of the design it affects. I explain the trade-off: consistency costs latency or availability. I suggest the smallest change, such as sending those operations to the primary database, or using a transaction (a group of database steps that all succeed or all fail together) or a consensus-backed store (a store whose servers vote, so they agree on one latest value) for that data. I also say what I would keep. Changing the design calmly shows better judgement than defending the first one.

Key takeaways

  • Use the six steps: clarify, estimate, API, data model, core design, and scale and failure.
  • Numbers drive decisions. Change them to per-second rates, apply peak factors, and size storage and caches.
  • Start from access patterns to choose keys, indexes and stores.
  • Spend your depth on the hard part. Compare alternatives, choose, and explain why.
  • Always talk about failure and trade-offs, and think out loud.

What's next

Lesson 01: Design a URL Shortener. This is the classic first problem. It covers the details that make a good answer: ID generation, collisions, redirects and caching.

Published by Jainik · Last updated · How these lessons are made

Keep learning

Related lessons

Part of the study guide

Related series