Free preview

Requirements checklist

□ Gateway timeout semantics — ask early: outcome is UNKNOWN,
  the charge may or may not have happened (the round's pivot)
□ Interface: createIntent / confirm / status / refund
  (full + partial); several currencies, handled fine in v1
□ Duplicates: double-clicks AND client retries must be safe;
  gateway accepts an idempotency key on charges
□ Records: money history never edited — corrections are new
  entries, never changed ones
□ Retries of unknowns: allowed only when provably safe
□ Volume: thousands/day — correctness dominates throughput

The core model

PaymentState      CREATED -> CONFIRMING -> SUCCEEDED | FAILED
                                        -> UNKNOWN (timeout/crash)
                  UNKNOWN exits ONLY via reconciliation — no guessing
Idempotency key   client-supplied, fixed on the INTENT (not the
                  request); create replays return the existing
                  intent; every charge attempt carries the key
Ledger            append-only, separate from mutable state;
                  appended exactly at settling moments;
                  corrections = compensating entries
Gateway port      charge(key, amount, timeout) + lookup(key) —
                  lookup is the reconciler's whole toolkit
Reconciler        sweeps UNKNOWNs, lookup, settle via the SAME
                  settle() as the happy path; no answer -> stays
                  UNKNOWN
Refund            own machine, references original, validates
                  against refundable remainder
Money             integer minor units, never floats

Principles demonstrated (name them at the decision)

  • Single responsibility — the state machine is the sole authority on legal transitions; UNKNOWN's only exit is reconciliation.
  • Separation of concerns — mutable state answers "where is it now"; the append-only ledger answers "what has ever happened"; different masters, different change rules.
  • Dependency inversion — the gateway behind a port with a timeout-capable stub; the reconciler testable without a network.
  • Open/closed with judgment — a fraud-check socket between confirm and the charge call; policy grows without touching callers.

Complexity facts

all operations   O(1) local hash-map work + one gateway call;
                 the gateway's 30+ s worst case dominates — never
                 loop on it synchronously
reconciler       O(u) in unknown payments per sweep; cost bounded
                 by gateway calls, so pace it
the argument     correctness dominates throughput at
                 thousands/day — no caching or sharding talk

What earns points, per report dimension

  • Requirements & interface — asked what a timeout means unprompted, and let the answer visibly reshape the design; pinned duplicate semantics and the never-edit rule.
  • Core design & invariants — UNKNOWN named as a state, not an error; keys anchored to the intent with the why; ledger appends exactly at settling moments; refunds validated against the remainder.
  • Extension probe — place the new requirement on an existing discipline (a state, an entry type, a port) and say which invariants are untouched.
  • Complexity honesty — the gateway call as the dominating cost; the reconciler's pacing argument said aloud.
  • Communication — the timeout catch block narrated ("this is the whole problem"); rejected alternatives (timeout-as-failure, sync retry loops, one record type) named with reasons.

Ready? Sit the live mock → — the interviewer will run a twist this chapter deliberately hasn't shown you.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue