Loading learning content...
The Parking Lot System stands as the quintessential low-level design problem—a deceptively simple domain that reveals whether a candidate truly understands object-oriented design, pattern application, and systematic problem-solving. It appears in technical interviews at companies like Google, Amazon, Microsoft, and countless startups not because parking lots are particularly exciting, but because the problem domain is universally understood while offering remarkable depth for design exploration.
Why requirements analysis comes first:
Before drawing a single class diagram or writing a line of code, elite engineers invest substantial effort in understanding what they're building. This isn't bureaucratic overhead—it's the difference between a design that elegantly solves the right problem and one that perfectly solves the wrong problem.
In this page, we'll systematically analyze the parking lot domain, extract functional and non-functional requirements, and establish the foundation upon which our entire design will rest.
By the end of this page, you will master the art of requirements elicitation for LLD problems. You'll understand how to distinguish functional from non-functional requirements, how to ask clarifying questions that reveal hidden complexity, and how to document requirements in a way that directly informs your design decisions. These skills transfer to every LLD problem you'll encounter.
A parking lot, at its most fundamental level, is a facility where vehicles are temporarily stored for a fee. But this simple definition conceals remarkable complexity. Before we can design a system, we must develop deep domain understanding.
The physical reality:
A real parking lot is a spatial entity with physical constraints. It has a finite number of spaces, organized across potentially multiple floors or sections. Different spaces accommodate different vehicle types—a motorcycle spot cannot fit a truck, and an electric vehicle charging space serves a specialized purpose. Entry and exit points control traffic flow, and the physical layout determines which spots are accessible when.
The operational reality:
Beyond the physical, parking lots are businesses with operational concerns. They need to track occupancy in real-time, calculate fees based on duration and vehicle type, issue and validate tickets, handle payment processing, and generate reports for management. Peak hours demand efficient allocation, while off-peak periods might enable flexible pricing strategies.
| Concept | Physical Aspect | System Aspect | Design Implication |
|---|---|---|---|
| Parking Space | A marked area for one vehicle | Unique identifier, type, location, status | Core entity with state management |
| Vehicle | Physical machine needing space | Type, license plate, entry time | Entity with type hierarchy |
| Ticket | Paper or digital proof of entry | Unique ID, timestamps, vehicle reference | Transaction record linking vehicle to stay |
| Entry/Exit | Physical gates or barriers | Control points with sensors | Boundary where system interacts with reality |
| Floor/Section | Physical organization of space | Grouping mechanism for spots | Hierarchical structure for navigation |
| Rate | Pricing policy | Calculation rules per time/vehicle type | Strategy pattern opportunity |
Notice how we're building a vocabulary of the domain before touching any code concepts. This ubiquitous language—shared between business stakeholders and developers—becomes the naming convention for our classes, methods, and variables. When your code speaks the language of the domain, it becomes self-documenting and intuitive to extend.
In an interview or real-world scenario, requirements are never handed to you on a silver platter. The ability to ask incisive clarifying questions separates exceptional engineers from those who make dangerous assumptions.
The meta-skill of question-asking:
Good questions serve multiple purposes: they reveal hidden complexity, they demonstrate your systematic thinking, they give you control over the problem's scope, and they build rapport with the interviewer. The goal isn't to ask every possible question—it's to ask the right questions that disambiguate critical design decisions.
Sample interview dialogue:
You: "Before I start designing, I'd like to understand the scope. Should I design for a single parking lot or a system managing multiple lots?"
Interviewer: "Let's focus on a single lot for now, but design it so we could extend to multiple lots."
You: "Great. What vehicle types should we support?"
Interviewer: "Motorcycles, cars, and larger vehicles like buses."
You: "Should a motorcycle be able to park in a car spot if all motorcycle spots are full?"
Interviewer: "Interesting question. Let's say yes, but we should prefer motorcycle spots for motorcycles."
You: "For pricing, is this hourly, daily, or both? And does it vary by vehicle type?"
Interviewer: "Hourly for now, with different rates per vehicle type."
Notice how each question narrows the design space and reveals requirements that weren't initially stated. The interviewer's responses become your documented requirements.
In a 45-minute interview, spend at least 5 minutes on requirements clarification. It feels counterintuitive—you want to show you can design! But interviewers explicitly evaluate your ability to scope problems. A well-scoped design is infinitely better than a sprawling, half-finished one.
Functional requirements describe what the system must do—the behaviors and features users directly experience. After our clarifying conversation, we can document these with precision.
The difference between good and great requirements:
A novice might write: "The system should park cars." This is a starting point, but it leaves too much ambiguity. Great requirements are testable—you can objectively verify whether the system satisfies them. They specify the actor, the action, and the expected outcome.
Organizing requirements by actor:
Another powerful technique is grouping requirements by who initiates them:
| Actor | Capability | System Response |
|---|---|---|
| Vehicle/Driver | Enter parking lot | Allocate spot, issue ticket, open gate |
| Vehicle/Driver | Exit parking lot | Calculate fee, process payment, free spot, open gate |
| Parking Attendant | Check availability | Return counts by type/floor |
| Parking Attendant | Manual override | Assign specific spot, handle exceptions |
| System Administrator | Configure rates | Update pricing rules |
| System Administrator | View reports | Generate occupancy/revenue reports |
| Automated System | Monitor capacity | Update displays, close entry when full |
For an interview, focus on the core flow: vehicle entry, spot allocation, exit, and payment calculation. Mention that you're aware of admin features and reporting but will defer those to keep the design focused. This demonstrates prioritization—a key engineering skill.
Non-functional requirements (NFRs) describe how the system should behave—the quality attributes that cut across all features. While often overlooked in LLD discussions, NFRs profoundly influence design decisions.
Why NFRs matter for LLD:
Consider a parking lot with a single entry point versus one with ten simultaneous entry points. The functional requirements might be identical, but the concurrency NFR drives you toward thread-safe data structures, perhaps even a different architectural approach entirely. NFRs are the invisible forces shaping your design.
Notice how NFR-4 and NFR-5 directly point to design patterns: Strategy for pricing, Factory for vehicle/spot creation. NFR-1 suggests synchronized data structures or optimistic locking. Great engineers trace their pattern choices back to specific requirements.
Use cases describe end-to-end scenarios from the user's perspective. They're more narrative than requirements lists and help verify that your design covers complete workflows.
The primary use cases:
Use Case: Vehicle Entry================================Actor: DriverPrecondition: Parking lot is not full for the vehicle typeTrigger: Vehicle arrives at entry gate Main Flow:1. Driver presses button or ticket is auto-detected2. System checks availability for vehicle type3. System allocates the best available spot4. System generates a ticket with: - Unique ticket ID - Entry timestamp - Allocated spot location - Vehicle type5. System prints/displays ticket6. Entry gate opens7. System updates spot status to OCCUPIED8. System updates capacity counters Alternative Flows:- 2a. No suitable spots available: - System displays "FULL" message - Gate remains closed - Use case ends - 3a. Vehicle type can use larger spot: - System allocates larger spot with explanation Postcondition:- Ticket issued- Spot marked as occupied- Capacity updatedDeriving methods from use cases:
Each step in a use case often maps to a method or responsibility in your design:
| Use Case Step | Probable Class | Method Signature |
|---|---|---|
| Check availability for vehicle type | ParkingLot | hasAvailableSpot(vehicleType): boolean |
| Allocate best available spot | ParkingLot / SpotAllocator | allocateSpot(vehicleType): ParkingSpot |
| Generate ticket | TicketService / Factory | issueTicket(vehicle, spot): Ticket |
| Calculate parking duration | Ticket | getDuration(): Duration |
| Apply pricing rules | PricingStrategy | calculateFee(ticket): Money |
| Mark spot as available | ParkingSpot | vacate(): void |
This traceability from use case to class responsibility is what distinguishes ad-hoc design from systematic engineering.
Every design exists within constraints and is built upon assumptions. Making these explicit prevents misunderstandings and documents the boundaries of your design.
When assumptions break, bugs appear. By documenting 'Vehicle type declared at entry matches actual vehicle,' you're acknowledging that your design doesn't handle fraud detection. When product asks for fraud detection later, you know exactly where in the design to add it—at the entry flow, before ticket issuance.
Before moving to entity identification, let's preview how our requirements will drive design decisions. This forward-looking analysis demonstrates the systematic thinking interviewers value.
| Requirement | Design Implication | Pattern/Approach |
|---|---|---|
| FR-1: Multiple vehicle types | Vehicle class hierarchy | Inheritance + Type enumeration |
| FR-2: Multiple spot types | ParkingSpot class hierarchy | Inheritance + Type enumeration |
| FR-4: Prefer smallest suitable spot | Smart allocation algorithm | Strategy pattern for allocation |
| FR-6: Calculate fee by duration/type | Pricing encapsulation | Strategy pattern for pricing |
| NFR-1: Concurrent operations | Thread-safe spot management | Synchronized collections or locking |
| NFR-2: O(1) or O(log n) allocation | Efficient data structures | HashMap/TreeMap for spot lookup |
| NFR-4: Extensible types | Open for extension | Factory pattern for creation |
| NFR-6: No double-allocation | Atomic state transitions | Transactional spot status updates |
This traceability matrix serves multiple purposes:
The insight to internalize:
Patterns like Strategy and Factory aren't decorative—they're the natural solution to requirements demanding flexibility and extensibility. When someone asks "Why did you use Factory here?", the answer isn't "Because it's a common pattern." The answer is "Because FR-1 requires multiple vehicle types, NFR-4 requires extensibility, and Factory gives us both while keeping creation logic centralized."
We've completed the most critical phase of the design process—understanding what we're building before we build it.
What's next:
With requirements in hand, we're ready to identify the core entities that will form the backbone of our design. In the next page, we'll systematically extract Vehicle, ParkingSpot, Ticket, and ParkingLot—defining their attributes, behaviors, and responsibilities.
You now have a comprehensive requirements specification for the Parking Lot System. This foundation will guide every subsequent design decision. In the next page, we identify and model the core entities that bring these requirements to life.