Revision sheet
Design hotel reservation.
The six things worth holding in your head the night before. Everything else is on the full page.
The opening move — minute one
“A hotel sells room-nights, not rooms — a count per room type per night, so a three-night booking must reserve three rows atomically. And unlike e-commerce, I’m allowed to oversell on purpose: no-shows run ~8%, so the ceiling is physical × (1 + overbook rate), with a walk policy for the night the statistics lose. Search is cached and may lie; the book path never does. At ~3M bookings a day — ~35 a second — the database is boring; the policy is the design.”
The booking state machine
PENDING → CONFIRMED → CHECKED_IN → CHECKED_OUT
CANCELLED (hold expired or guest cancelled — the window is evaluated property-local) · NO_SHOW (night audit: charge the fee, release the nights, feed the forecast) · WALKED (everyone showed — partner room + transport, logged as the policy’s cost)
Must-haves
- Models inventory as counts per (room type, night) — no physical-room rows, no date-range arithmetic on the booking path — and assigns room numbers at check-in.
- Reserves a multi-night stay atomically: conditional updates against the sellable ceiling in one transaction, date-ordered locking, rowcount == N or rollback — and names the TOCTOU race in check-then-insert.
- Treats overbooking as bounded policy: sellable = physical × (1 + overbook_rate) as data, reserved ≤ sellable as invariant, a walk policy with named compensation — and zeroes the rate on compression nights.
- Splits search from book — cached, fan-out, allowed-to-lie search against a strongly consistent book path — and does the arithmetic (~3M/day ≈ ~35 TPS) that keeps one ACID database the right answer.
Red flags
- Read-then-write availability anywhere on the book path, or a multi-night stay that can partially book.
- Refusing the overbooking requirement (“just never oversell”) or implementing it without bounds — both miss that it’s a tuned, priced policy.
- Charging cards at booking on guarantee rates, or evaluating cancellation windows in UTC.
The 7 trap claims — each one is wrong
- “model each physical room, and book room 204”
- “never sell more rooms than the hotel has”
- “check that the nights are free, then insert the booking”
- “charge the card when the booking is made”
- “store availability as date ranges per booking”
- “make search strongly consistent so it never lies”
- “a no-show just frees up the room”
The L4 lines — what depth sounds like
Room-Night Inventory & Multi-Night Atomicity
Adds date-ordered locking against deadlock between overlapping stays, reasons about isolation (why read-committed plus conditional updates suffices), and prices false “unavailable” against oversell under retry storms
Overbooking Policy & Walk Handling
Closes the control loop: no-show actuals and walk costs feed a per-(property, night) forecast, compression nights are detected from sellout velocity, and the walk budget is an explicit revenue trade
Booking Lifecycle & Holds Without Money
Handles the seams: bounded hold extension during the guarantee attach, cancel-vs-check-in races as conditional row updates, no-show fees against the token, and a time-zone-correct night audit as the lifecycle’s clock
Search / Book Split & Hot Nights
Handles the compression night end to end: local row-contention analysis (why row locks suffice at ~500/s), demand shaping at the edge, overbook-rate zeroing, and cache-vs-ledger drift reconciliation