How To Talk Through a System Design Interview: A 45-Minute Framework
Quick summary
Summarize this blog with AI
A system design interview is not a silent architecture contest. The interviewer can score only the decisions you make visible. Strong candidates define the problem, propose a coherent baseline, test it against scale and failure, and explain what should change next. This 45-minute framework gives you a clock and concrete outputs.
The score is in the conversation, not the number of boxes
Most system design prompts are intentionally incomplete. “Design notifications” could mean transactional alerts, social updates, mobile push, email, or an internal event bus. Starting with a polished diagram before resolving that ambiguity is risky: you may solve the wrong problem efficiently.
Your conversation should demonstrate four things:
- Problem definition: separate must-have behavior from optional behavior.
- Coherent baseline: make APIs, data, services, and flow fit together.
- Constraint-driven judgment: connect scale, latency, consistency, cost, and reliability to choices.
- Collaboration: invite corrections, expose assumptions, and revise when needed.
Use short reasoning loops: “I’ll choose X because Y. That gives us Z, with this trade-off. Does that match the direction you want to explore?”
A 45-minute system design map
| Time | Objective | Visible output |
|---|---|---|
| 0–2 minutes | Orient and frame | A one-sentence restatement and an agenda |
| 2–7 minutes | Clarify scope | Functional requirements, exclusions, and success criteria |
| 7–10 minutes | Set constraints | Two or three estimates and the qualities they affect |
| 10–15 minutes | Define the contract | Core APIs, events, and a small data model |
| 15–22 minutes | Draw the baseline | An end-to-end request or event flow |
| 22–32 minutes | Deep dive | Detailed reasoning about the most important subsystem |
| 32–38 minutes | Stress and repair | Bottlenecks, failure modes, and mitigations |
| 38–42 minutes | Discuss evolution | Trade-offs and the next change at greater scale |
| 42–45 minutes | Close clearly | A concise recap, open risk, and interviewer questions |
Minutes 0–10: create a problem worth solving
0–2: restate the prompt and offer a route
Open by translating the prompt into an outcome, not by repeating its nouns. Then tell the interviewer how you intend to proceed.
“I’ll design a service that accepts notification requests and delivers them through the user’s allowed channels. I’d like to clarify delivery guarantees and scale, then define the interface, draw a baseline flow, and spend most of our time on fan-out and failure handling.”
2–7: clarify behavior, priorities, and exclusions
Ask questions that can change the architecture. Avoid collecting trivia. For a notification system, useful questions include:
- Which channels are required: in-app, push, SMS, or email?
- Are notifications triggered one user at a time, or do we support broadcasts to millions?
- Is delivery best-effort, at-least-once, or expected to appear exactly once to the user?
- How quickly should transactional and bulk messages arrive?
- Must user preferences, quiet hours, and unsubscribe rules be enforced?
- Do senders need delivery status or an audit history?
Convert the answers into a compact scope statement. For example: “I’ll support in-app and push, both direct and bulk sends, at-least-once internal processing with user-visible deduplication, per-user preferences, and status tracking. I’ll leave template authoring and billing out of scope.”
7–10: estimate only what changes a decision
Estimate only enough to expose design pressure. With 50 million daily active users, 20 notifications each, and a ten-times peak, the system handles roughly one billion deliveries per day, about 12,000 per second on average and 120,000 at peak. Synchronous delivery from the request path will not absorb that peak; a durable queue and independently scalable workers are justified. Broadcasts also create highly skewed fan-out.
“The average rate is manageable, but the peak and fan-out skew are the design drivers. I’ll decouple acceptance from delivery, partition queued work, and treat bulk expansion separately from direct sends.”
Minutes 10–22: define a coherent baseline
10–15: start at the boundary
Define the minimum interface before naming databases. A possible write contract is POST /v1/notifications with recipient or audience, template data, channel preference, priority, and an idempotency key. The response can return a notification ID and an accepted status. A read contract such as GET /v1/notifications/{id} exposes processing and delivery state.
Sketch only the data needed to support the flow:
- Notification: ID, sender, audience reference, payload or template reference, priority, creation time, and idempotency key.
- Delivery: notification ID, user ID, channel, state, attempt count, next-attempt time, and provider message ID.
- User preference: user ID, permitted channels, quiet hours, and category-level opt-outs.
Connect storage to access patterns: sender plus idempotency key should be unique; delivery lookup needs notification and recipient keys; retries need next-attempt ordering. Choosing those indexes and state structures connects to data structures and algorithms preparation.
15–22: narrate one path from edge to outcome
Draw a client, API gateway, notification service, durable event log or queue, audience-expansion workers, preference service, channel queues, delivery workers, external providers, and a status store. Then trace a single direct notification:
- The API authenticates and rate-limits the sender.
- The notification service validates the request and atomically records the notification or recognizes its idempotency key.
- It publishes accepted work to a durable queue and returns quickly.
- A worker resolves preferences and creates channel-specific delivery work.
- A delivery worker calls the push provider and records the outcome.
- Transient failures are retried with bounded exponential backoff; terminal failures are retained for inspection.
Be explicit about the boundary between durable state and messages. If writing the database succeeds but publishing the queue message fails, work can disappear. An outbox record written in the same transaction as the notification lets a relay publish reliably. A consumer still must be idempotent because a relay or queue can deliver more than once.
Minutes 22–38: go deep, then try to break the design
22–32: choose the deep dive instead of waiting for one
Offer two useful branches: “The two areas with the most risk are broadcast fan-out and delivery guarantees. I’ll go into fan-out unless you prefer reliability.” This shows prioritization and keeps the exchange collaborative.
For broadcast fan-out, avoid generating 50 million queue messages in the API request. Store an audience snapshot or query reference, split the audience into bounded shards, and let expansion workers produce delivery batches. Partition work by a stable recipient hash so one large audience can use many workers without sending the same shard twice. Apply per-provider rate limits at channel workers, not globally, so an email slowdown does not block in-app delivery.
Then state the delivery semantics precisely. “Exactly once” across your database, queue, and an external push provider is usually not a realistic end-to-end promise. A practical design accepts at-least-once processing, uses stable delivery IDs and idempotent consumers, passes an idempotency key to providers that support it, and deduplicates the in-app presentation layer. That is a stronger answer than merely naming Kafka or Redis.
32–38: test failure modes in order of impact
Walk through several failures and say what the user observes:
- Queue lag rises: autoscale on oldest-message age, reserve urgent capacity, and defer low-priority work.
- Preferences are unavailable: fail closed for marketing; use a documented policy for critical messages.
- A provider times out: mark the result unknown, retry with the same delivery key, and reconcile receipts.
- A region fails: route new accepts elsewhere and recover replicated or durably stored queued work.
- A hot tenant floods workers: enforce tenant quotas and fair scheduling.
Monitor acceptance and delivery latency, success and retry rates, oldest-message age, dead-letter volume, and cost per delivery. Alert on user impact, not raw CPU alone.
Minutes 38–45: show judgment and close the loop
38–42: explain what you deliberately did not build
A mature design has an evolution path. You might begin with one region, a relational store for notification metadata, and a managed queue. At higher volume, shard delivery state by recipient or notification ID, separate bulk from transactional capacity, and add regional provider routing. Say what evidence would trigger each step.
“I would not introduce multi-region active-active writes on day one. I’d first measure whether the recovery objective or regional latency requires that complexity. The outbox and idempotent consumers give us a cleaner path to add regions later.”
42–45: recap in sixty seconds
End before the interviewer has to stop you. Summarize the requirements, the core path, the main reliability decision, and one unresolved risk.
“We scoped a multi-channel notification service with direct and bulk sends. The API durably accepts idempotent requests, an outbox feeds partitioned asynchronous work, preference checks precede channel delivery, and consumers tolerate duplicates. We protected urgent traffic with isolation and backpressure. The main open choice is how much regional replication the recovery target justifies.”
Then ask, “Is there a decision you’d like me to defend or a part you’d like to extend?”
How to recover when you are uncertain
Uncertainty is expected; disappearing into silence is the problem. Use a four-step recovery loop:
- Name the uncertainty. “I’m deciding whether delivery state should be partitioned by recipient or notification.”
- Return to an access pattern or requirement. “The common read is a user’s inbox, while broadcast status is an aggregate.”
- Choose a reasonable default. “I’ll partition by recipient to distribute fan-out and support inbox reads.”
- Mark the consequence and move on. “Broadcast reporting will need asynchronous aggregation. I’ll note that and continue through delivery.”
If you do not know a product fact, reason from required properties: “I don’t recall that queue’s exact guarantee. We need ordering per recipient, so I’ll require ordering within a partition key.” If a premise changes, revise visibly rather than defending the old design.
If the interviewer challenges you, treat it as information rather than a verdict. Useful responses include:
- “That creates a hot broadcast partition. I’ll separate audience expansion from recipient-partitioned delivery.”
- “Strict preference enforcement means I should fail closed and accept delayed delivery.”
- “I’ll compare those options on recovery target and operational cost, then choose.”
A practice plan that trains the narration
Reading designs builds vocabulary; timed speaking builds interview performance. Use six sessions over two weeks:
- Session 1: requirements only. Take five prompts and spend five minutes on each producing a scope statement and two architecture-driving estimates.
- Session 2: interfaces and flows. For three prompts, define one write path, one read path, and the minimum data model in ten minutes each.
- Session 3: recorded baseline. Complete one 45-minute design aloud. Do not restart after mistakes.
- Session 4: failure drills. Reuse that design and answer rapid prompts about duplicate messages, hot keys, dependency failure, regional loss, and backpressure.
- Session 5: collaborative mock. Ask a partner to interrupt, change a requirement, and challenge one assumption. Practice acknowledging and revising.
- Session 6: fresh simulation. Use a new prompt, keep the clock visible, and reserve the final three minutes for a recap.
Score each recording from zero to two on scope, requirement-driven estimates, coherent end-to-end flow, depth, failure reasoning, explicit trade-offs, and closing summary. Change only the lowest two dimensions in the next session. If you are targeting staff or senior roles, combine this practice with preparation for senior software interviews beyond algorithm drills, where prioritization and influence often matter as much as component knowledge.
Your final interview checklist
- Frame the outcome, scope, constraints, and agenda.
- Define interfaces and data, then trace one durable end-to-end path.
- Deep-dive on risk and test failures, backpressure, and observability.
- State trade-offs, evolution triggers, and open risks.
- Recap before time expires.
A good system design conversation resembles a focused technical meeting. Make every decision traceable to a requirement and visible enough for the interviewer to collaborate.