A System Designer guide
How to practise system design
A practical loop for turning a diagram into a design you can explain: clarify, estimate, predict a failure, test it and revise one decision.
A whiteboard helps you organise an explanation. It does not tell you whether the workers can drain the queue, whether the database becomes the bottleneck after a cache miss, or whether a retry repeats a charge. A convincing diagram can hide all three.
Practise the reasoning between the boxes. For each part, say which user promise it serves, which new failure it introduces and which measurement would make you remove it. That gives you something to test, rather than a picture to memorise.
Write the user promise first
Take Notification service. Is success accepting a message, reaching a provider or reaching a phone? Those are different boundaries. The scenario measures provider acceptance and has a separate waiting deadline. Copy the actual promise into your notes before choosing a queue.
Ask who uses the system, which operation matters most, whether data changes and what a failure may lose. Keep assumptions visible. If a missing answer could reverse a decision, state both possibilities and ask about that one first.
Estimate the work that reaches each step
Use Numbers you can do in your head to turn a peak rate and request mix into a per-path load. A total request rate does not mean every request reaches the database. A cache removes repeated reads; a retry adds work; fanout turns one action into many writes.
Keep average, normal peak and event peak in separate rows. Size for the relevant peak with room for recovery. Then ask whether that room is already committed to a failed zone. Do not promise the same spare capacity twice.
Use a repeatable practice loop
- Read the brief and answer the clarification questions without drawing.
- Estimate the busiest request path and state the units of every number.
- Build the simplest connected design that could keep the promises.
- Write a prediction: name the first limiting part and the event that exposes it.
- Run the whole day. Record the measured failure, its time and the affected request type.
- Change one decision, predict its effect and run again.
- Explain the improvement and its cost. Then test a different situation before calling the idea learned.
Make one useful experiment
Suppose requests fail after a spike. One explanation is too little server capacity. Another is repeated misses reaching the database. Adding servers and a cache at once cannot distinguish them. Change just the suspected boundary, keep the workload fixed and compare database load as well as success rate.
The URL shortener is a useful first experiment because links do not change and reads dominate. Predict what happens when its cache empties, then compare your run with that prediction. Play this problem.
Keep correctness separate from throughput
A high score does not prove that a database transaction and an external payment happen atomically. Trace one logical operation through a lost reply and a crash. Where is its stable identity stored? When can a retry learn the result? What if the provider accepted work before your process stopped?
Use Exactly once, on purpose and the problem’s checked traces to practise that explanation. State what the traffic run measured and what still needs a protocol argument. Both matter in a design discussion.
Finish with a decision you can defend
Keep a short record: the promise, your estimate, the first failure, your change and the result. Include an alternative you rejected and the condition under which it becomes better. On the next attempt, begin from the brief again rather than copying the finished diagram.
When ordinary Practice feels comfortable, use Interview mode on a Medium or Hard problem. Speak through clarification and estimates before building. Defend a choice using the run’s evidence and a tested claim. The goal is a clear chain from requirement to decision to observed result, not a perfect drawing.