Car Rental System
The trick to this one isn't renting a car - it's that "available" depends on a date range, not a boolean. A vehicle sitting idle today can still be unavailable for the week someone wants it, because it's already booked for three of those seven days.
Requirements
Functional
- A
RentalCompanyoperates severalBranches, each holding a fleet ofVehicles. - A
Customersearches for vehicles of a given type available across all branches for a date range, and reserves one as aRentalAgreement. - A vehicle already booked for any overlapping date range must not be offered again for that range.
- Returning a vehicle (ending the agreement) can happen at a different branch than it was picked up from.
Non-functional
- Availability search must not be a per-vehicle linear scan of every agreement ever made once history grows large - the design should call out where an index goes even if it keeps the reference implementation simple.
- Price depends on both vehicle type and rental duration (weekly rates undercut day-rate multiples), and that formula needs to change without touching search or booking code.
Design
A Vehicle doesn't track "available" as a field at all - availability is computed by asking
whether any of its existing RentalAgreements overlap the requested range. Branch searches
its own fleet; RentalCompany fans that search out across branches. Pricing is delegated to
a PricingStrategy keyed by vehicle type, the same shape as the fee strategy in
parking-lot.mdx, because "how much does this cost" is exactly the kind of rule that changes
on its own schedule.
- 1The customer asks the whole company, not a specific branch.
- 2The company fans the search out to every branch it operates.
- 3Each vehicle checks its own agreements for a date overlap - no shared state to query.
- 4A vehicle from the results is booked into a new agreement.
- 5Price is computed by a strategy keyed on type - the company never hardcodes a rate.
RentalAgreement is the record of one booking - vehicle, customer, pickup/return branch, and
date range - and it's the only thing consulted when checking whether a vehicle is free,
never a separate availableDates cache that could drift out of sync with it.
Class diagram
Code
Design decisions
- Availability is derived, not stored. A
boolean availablefield onVehiclewould need updating at both the start and end of every agreement, and any missed update - a bug, a crash mid-transaction - leaves the field lying about reality. Computing it from the overlap check againstRentalAgreements means there's nothing to keep in sync; the agreements are the single source of truth. - Overlap is one date-range comparison (
aStart < bEnd && bStart < aEnd), reused everywhere availability is checked. Writing that comparison inline at each call site is exactly the kind of off-by-one that gets an interviewee marked down; giving it one home onRentalAgreementmeans it's tested once and never re-derived incorrectly. - Pricing is a
PricingStrategyper vehicle type, not anif/elseinBranch. Weekly discounts, seasonal surcharges, and loyalty rates are business decisions that change far more often than the booking flow itself; isolating them means marketing can change a rate table without anyone touchingRentalAgreementcreation. - What's missing for a real system: the linear overlap scan over a vehicle's agreements
is fine at demo scale but needs an interval tree or a date-bucketed index once a fleet has
years of booking history, and reserving a vehicle across a distributed system needs the
same atomic check-and-book guarantee called out in
parking-lot.mdxandmovie-booking.mdx- two customers racing for the last convertible on Friday night must not both win.