Step 1 — Clarify the requirements
Never start drawing boxes. A strong candidate spends the first few minutes scoping the problem so the design that follows is justified. For a parking lot system, the questions worth asking are:
- Single level or multi-level, and how many spot types (compact, large, handicapped, EV)?
- How are fees calculated (hourly, daily cap, by vehicle type)?
- Do we issue tickets, and how do drivers pay (cash, card, app)?
- Do we need real-time availability display and reservations?
Functional requirements
- Admit a vehicle, assign an appropriate free spot, and issue a ticket.
- On exit, compute the fee from duration and process payment.
- Track and display available spots by type.
Non-functional requirements
- Correct spot assignment with no double-booking.
- Extensible to new vehicle types, spot types, and pricing.
- Concurrency-safe at busy entrances.
Step 2 — Back-of-the-envelope estimates
Sizing the system tells you which parts are hard. Round aggressively and state your assumptions out loud; the numbers matter less than showing you can reason about scale.
| Metric | Estimate | Reasoning |
|---|---|---|
| Scale | thousands of spots | A single facility; this is a modelling problem, not a throughput one. |
| Concurrency | a few entrances/exits | The contention point is assigning a spot to simultaneous arrivals. |
Step 3 — Data model and API
A compact data model and a small API surface anchor the rest of the discussion. Keep both minimal; you can always extend them when the interviewer pushes.
Core entities
ParkingSpot
id, type (Compact/Large/Handicapped/EV), level, isFree
Polymorphic by type; a vehicle fits certain spot types.
Vehicle
licensePlate, type (Car/Motorcycle/Truck/EV)
Drives which spot types are eligible.
Ticket
id, spotId, vehicle, entryTime, exitTime, fee
The record from entry to payment.
API sketch
- POST
ParkingLot.parkVehicle(vehicle)— Assign a spot, return a Ticket (or reject if full). - POST
ParkingLot.unparkVehicle(ticket)— Free the spot, compute fee, take payment. - GET
ParkingLot.availability()— Free spot counts by type and level.
Step 4 — High-level design
Sketch the happy path end to end before optimising anything. This is the architecture you would draw on the whiteboard first:
- 1Model the lot as levels, each holding typed ParkingSpots.
- 2A SpotAssignmentStrategy picks the best free spot for an incoming vehicle type.
- 3On entry, mark the spot occupied and create a Ticket with entry time.
- 4On exit, a FeeStrategy computes the charge from duration; a PaymentProcessor settles it; free the spot.
Step 5 — Deep dives that separate strong answers
The high-level design is table stakes. Interviewers spend most of the time here, probing the decisions that actually carry the system. These are the ones to be ready for.
The object model and polymorphism
Model vehicles and spots as class hierarchies (or enums plus a fit-rule) so behaviour extends without rewrites. A Vehicle knows which spot types it can occupy; a ParkingSpot knows whether it is free and what fits. Favour composition and small interfaces over a god-class ParkingLot. Use enums for fixed categories (vehicle type, spot type) and an explicit eligibility rule (a motorcycle fits any spot, a truck needs a large one). This is the part interviewers grade hardest: a clean, open-for-extension model that does not need surgery to add an EV spot type or a new vehicle.
Strategy patterns for assignment and pricing
Spot assignment and fee calculation are exactly where requirements churn, so isolate them behind strategy interfaces. A SpotAssignmentStrategy can be nearest-to-entrance, fill-by-level, or best-fit by size, swappable without touching the lot. A FeeStrategy can be flat hourly, tiered, daily-capped, or vehicle-type-dependent. Encapsulating these means a new pricing scheme is a new class, not edits scattered through the codebase. This demonstrates the open/closed principle concretely, which is the point of the exercise.
Concurrency and state integrity
Even though the scale is small, two cars can reach the entrance at once, so assigning a spot must be atomic: reserve-then-confirm, or guard the free-spot pool with a lock, so the same spot is never handed to two vehicles. Keep availability counts derived from spot state (or carefully kept consistent with it) to avoid drift. If you extend to a multi-facility or app-reservation system, this becomes a real distributed-locking discussion, which is a natural place to show you know when a low-level problem grows into a systems problem.
Step 6 — Bottlenecks and how to scale past them
Naming where the design breaks, and the specific fix, is what signals seniority. For a parking lot system the pressure points are:
Race when assigning a spot to simultaneous arrivals.
Atomic reserve-then-confirm or lock the free-spot pool per type.
Availability count drifting from real state.
Derive counts from spot state, or update them under the same lock.
Step 7 — Key tradeoffs
There is rarely one right answer. State the tradeoff, then commit to a side with a reason tied to the requirements you clarified in step one.
Type modelling
Class hierarchy (rich behaviour)
Enum + rules table (flat, data-driven)
Guidance: Hierarchy for behaviour-rich types; enum + rules when categories are simple and stable.
Assignment
Nearest spot (driver convenience)
Best-fit by size (utilisation)
Guidance: Make it a strategy so the lot can switch policy without code changes.
Common follow-up questions
When you finish the core design, expect the interviewer to pull on one of these threads. Have a one-paragraph answer ready for each.
- How would you add multiple levels and a real-time availability board?
- Model vehicles and spots as class hierarchies (or enums plus a fit-rule) so behaviour extends without rewrites. A Vehicle knows which spot types it can occupy; a ParkingSpot knows whether it is free and what fits. Sketch the change against the high-level design above and tie your choice back to the requirements you clarified, rather than reaching for the most complex option.
- How do you support reservations from an app?
- Spot assignment and fee calculation are exactly where requirements churn, so isolate them behind strategy interfaces. A SpotAssignmentStrategy can be nearest-to-entrance, fill-by-level, or best-fit by size, swappable without touching the lot. Sketch the change against the high-level design above and tie your choice back to the requirements you clarified, rather than reaching for the most complex option.
- How would you model EV charging spots with their own pricing?
- Even though the scale is small, two cars can reach the entrance at once, so assigning a spot must be atomic: reserve-then-confirm, or guard the free-spot pool with a lock, so the same spot is never handed to two vehicles. Keep availability counts derived from spot state (or carefully kept consistent with it) to avoid drift. Sketch the change against the high-level design above and tie your choice back to the requirements you clarified, rather than reaching for the most complex option.
- How does the design change for a chain of lots across a city?
- Model vehicles and spots as class hierarchies (or enums plus a fit-rule) so behaviour extends without rewrites. A Vehicle knows which spot types it can occupy; a ParkingSpot knows whether it is free and what fits. Sketch the change against the high-level design above and tie your choice back to the requirements you clarified, rather than reaching for the most complex option.