Design BookMyShow / Movie Booking (Low-Level Design)
Design a movie ticket booking system in an LLD interview — the concurrency-focused version. Modelling Movie/Show/ShowSeat, and the reserve-then-confirm seat locking that prevents double-booking. Classes, UML, decisions.
🔴 Low-Level Design · Case Study · Super-senior (concurrency)
"Design BookMyShow / a movie ticket booking system" as a low-level design question is really about one hard thing: two users must never book the same seat. The class model is straightforward; the concurrency is what separates a good answer from a great one. (For the distributed-scale version, see the HLD Ticketmaster design — here we focus on the objects and locking.)
Step 1 — Requirements
- Functional: browse movies and their shows across theaters; view a show's seat map; select and book seats; pay; get a booking confirmation.
- Non-functional (the point): no double-booking under concurrent users, correct seat state, graceful handling when a seat is taken while you're choosing.
Step 2 — The classes
- Movie — a film; shown as many Shows.
- Theater → Screen — a theater has screens; a screen has physical seats.
- Show — a movie on a screen at a time; owns the bookable ShowSeats (seat + status for this show).
- Seat / ShowSeat — a seat's status (
AVAILABLE / LOCKED / BOOKED) is per-show, not per-seat. - Booking — a user + a set of ShowSeats + status; Payment confirms it.
Step 3 — The core: preventing double-booking
🔴 Naive "check available → mark booked" has a race: two users both see a seat free and both book it. The fix is the reserve-then-confirm pattern with a lock:
- User selects seats → the system tries to LOCK them (a temporary hold, e.g. 5 minutes). This must be atomic — only one user can win the lock on a seat.
- Locked seats show as unavailable to others. User pays within the window → seats become BOOKED.
- If the timer expires or payment fails → the lock releases and seats return to AVAILABLE.
class Show {
private final Map<String, ShowSeat> seats;
// atomic lock: synchronized (or a per-seat lock / DB row lock)
public synchronized boolean lockSeats(List<String> ids, User u) {
for (String id : ids)
if (seats.get(id).status != AVAILABLE) return false; // someone took it
for (String id : ids) { seats.get(id).status = LOCKED;
seats.get(id).lockedBy = u;
seats.get(id).lockExpiry = now()+5min; }
return true; // this user won all seats
}
}
The check-and-lock happens as one atomic step (a synchronized block here; in a real system a DB transaction with row locks / SELECT … FOR UPDATE, or a distributed lock). That atomicity is the entire answer to "how do you prevent double-booking?"
Step 4 — The seat-lock design decisions
🔴 What interviewers dig into:
- Pessimistic vs optimistic: pessimistic locking (lock the seat rows) suits high contention (a blockbuster on sale); optimistic (version check at commit) suits low contention. Name both.
- Lock expiry: a background sweeper releases expired locks so abandoned carts don't hold seats forever.
- Idempotent payment: the confirm step must not double-charge on retry (link to payment design).
Step 5 — Other structure
🟠Search (movies by city/date) is a lookup over the movie/show data. Booking is itself a small state machine (CREATED → CONFIRMED → CANCELLED). Keep seat status per show, not per physical seat, since the same seat is independently bookable across shows.
The interview-ready walkthrough
"I'd model Movie → Show → ShowSeat (seat status is per-show) with Booking and Payment. The core is preventing double-booking, so I use reserve-then-confirm: selecting seats atomically locks them for a few minutes (AVAILABLE→LOCKED→BOOKED), releasing on timeout or failure. The check-and-lock is a single atomic step — a synchronized block or, realistically, a DB transaction with row locks (pessimistic for hot shows, optimistic otherwise). A sweeper frees expired locks, and payment is idempotent." That puts the concurrency front and centre — exactly the crux."
What to read next
- Design Ticketmaster (HLD) — the same problem at distributed scale
- ACID & Isolation Levels — the locking that backs it
- Design Splitwise — the next LLD case study
- ← The complete System Design guide (hub)