Engineering Atlas › Problem Solving & Incidents (AI era)

The Paradox: Every System Has the Same Problems

13 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

Why domains look different

A payments engineer talks about authorisations, captures and chargebacks. A ride-hailing engineer talks about dispatch, ETAs and surge. A chat engineer talks about presence, read receipts and fan-out. Each group has its own conferences, its own jargon and its own war stories, so it is natural to assume each needs its own way of thinking.

Strip the nouns off the war stories and they rhyme. "A customer was charged twice" and "a rider got two cars" and "the group got the message twice" are the same sentence: a request was retried, and the side effect was not idempotent. Payment providers say the same thing in their own docs: a connection error leaves you not knowing whether the request ran, so the API accepts a client-chosen key to make a retry safe (Stripe API docs), and Stripe's webhook guide tells receivers to expect the same event more than once (Stripe webhooks). "We sold 103 tickets for 100 seats" and "two riders were matched to one driver" are the same sentence: two writers raced on one scarce thing and the check and the write were not atomic.

The ten shapes

This course uses ten shapes, listed in curriculum/problem-shapes.md and on the home page:

  1. Contention: many writers want one thing.
  2. Duplicates: the same request arrives more than once.
  3. Ordering: events arrive in a different order than they happened.
  4. Fan-out: one event must reach many receivers.
  5. Hot spots: skew, where one key gets far more than its share.
  6. Overload: demand exceeds capacity.
  7. Partial failure: you cannot tell whether something happened.
  8. Multi-step consistency: several changes must all happen or none.
  9. Finding things fast: search, lookup and nearest-neighbour.
  10. Trust but verify: checking that what happened is what should have happened.

The list is not sacred. What matters is having a short list in your head and reaching for it every time.

What the domain decides

Once the shape is named, the domain supplies the numbers and the policy. For contention, the mechanism is a hold with an expiry plus an atomic check-and-set. The domain decides how long the hold lasts (a concert seat: ten minutes while you pay; a driver: fifteen seconds while they accept; a stock unit: thirty minutes in a cart), what happens when the hold expires, and whether overbooking is allowed on purpose (airlines do it, cinemas do not). Mistaking a parameter difference for a mechanism difference is how teams end up building three reservation systems that each have a different bug.

Why this is the skill of the AI era

Coding agents are very good at producing a mechanism once it is named: "add an idempotency key with a unique constraint and return the stored response on conflict" is a ten-minute task. They are much worse at noticing that a feature request about "group gift cards" is secretly a multi-step consistency problem. The engineer who names the shape writes the right spec, asks the agent for the right mechanism, and knows which tests prove it. The engineer who doesn't gets fast, plausible code for the wrong problem.

Down the stack

Layer 1The contract

The human practice promises one thing: before designing or debugging, you can state the problem as "this is a shape problem in the domain domain, with these parameters". For example: "Booking a driver is contention on a scarce resource; hold 15 s; on expiry offer the next driver; never two confirmed riders per driver". The statement is testable: a reviewer can check that the design contains the known mechanism for that shape and a test for its known failure modes.

Layer 2The mechanism

Each shape maps to a small set of mechanisms with well-understood behaviour. Contention maps to locks, compare-and-set on a version column (UPDATE seats SET holder=$1, version=version+1 WHERE id=$2 AND version=$3), or a single-writer queue per resource. Duplicates map to idempotency keys stored under a unique index; the same idea lives inside Kafka, where an idempotent producer (since 0.11.0.0) gets a producer ID and sequence numbers so a resent batch does not duplicate log entries (Kafka design docs). Ordering maps to sequence numbers per key and partitioning by key so one consumer sees a key's events in order (Kafka orders messages only within a partition, and a key hashes to one partition, per the same page). Partial failure maps to timeouts, retries with idempotency, and reconciliation; the Azure Architecture Center warns that retrying a non-idempotent step, such as incrementing a value, gives a wrong result, and tells you to make each step idempotent (Azure: transient fault handling). Recognising the shape gives you this menu, and each item comes with known failure modes: locks deadlock, compare-and-set livelocks under heavy contention, unique indexes become hot.

Layer 3The machine

