Object-Oriented Design: Hotel Room Booking System
Company: Apple
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Onsite
# Object-Oriented Design: Hotel Room Booking System
Design the object model and core service for a hotel room booking system. The service must let a client check whether a room is available over a date range and book a room for a customer over a date range. After the core design, you will address how the system behaves when many booking requests arrive at the same time.
You should produce a clean class design and working logic for at least these two operations:
- `checkAvailability(roomId, startDate, endDate)` — is the given room free for the entire range?
- `bookRoom(customerName, roomId, startDate, endDate)` — reserve the room for the customer over the range, or reject if it is not free.
### Constraints & Assumptions
- A single hotel with a fixed set of rooms; each room has an id and a type (e.g., single, double, suite).
- Dates are at **day granularity**. A stay is the half-open interval `[startDate, endDate)`: check-out day is not occupied, so a guest checking out on day `D` and a guest checking in on day `D` do **not** conflict.
- Two bookings for the **same room** conflict if their date ranges overlap.
- The core exercise can be in-memory, but the model should map cleanly onto a real datastore.
- Availability checks are frequent (read-heavy); booking requests can arrive concurrently.
### Clarifying Questions to Ask
- Single property, or a chain of hotels that share the model?
- Day granularity, or do we need check-in/check-out times (hour granularity)?
- Are back-to-back stays (one guest out, another in on the same day) allowed? (Assume yes — half-open intervals.)
- Do we need cancellation and modification of an existing booking?
- Are room **types** bookable (any room of a type) or only a specific `roomId`?
- What is the overbooking policy — strictly no overbooking, or allow a configurable buffer?
### Part 1 — Class model and core API
Design the classes and implement `checkAvailability` and `bookRoom`. Show the data structures that store bookings per room and the logic that decides whether a range is free.
```hint Where to start
Identify the entities first: `Room`, `Customer`, `Booking` (room + customer + date range), and a `BookingService` that owns the operations. Keep responsibilities separate.
```
```hint Data structure for availability
For each room, store its bookings keyed by start date in a sorted map (e.g., a `TreeMap<LocalDate, Booking>`). To test a candidate range you only need to inspect the neighboring entries (`floorEntry`/`ceilingEntry`) instead of scanning every booking.
```
```hint Overlap test
Two half-open ranges `[s1, e1)` and `[s2, e2)` overlap exactly when `s1 < e2 && s2 < e1`. Validate `startDate < endDate` before anything else.
```
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### Part 2 — Concurrency: no double-booking
Multiple clients may call `bookRoom` for the **same room and overlapping dates** at the same time. Explain where the race condition is and design the system so that at most one of them succeeds — no two confirmed bookings for a room ever overlap.
```hint Name the race
The bug is a classic check-then-act: two threads both run `checkAvailability` (both see "free"), then both insert. The availability check and the insert must be one atomic step.
```
```hint Lock granularity
A single global lock serializes the entire hotel and kills throughput. Prefer a lock **per room** (e.g., a `ConcurrentHashMap<roomId, Lock>` or striped locks) so bookings for different rooms proceed in parallel.
```
```hint Production mapping
In a real datastore, push the invariant down: a uniqueness/exclusion constraint on (room, date) or `SELECT ... FOR UPDATE` / a serializable transaction, so the database — not application memory — guarantees no overlap across processes.
```
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### What a Strong Answer Covers
```premium-lock What a Strong Answer Covers
```
### Follow-up Questions
- How would you persist bookings and enforce the no-overlap invariant at the database level (schema, constraints, transaction isolation)?
- Add cancellation and modification of an existing booking — how do the data structures and locking change?
- Generalize to booking a room **type**: any available room of the requested type is acceptable. How does availability and assignment change?
- How would you scale this to thousands of hotels and shard the data while keeping per-room booking correct?
Quick Answer: This question evaluates object-oriented design skills through modeling a hotel room booking system with availability checks and reservations. It is commonly asked to assess class decomposition, interval-overlap logic, and data structure choices for efficient scheduling queries. A follow-up on concurrent booking requests tests practical understanding of race conditions and locking strategies in a system design context.