# Four weeks of system design interview prep

> A practical system design interview prep plan that prioritizes common topics, timed practice, capacity math, and clear tradeoff narration.

A strong system design interview is a controlled conversation, not a memory test. You need enough technical range to recognize the shape of the problem, enough practice to make decisions under a clock, and enough discipline to explain why each decision fits the stated requirements. Four weeks is enough to build that skill if you practice outputs instead of collecting more reading material.

The common failure is uneven preparation. Candidates spend hours learning how a famous service works, then freeze when an interviewer asks for traffic estimates, a data model, or one explicit consistency choice. This plan fixes the sequence: establish a repeatable interview loop, cover the highest-frequency design decisions, add failure analysis, and finish with recorded mocks that expose how you sound when time is short.

## Your scorecard comes before your study plan

Start by measuring what you can produce in 45 minutes. Topic familiarity feels reassuring, but interview performance depends on observable actions: clarifying the prompt, naming assumptions, estimating load, drawing boundaries, defending a data model, finding bottlenecks, and changing the design when a requirement moves.

Take one prompt you have not studied recently, such as designing a notification service. Record yourself and use a fixed clock. Spend five minutes on requirements, five on estimates, ten on the interface and data model, fifteen on the main architecture, and ten on failures and deeper questions. Do not pause the recording to look anything up. The result gives you a baseline that a reading checklist cannot.

Score the attempt from zero to two on each item:

- Requirements separate essential behavior from optional behavior.
- Estimates affect a design choice instead of decorating the page.
- Data ownership and the main write path are unambiguous.
- Tradeoffs include a rejected alternative and a reason.
- Failure handling covers partial failure, recovery, and observability.

Zero means you omitted the item, one means you mentioned it without using it, and two means it changed or justified the design. Add a separate note for communication: did you invite correction, respond to hints, and keep the diagram synchronized with your words? A total score matters less than the pattern. Someone who repeatedly scores zero on estimates needs estimation drills, not another video about distributed databases.

Keep the same scorecard for all four weeks. Changing criteria after a bad mock hides progress. You want comparable samples that show whether a weakness is shrinking. Save the recording, diagram, score, and one paragraph about what you would change. That paragraph becomes the first task in the next practice session.

## Week one builds a reusable interview loop

The first week should make the opening fifteen minutes automatic. Practice requirements, rough capacity math, API boundaries, and data models across small prompts before you try to master large architectures. A clean opening buys time later because the interviewer can see what you are solving and correct a bad assumption early.

On day one, build a question bank for functional requirements. For each prompt, ask who creates data, who reads it, which action must feel immediate, what can happen later, what must be retained, and who may access it. Ask for the expected scale and geography. Then state what you will leave out. That last sentence prevents a vague prompt from expanding until no design can fit the interview.

On day two, practice estimates with powers of ten. Convert daily active users into peak requests per second, estimate average payload size, project storage for the stated retention period, and identify the largest bandwidth path. Interview math does not need false precision. It needs a visible chain of assumptions and a conclusion such as, "The write rate fits one primary database, but reads need caching because the peak fan-out is much larger."

Use this compact worksheet:

```
traffic = active users x actions per user / active seconds
peak traffic = average traffic x stated peak factor
storage = writes per day x bytes per record x retention days
bandwidth = requests per second x bytes per response
```

On days three and four, map verbs to interfaces and persistent entities. If the product lets a user create, edit, fetch, list, and delete an object, write those operations before drawing boxes. Define identifiers, idempotency behavior, pagination, and the fields needed for the critical read. Then choose a data model that supports those access patterns. Do not reach for a document store because the payload looks like JSON or a relational database because the entities have names. The access path, transaction boundary, and growth pattern should drive the choice.

Use days five and six for two 45-minute designs: a URL shortener and a rate limiter are useful because they expose different muscles. The first tests identifiers, read-heavy traffic, cache behavior, and abuse controls. The second tests scope, time windows, atomic updates, clock assumptions, and failure policy. On day seven, review the artifacts and rewrite only the weakest opening. Rest matters more than squeezing in a third full design when your attention has already dropped.

## Week two covers data movement and scale

The second week should focus on how data moves when one machine or one synchronous request is no longer enough. The frequent topics are partitioning, replication, caching, queues, indexing, and consistency. Learn each as a response to a measured constraint, not as a box that makes a diagram look mature.

Partitioning answers where data lives. Practice choosing a partition key, then attack it with skew, hot users, time-based traffic, and rebalancing. A user ID spreads many consumer workloads reasonably well but makes cross-user aggregation harder. A timestamp helps range scans but can send current writes to the same partition. Random keys distribute writes but require another index for lookup. State which pain you accept.

