01Start with the contract
Ask questions that change architecture: who uses it, what the critical read/write path is, whether data loss is acceptable, and what success looks like. State assumptions when the interviewer will not choose for you.
Consider a paste-sharing service. “Create a paste” sounds simple until you ask whether pastes are public, whether readers need accounts, and whether an expired link may still reveal a cached body. Each answer changes a different boundary: authorization, key design, retention, or cache behavior. Write a concrete success trace before naming components: the creator submits text, receives a stable URL, and an authorized reader can retrieve it until expiry.
Turn vague quality goals into testable statements. “Fast reads” might become “95% of reads finish within 200 ms, measured at the service edge.” Specify the population and window, and whether failures count. A durability requirement asks what acknowledged data may be lost; an availability requirement asks whether requests can finish. You can have a reachable system that loses accepted writes, so neither requirement substitutes for the other.
Separate a known requirement from an assumed one. Record “assume one-year retention; confirm with product” rather than quietly designing around it. Pick the two constraints that dominate the first design. If privacy and reliable retrieval matter more than global latency, spend your early reasoning on permission checks and acknowledged storage instead of worldwide replication.
- Functional: verbs the system must support
- Non-functional: measurable quality constraints
- Out of scope: complexity you deliberately defer
02Estimate to choose—not to perform arithmetic
Use round numbers and show units. An estimate matters when it changes a decision: one database or shards, synchronous work or a queue, memory cache or disk, one region or several.
Build estimates from behavior. Suppose 5M daily readers each make three reads: 15M reads/day divided by 86,400 seconds/day is about 174 reads/s. A stated 5× peak gives 868 reads/s. MAU alone cannot supply either number: you need a daily-active share and actions per active user. Keep these assumptions next to the arithmetic so another engineer can challenge them.
Use units to catch mistakes. At 50k new 4 KB pastes/day, raw body growth is 200 MB/day, or 73 GB per 365-day year in decimal units. Three replicas make 219 GB before metadata, indexes, backups, and storage overhead. Replication increases retained bytes; it does not multiply the number of user creates. Peak bandwidth depends on response bytes and peak reads, not annual storage.
Finally ask which estimate changes a choice. A few writes per second suggests testing one relational primary before sharding. A 20 MB maximum body suggests separating blob transfer from metadata even if average objects are small. Recalculate with the daily-active share halved and doubled. If the decision stays the same, the estimate is already useful; extra decimal places will not resolve uncertainty in the workload.
- Average RPS = daily actions / 86,400
- Peak is commonly 2–10× average; explain your factor
- Storage/year = writes/sec × bytes/write × seconds/year × replication
03Architecture is a chain of responsibilities
Every box should own something and every arrow should carry a named request or event. Begin with the critical path, then add components only to satisfy a requirement or repair a bottleneck.
Trace the write path first: client → API → authorize and validate → commit paste metadata and body → acknowledge. For each arrow, say what is carried and what happens if it times out. If metadata and bodies live in separate stores, ask how a reader avoids seeing metadata for an absent body. One simple option is to upload the immutable body first, then publish its metadata, with cleanup for abandoned uploads.
Trace the read path separately: parse ID → look up metadata → check permission and expiry → fetch body → respond. A cache is an optimization around this contract. Caching a public body is different from caching an authorization decision; a formerly authorized reader must not retain access merely because a cache entry remains warm. Name the authoritative state and where freshness is enforced.
Only now add scale mechanisms. If a load test shows the primary is saturated by repeat reads, evaluate caching or replicas; if writes or data exceed its measured limit, evaluate partitioning. A queue is justified when work can finish later and its eventual result has a clear contract. This method produces a small design whose next component has a reason to exist and a measurable trigger.
- Name data and control flows
- Mark stateful boundaries
- Identify one bottleneck before proposing scale mechanisms