Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
A design that has never been pushed is a drawing. You learn almost nothing from looking at one, because on a whiteboard everything works: the boxes are the right size, the network never drops packets, and the third-party API always answers. The only way to find out whether a design is understood is to apply pressure and watch which joint moves first. This course applies exactly six pressures, the same six, to every system it builds — not because six is a magic number but because these six are close to orthogonal. Each one loads a different structural axis, and a design can pass any five and fail the sixth badly. Once you have run a design through all six a dozen times, the questions stop being an exercise and become a reading habit: you start seeing where a design will bend before anyone asks you to push it, which is the entire skill this course is trying to install.
Here are the six, what each one is really probing, and what usually breaks first when you apply it to a typical read-heavy web system.
1. Traffic becomes 100x. Axis: throughput and capacity. First casualty: usually not the thing people name. It is rarely CPU; it is connection limits, a single write primary, or a queue that grows without bound because the consumer never got scaled with the producer.
2. One region goes down. Axis: availability and failure domains. First casualty: whatever quietly had exactly one copy — a primary database, a coordination service, a config store, or a DNS record with a long TTL.
3. Duplicates become unacceptable. Axis: correctness under retry. First casualty: any write path where the client retries and the server has no idempotency key. Networks retry silently; at-least-once is the default of the universe and exactly-once is something you build.
4. Reads must be under 100 ms. Axis: tail latency. First casualty: the fan-out. If one request touches ten services in sequence, your p99 is not the p99 of any one of them — it is much worse, because you need all ten to be fast simultaneously.
5. Data must stay in country. Axis: topology under regulation. First casualty: the global cache, the analytics pipeline, the backup bucket, and every third-party vendor you forgot processes your data too.
6. A critical dependency became unreliable. Axis: blast radius and isolation. First casualty: your own availability, via a thread pool that fills with requests waiting on a timeout that was set to 30 seconds by a default nobody chose.
Every stress task in this course answers the same six questions in the same order, so the shape becomes automatic: Scale — the concrete number that changed. Bottleneck — what breaks first, and why it rather than something else. Decision — the one thing you actually change. Tradeoff — what that decision costs, because there is always a cost. Incident — a plausible concrete failure this prevents or causes. Outcome — the measurable state afterwards.
And then, always, the paragraph that matters most: what does NOT change, and why. That is task six.
# stress.yml — run any design through this. One block per pressure.
# The six fields are the same every time; that repetition is the point.
- pressure: traffic becomes 100x
scale: 300 read rps -> 30,000 read rps; writes 0.35 -> 35 per sec
bottleneck: single write primary and its connection pool, not CPU
decision: add read replicas + a cache; keep one write primary
tradeoff: replication lag makes read-your-writes false by default
incident: user posts, refreshes, does not see their own post, posts again
outcome: p99 read under 40 ms; write path untouched at 35 rps
does_not_change: the data model, the ranking function, every invariant
- pressure: one region goes down
scale: 100% of one region's traffic must land somewhere else
bottleneck: the primary lives in exactly one region
decision: standby primary in region B, promote on failure
tradeoff: promotion risks split brain; you must fence the old primary
incident: both primaries accept writes for 40 seconds during a netsplit
outcome: RTO under 5 min, RPO under 30 s, measured by a real drill
does_not_change: the schema, the API contract, the client
- pressure: duplicates become unacceptable
scale: 1 in 1,000 requests is a client retry = 30 dupes/day at this volume
bottleneck: POST /orders has no idempotency key
decision: client-supplied key, unique index, return the original response
tradeoff: keys must be stored and expired; storage grows with traffic
incident: a customer is charged twice and tells everyone about it
outcome: zero duplicate orders across a 1M-request replay test
does_not_change: the pricing logic, the ledger invariant, the schema
# ... and the same block for: reads under 100 ms, data stays in country,
# a critical dependency became unreliable.
#
# Rule: if 'does_not_change' is empty, you have not understood the design.
# Rule: if 'tradeoff' is empty, you are lying.