Replication answers how the system survives loss and serves distant readers. Be able to explain synchronous versus asynchronous replication without claiming that one is simply better. Synchronous acknowledgement can protect a stronger durability or consistency promise at the cost of latency and availability during a partition. Asynchronous replicas reduce write latency but can serve stale data or lose acknowledged writes during a narrow failure window, depending on the database and failover policy.

Treat caching as a consistency policy with storage attached. RFC 9111 defines HTTP cache behavior in terms of freshness, validation, and invalidation rules. The useful interview lesson is broader: name who owns freshness, how an entry expires, what happens after a write, and what the system does when the cache is unavailable. "Add Redis" answers none of those questions. For each mock, choose cache-aside, write-through, or no cache, and explain the failure you avoid and the failure you introduce.

Queues separate the acceptance of work from its completion. Practice at-least-once delivery first because duplicate work is a routine operational fact. Give the job an idempotency key, store the result of completed work, define a retry limit with backoff, and send exhausted jobs to a place operators can inspect. Exactly-once language usually hides the boundary: a broker may deduplicate delivery while an external payment, email, or database write still repeats. Name the side effect and make that boundary safe.

End the week with a news feed design and a file processing pipeline. The feed forces a choice between computing reads on demand and distributing writes ahead of time. The pipeline forces you to discuss object storage, metadata, asynchronous work, retries, and progress states. Run each twice. On the second run, change one requirement, such as celebrity accounts or a strict completion deadline, and alter the design rather than defending yesterday's answer.

## Week three makes failure behavior explicit

The third week turns a plausible diagram into an operable system. Interviewers often push on failure because happy-path components are easy to name. You should be able to say what fails, what the caller observes, how work resumes, and how an operator knows recovery is working.

Start with timeouts and retries. Every remote call needs a time budget. A retry can improve success after a transient failure, but synchronized retries can multiply load on a sick dependency. Practice bounded exponential backoff with jitter, a total deadline, and a rule about which errors are safe to retry. Then connect retries to idempotency. If repeating a request can charge a card or create a second order, the API needs a stable request key and durable deduplication at the side-effect boundary.

Next, practice overload. Queues absorb bursts only until their wait time violates the product requirement or storage fills. Define admission control, per-tenant limits, load shedding, and backpressure. Decide whether the system rejects new work, serves a degraded response, or delays processing. The answer depends on the operation. Dropping a recommendation refresh may be acceptable; silently dropping a payment is not.

Use the Google Site Reliability Engineering treatment of error budgets as a decision tool, not a slogan. The useful idea is that a reliability target leaves a measurable allowance for failure. In an interview, translate that into behavior: which endpoint has which availability goal, which dependency consumes most of its latency budget, and when the team stops risky changes to restore reliability. Do not promise five nines because it sounds senior. Stronger targets cost money and restrict design choices.

Walk one failure all the way through. Suppose a consumer writes a record, crashes before acknowledging the message, and receives the same message again after restart. If the handler inserts blindly, the system creates a duplicate. If it records the idempotency key and result in the same transaction as the write, the second attempt can return the first result. If the side effect lives outside that transaction, you need an outbox, a provider idempotency mechanism, or reconciliation. This is the level of detail that distinguishes a recovery story from the phrase "the queue retries it."

Finish with two mocks that invite operational questions: a payment workflow and a metrics ingestion service. For each critical path, annotate the diagram with timeout, retry owner, idempotency boundary, and the signal an operator watches. Cover latency, error rate, traffic, and saturation where they fit, but tie every signal to a decision. A dashboard nobody acts on is not a recovery plan.

## Week four converts knowledge into interview performance

The final week should contain more timed speaking than new study. Run four full mocks, review them with the same scorecard, and spend the gaps on narrow repairs. By now, another broad course will create familiarity without improving the behaviors the interviewer can grade.

Schedule mocks with different conditions. Run one with a peer who interrupts often, one with a quiet peer who gives little guidance, one on an unfamiliar prompt, and one at the expected interview time of day. If no partner is available, record yourself and inject requirement changes from sealed notes at fixed timestamps. Self-review misses interpersonal habits, but it still exposes rambling, silent drawing, and unexplained component changes.

Use a strict review loop after each mock:

1. Write the first minute when the design went off course.
2. Identify the missing question or decision that caused it.
3. Redo only that five to ten minute segment.
4. Repeat the segment without notes the next day.
5. Check whether the next full mock shows the same failure.

Do not redo the whole interview immediately. Fatigue and memory can make the second attempt look better without teaching recall. A short repaired segment creates a clearer link between error and correction. The next-day repetition tests whether the correction stuck.