The same shapes appear at every level of the stack, which is the strongest evidence that they are real. Two CPU cores incrementing one counter are contention, solved by an atomic instruction (LOCK CMPXCHG on x86) that holds the cache line in exclusive state for a few nanoseconds. A TCP segment retransmitted after a lost ACK is a duplicate, solved by sequence numbers that let the receiver drop bytes it already has. Out-of-order packets are reassembled by the same sequence numbers. A NIC with more packets than ring-buffer slots drops them: overload, with the same answer as an API gateway (shed or queue). Hardware engineers solved these shapes in silicon decades ago; distributed systems engineers solve them again with network round trips that cost a million times more.

Why it's built this way

  1. Physics gives every system the same constraints: information takes time to travel, machines fail independently, and capacity is finite.
  2. Time to travel means two parties can act on stale views, which produces contention, ordering and duplicate problems.
  3. Independent failure means a sender cannot know whether a receiver acted, which produces partial failure and multi-step consistency problems.
  4. Finite capacity produces overload and hot spots, and the need to find things among many produces indexing problems.
  5. Because the constraints are universal, so are the problems, and so are the solutions. Only the parameters are local.

Diagram

flowchart LR
  D["New problem in your domain"] --> S["Strip the nouns"]
  S --> N["Name the shape"]
  N --> M["Known mechanisms"]
  N --> F["Known failure modes"]
  M --> P["Set domain parameters"]
  F --> T["Tests for each failure"]
  P --> B["Design or agent spec"]
  T --> B

Worked example

A product manager asks for "group gift cards": several friends each chip in, and the card is issued when the target is reached. It sounds new. Strip the nouns: many payers each make a payment (several steps), the card must be issued exactly once (duplicates), contributions can race at the threshold (contention), and if one contribution fails after others succeed, someone must refund (multi-step consistency).

So the design is three known mechanisms. Each contribution carries an idempotency key, so a payer who taps twice pays once. The running total lives in one row updated with compare-and-set, so the contribution that crosses the target is the only one that triggers issuance. Issuance and refunds run as a saga with compensations, driven by an outbox so that the "target reached" event is never lost. Compensations can fail and be retried, so each one must itself be idempotent, and some steps (an email already sent) have no undo and should come last (Azure: compensating transaction pattern).

With 50,000 gift cards a day and five contributors each, that is 250,000 payments a day, about 3 a second on average and maybe 30 at peak: trivial load. The difficulty was never scale; it was naming the shapes. A team that skipped that step would likely ship a check-then-insert race and a missing refund path, then rediscover both in production.

In the wild

Trade-offs

ApproachStrengthsWeaknessesChoose when
Name the shape firstReuses proven mechanisms and tests; faster reviewsCan force-fit a genuinely novel problemAlmost always; most problems are not novel
Domain-first designCaptures domain rules and language preciselyRe-invents mechanisms, often with old bugsDomain modelling, alongside shape naming
Copy a big company's architectureFast start, battle-tested ideasTheir parameters (scale, latency, team) are not yoursYou genuinely share their constraints
Let the agent decide the mechanismVery fastPlausible code for the wrong shapePrototypes and throwaway spikes

Pitfalls in production

Leadership lens

Check yourself

  1. A rider app occasionally shows a trip as "cancelled" after it was "completed". Which shape is this, and what is the usual fix?

    Show answer

    Ordering: a late "cancelled" event overwrote a newer state. Attach a version or sequence number per trip and ignore events older than the stored version.

  2. Why is "how long should a hold last?" a domain question, but "how do we stop two people holding the same seat?" is not?

    Show answer

    The atomic check-and-set mechanism is the same everywhere; the hold duration depends on how long the human or system on the other side needs, which only the domain knows.

  3. A teammate says, "Our problem is unique, nobody has a real-time leaderboard for this game". How do you respond?

    Show answer

    Name the shapes: fan-out of score updates, hot spots on top players, finding things fast (top-k). Each has known solutions (sorted sets, sharded counters, periodic merge), so start there and focus effort on what is truly unique.

  4. Why do these shapes also appear inside a CPU and in TCP?

    Show answer

    Because they come from universal constraints: delay, independent failure and finite capacity. Any system with those constraints, at any scale, meets the same problems.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →