Read real code and config from the data-and-money cases, then pick the senior fix: a metric label, an idempotent charge, a lost-update wallet debit, and an atomic multi-night reservation.
SDCSenior◷ 14 min
Level
FoundationsJuniorMiddleSenior
Money bugs live in the code, not the prose: a label on a metric, a non-atomic read-then-write, a charge with no idempotency key, a per-night decrement outside a transaction. Read each snippet, trace the failure, and pick the fix a senior engineer would commit.
Practise the loop you run in a design review on money or correctness-critical data: spot the hazard in the code, name it, and choose the change the mechanism actually requires.
What's wrong with this instrumentation, and what's the fix?
Heads-up A label per user forks a series per user; series count is the PRODUCT of label cardinalities, so user_id (millions of values) multiplies it into the millions and exhausts the TSDB's memory/index. Rich per-user breakdowns belong in logs/traces, not metric labels.
Heads-up Counter vs gauge is the wrong axis — a request count is correctly a counter. The bug is the unbounded user_id label exploding cardinality; the metric type is fine.
Heads-up More labels MULTIPLY the series count (it's a product), making cardinality worse, not better. The fix is to REMOVE the unbounded label (user_id), not add more.
Snippet 2 — the charge call
def checkout(order): # client retries this call on timeout resp = psp.charge(amount=order.total, source=order.card) ledger.record(order.id, resp) return resp
Quiz
Completed
A client retries checkout() after a timeout. What happens, and what's the fix?
Heads-up PSPs deduplicate by IDEMPOTENCY KEY, not by inspecting amount/card (two legitimate identical-amount charges are valid). Without a client-supplied key, the retry is a fresh charge. You must pass an idempotency key the client minted before the first attempt.
Heads-up A local transaction can't span the external psp.charge call, and it doesn't prevent a second charge when the first response was lost. The fix is an idempotency key, not a DB transaction.
Heads-up Swallowing the error risks a genuinely-missed payment (the timeout is ambiguous — it may have succeeded or not). Retry SAFELY with an idempotency key so duplicates are recognized and missed charges still complete.
Snippet 3 — the wallet debit
def debit(wallet_id, amount): bal = db.query("SELECT balance FROM wallets WHERE id = ?", wallet_id) if bal >= amount: db.execute("UPDATE wallets SET balance = ? WHERE id = ?", bal - amount, wallet_id) return "ok" return "insufficient"
Quiz
Completed
Two concurrent debits hit the same wallet. What's the bug, and the single-statement fix?
Heads-up Each statement is atomic, but the READ and the WRITE are separate, leaving a gap where another debit reads the same stale balance. Two concurrent debits both pass the check — the classic lost update. Collapse it into one conditional UPDATE.
Heads-up An index speeds lookups but does nothing about the read-modify-write race. The fix is concurrency control: an atomic conditional UPDATE (or SELECT … FOR UPDATE), so check-and-decrement is indivisible.
Heads-up Caching makes staleness WORSE and still leaves the gap between read and write. The fix is to make the decrement conditional and atomic at the DB, not to add a cache.
Snippet 4 — the multi-night reservation
def reserve(room_type, nights): # nights = [Dec31, Jan1, Jan2] for night in nights: db.execute( "UPDATE inventory SET booked = booked + 1 " "WHERE room_type = ? AND date = ? AND booked < total", room_type, night) return "reserved" # each night updated independently, no transaction
Quiz
Completed
The per-night UPDATE is conditional (good), but the loop has no transaction. What can go wrong, and the fix?
Heads-up Per-night atomicity prevents overbooking ONE night, but without a transaction across the range, a 3-night stay can book 2 nights then fail on the 3rd, leaving a broken partial reservation. The whole range must be all-or-nothing.
Heads-up Retrying re-runs nights that already booked, double-decrementing inventory. The fix is a single transaction over all nights with a rollback if any night fails — not a retry over partial writes.
Heads-up Separate transactions are exactly the bug — they allow a partial reservation (some nights booked, one failed). The range must commit atomically as one transaction, all-or-nothing.
Recall before you leave
01
How do you read a wallet-debit or reservation snippet for the lost-update / partial-write hazard?
02
How do you spot the idempotency and cardinality hazards in code?
Recap
Every data-and-money bug is readable straight off the code. An unbounded metric label (user_id) forks a series per value and OOMs the TSDB — series cardinality, not request rate, is the constraint, so drop it from labels. A charge the client retries with no idempotency key double-charges when the first response is lost — pass a client-minted key with an atomic check-and-store. A wallet debit that reads the balance then writes it back has a read-write gap that two concurrent debits exploit (the lost update) — collapse it into one atomic conditional UPDATE. And a multi-night reservation that decrements each night outside a transaction can leave a partial reservation — wrap the whole range in one all-or-nothing transaction. The senior habit is the same across all four: find the hazard, name it, and make the operation bounded (cardinality) or atomic (idempotency, lost update, partial write) — the fix the mechanism requires, not the one that hides it.