During the last two days, reduce volume. Review your scorecards, estimation sheet, tradeoff pairs, and three failure walkthroughs. Do one light opening drill, then stop. Sleep and a working microphone will help more than a midnight tour of consensus protocols. You are preparing to reason aloud, which requires attention that cramming removes.

## Topic frequency should control your depth

Allocate study time by how often a concept shapes ordinary designs. Requirements, capacity estimates, APIs, data models, caching, partitioning, replication, queues, consistency, availability, and observability appear across prompts, so you need working fluency in all of them. Specialized algorithms matter when a prompt calls for them, but they should not displace the common decisions.

A practical depth map has three bands. In the first band, you should explain and apply the topic without notes: request flow, storage choice, indexes, cache policy, partition key, replication mode, asynchronous work, idempotency, rate limits, and failure handling. These concepts decide most diagrams.

In the second band, you should recognize the problem and discuss one credible approach: leader election, distributed locks, change data capture, search indexing, geospatial queries, streaming windows, and multi-region writes. Learn the conditions that require them and the operational cost they add. You do not need to reproduce an implementation unless the role emphasizes that domain.

In the third band, study role-specific material. A storage role may need LSM trees, compaction, bloom filters, and quorum behavior. A media role may need codecs, manifests, content delivery, and transcoding. A machine learning platform role may need feature freshness, offline and online parity, model rollout, and drift detection. Read the job description and recent engineering material from the company, then move relevant items upward. Frequency is contextual, not universal.

Build a small decision deck instead of a glossary. Each card should begin with a condition, such as "reads outnumber writes by two orders of magnitude and tolerate one minute of staleness." On the back, write one likely choice, its main cost, and a question that could reverse it. This forces you to retrieve architecture from constraints. A card whose front says only "caching" tests vocabulary and will not improve an interview answer. Review ten cards aloud, then discard any card you can answer without stating a downside.

Group prompts by the decision they expose rather than by product name. A chat service and collaborative editor both raise ordering questions, while a crawler and media pipeline both raise scheduling and backpressure questions. Once you recognize the shared decision, you can transfer knowledge instead of memorizing separate diagrams. Keep one representative prompt for each family and add variants that change a single constraint.

Spend less time on component catalogs. Interviewers can ask what a database, queue, or cache guarantees in your design, and vendor defaults often differ. Learn the behavior you require before naming an implementation. If you do name one, qualify the claim: state the configuration or operating mode that supplies the guarantee. This habit also gives you a safe response when the interviewer prefers a different technology, because your decision rests on behavior rather than brand loyalty.

Consensus deserves careful placement. You should understand why a system needs agreement, what a leader does, and how partitions affect progress. Most general interviews do not require you to derive Raft. They do require you to avoid placing a distributed lock or consensus group on every request without discussing latency and availability. Study the abstraction before the paper's mechanics unless the position calls for the mechanics.

## Tradeoffs need a decision, not a recital

Good narration connects a requirement to a choice, names its cost, and leaves a trigger for revisiting it. Saying "SQL versus NoSQL depends" only restates uncertainty. Saying "The order write spans inventory and payment state, so I want transactional constraints in a relational store; if read traffic dominates later, I will build a separate read model from the change log" gives the interviewer something to test.

Use a four-part sentence whenever you make a major choice:

```
Because [requirement or estimate], I will choose [design].
This gives us [specific benefit] but costs [specific downside].
I am rejecting [credible alternative] because [reason in this prompt].
I would revisit the choice if [measurable condition changes].
```

The last line prevents false certainty. It shows that architecture responds to constraints. The trigger should be concrete: write volume exceeds one primary's tested capacity, cross-region latency breaches the target, queue age passes the product deadline, or cache hit rate fails to justify its complexity. Avoid vague triggers such as "when we scale."

Narrate at decision boundaries, not continuously. State what part of the diagram you are drawing, make the choice, explain it, and ask whether the interviewer wants depth there. Constant speech can hide the architecture. Long silence makes your reasoning invisible. A useful rhythm is twenty or thirty seconds of explanation followed by a brief check for alignment. You do not need permission for every box.

When the interviewer challenges a choice, do not treat it as a verdict. Restate the changed constraint and trace its effect. "If users must read their own writes across regions, the asynchronous read replica no longer meets the requirement. I can route a user to the write region, use a session token to wait for replication, or pay for a stronger multi-region write model. Which latency target matters here?" That answer creates options without pretending they are free.

The Dynamo paper is useful because it explains mechanisms such as sloppy quorum and hinted handoff as ways to keep accepting work during failures, while also describing conflict resolution. The lesson is not to copy Dynamo into every design. Availability choices push complexity into reconciliation, application semantics, and operations. If the prompt cannot tolerate conflicting versions, say so before borrowing an availability technique built around them.

