The interviewer just said…
“OK, that scope works. How would you approach the design?”
They’ve agreed on v1. Now they want to see structure — not a flood of classes.
What you should do next
Apply the LLD delivery framework in order. Say the steps aloud, then execute them on the whiteboard:
- Requirements — done (search, shows, seats, book, cancel)
- Entities & relationships — Movie, Theater, Screen, Show, ShowSeat, Ticket
- Service APIs — method signatures a client would call
- Core flow — happy path: reserve → pay → book → ticket
- Extensions — failure compensation; concurrency if time remains
This mirrors LLD delivery in a hurry: narrow problem → model → API → flow → hard parts last.
Timeboxing for a 45-minute round
| Phase | Minutes | Deliverable |
|---|---|---|
| Clarify + read-back | 5 | Agreed v1 scope |
| Entities + seat state machine | 10 | Boxes, ShowSeat lifecycle |
| Service APIs | 8 | 5 interfaces, key methods |
| Happy path walkthrough | 10 | reserve → pay → book → ticket on board |
| Failure / cancel | 7 | Catch blocks, release/refund |
| Concurrency (if asked) | 5+ | “Critical section is reserve”; one strategy |
If you’re running long, cut Movie metadata fluff, not the booking saga. Interviewers remember whether you understood RESERVE before payment.
The approach in one paragraph (memorize this shape)
“I’ll model theaters in cities with screens and scheduled shows. Each show has its own seat inventory via ShowSeat rows with status AVAILABLE, RESERVE, or BOOKED. MovieService handles city search; ShowService handles availability and seat transitions; BookingService orchestrates reserve, payment stub, book, and ticket creation; TicketService persists tickets. Cancel reverses book. If two users race for the same seat, the reserve step must be atomic — we can discuss synchronized blocks or DB row locks after the happy path.”
That paragraph is your roadmap. Everything below fills in details.
Core flow (sketch before coding)
User picks show + seats
│
▼
reserveSeat() ──► AVAILABLE → RESERVE
│
▼
payment (stub) ──► may throw PaymentException
│
▼
bookSeat() ──► RESERVE → BOOKED
│
▼
bookTicket() ──► return ticketId
Cancel (separate path):
cancelTicket(ticketId) → load Ticket → releaseSeat → refund stub
Where concurrency fits (don’t lead with it)
The critical section is between reading a seat as AVAILABLE and writing RESERVE. Two threads in that gap → double booking.
For v1 implementation in hub/scripts/movie-ticket-sourced/, ShowService.reserveSeat starts with synchronized — enough for a single JVM demo. In the interview, mention show-level or row-level locks and distributed options after the domain is clear. Leading with Redis before ShowSeat exists is a red flag.
Mapping phases to this course
| Delivery step | Course chapter | Code location |
|---|---|---|
| Entities | Design entities | com.interview.model.* |
| APIs | Design service APIs | com.interview.service.* |
| Implement models/repos | Implement models | com.interview.repo.* |
| Happy path | Booking happy path | BookingService, Main.java |
| Failures | Failure handling | try/catch in BookingService |
| Concurrency | The race (next module) | ShowService* variants |