Cut filler from your spoken answer. Phrases such as "we can use a load balancer for scalability" name a component without a decision. Specify whether it terminates connections, routes by region or tenant, performs health checks, or protects an overloaded pool. If none of those behaviors matters yet, leave the box out. An interviewer can judge a wrong choice that you explain; they cannot judge a decorative rectangle.

## A worked prompt shows where the minutes go

A notification service is a useful rehearsal because it combines user preferences, multiple delivery channels, bursts, retries, provider failures, and status tracking. Begin with scope: accept notification requests from internal products, honor user preferences, deliver email and push messages, and expose delivery status. Exclude authoring interfaces and marketing segmentation unless the interviewer adds them.

State assumptions rather than waiting for perfect numbers. Suppose traffic averages 10,000 notification requests per second and peaks at five times that rate. Each request may fan out to two channels. Delivery may take seconds, but request acceptance should return quickly. Users must not receive repeated transactional messages when a worker retries. These assumptions immediately favor durable asynchronous processing and make idempotency part of the central design.

Define an interface with a caller-supplied idempotency key, recipient, template reference, parameters, requested channels, and priority. Return a notification ID plus an accepted status. Store the request and an outbox record in one transaction. A relay publishes channel jobs from the outbox, which closes the gap where the database commits but publishing fails. Channel workers read preferences, render content, call providers, and record attempts.

Partition jobs by recipient when per-user ordering matters. If global ordering does not matter, do not pay for it. Separate queues by channel and perhaps by priority so a slow email provider does not block urgent push work. Bound retries according to provider response and message expiry. A password reset that arrives tomorrow has failed even if the worker eventually marks it delivered.

The data model needs notification, delivery attempt, preference, and idempotency records. Keep immutable request facts separate from changing delivery state. Index status queries by notification ID and operational queries by state plus next attempt time. Archive or expire verbose attempt history according to an explicit retention need; leaving it unbounded is not a design.

Now push on failure. If a provider accepts a request and times out before returning, the worker cannot know whether delivery occurred. A stable provider idempotency key solves the ambiguity only if that provider honors it. Otherwise the system must choose between a possible duplicate and a possible omission, then make that product decision visible. For transactional security messages, the choice may differ from promotional mail.

Push on overload next. Admit critical transactional work before bulk notifications, cap each tenant, and expose queue age rather than queue length alone. Queue age tells you whether work can still meet its deadline. If a provider degrades, pause or slow that channel while other channels continue. Record the reason for final failure so callers and operators can distinguish invalid addresses, provider rejection, expiry, and exhausted retries.

With five minutes left, summarize the critical path and the accepted costs. The design favors fast acceptance and isolated delivery at the cost of eventual status and duplicate defenses. It keeps request and outbox state together, but provider calls remain outside that transaction. The deepest unresolved choice is the product policy for ambiguous provider outcomes. That is a credible ending because it identifies a real boundary instead of claiming the system is finished.

## Seniority changes the expected conversation

The same prompt measures different things at different levels. A mid-level candidate should produce a coherent path, choose reasonable components, and explain basic scaling and failure behavior. A senior candidate should control scope, expose organizational and operational costs, recognize migration paths, and ask which business constraint deserves complexity. Staff-level discussion often extends to ownership boundaries, cross-team interfaces, rollout risk, and how the design evolves while serving traffic.

Do not imitate seniority by adding components. Senior engineers often remove machinery after finding that the stated load fits a simpler system. If one relational primary can handle the estimated writes with headroom, say that you will test it before partitioning. Explain how you would observe capacity and introduce partitioning later. Complexity without a requirement creates more failure modes and gives the interviewer more weak decisions to probe.

Company context also matters. Consumer products may emphasize fan-out, abuse, privacy, and global latency. Financial systems may emphasize auditability, reconciliation, and strict state transitions. Infrastructure companies may probe tenancy, control planes, data planes, and safe rollout. Use the same interview loop, but change the depth map according to the role.

If you repeatedly fail mocks because your current work offers too little architecture exposure, get review from someone who has operated these systems. Founder advisory or fractional CTO work from oleg.is is aimed at companies rather than interview coaching, so it only fits if the underlying gap is inside a startup team. For an individual interview, a skilled peer with a timer and a blunt scorecard is the more direct tool.

On interview day, write the requirements and success measures where both people can see them. Keep a small time budget beside the diagram. When the clock tightens, finish one critical path and one failure path before adding optional features. A complete argument about a bounded system beats an ambitious diagram whose arrows never explain what happens.
