DEV Community

Cover image for Designing a parking lot: the low-level design interview, explained
Gowtham Potureddi
Gowtham Potureddi

Posted on

Designing a parking lot: the low-level design interview, explained

Designing a parking lot: the low-level design interview, explained

"Design a parking lot" is the most common opener in a low-level design interview, and it is deceptively easy to start and surprisingly easy to fail. The trap is treating it as a coding problem — there is no algorithm to crack and no test cases to pass. What the round is really testing is object-oriented design: can you turn a fuzzy real-world problem into a clean set of classes, draw the relationships between them, decide where behaviour lives, and keep the design open to change when the interviewer adds a requirement five minutes in? The parking lot is a favourite precisely because everyone understands the domain, so there is nowhere to hide — the whole conversation is about the quality of your model.

This guide walks the parking lot the way a strong candidate works it in an LLD / OOD interview: clarify the requirements first, identify the core entities, sketch the classes and the key methods, and then defend the handful of decisions the interviewer always pushes on — how a car gets assigned a spot, how pricing stays flexible, how a new vehicle type slots in without rewriting everything, and what happens when two cars race for the last open spot. In a low-level design round you write these classes out in an editor, not as a finished program but as a design you can explain and extend out loud, one method at a time.

Title card for a low-level design interview explainer on designing a parking lot, showing a class diagram with a ParkingLot containing Levels, each Level holding ParkingSpots of different sizes, Vehicles assigned to spots, and a Ticket linking a vehicle to its spot and entry time, with tags for the Strategy and Factory patterns, on a dark citrus-and-lavender background.

Why the parking lot comes up in low-level design interviews

The parking lot earns its place because it exercises every muscle an LLD round cares about in a domain nobody needs explained. There are obvious entities (a lot, spots, vehicles, tickets), obvious relationships (a lot has levels, a level has spots, a spot holds one vehicle), obvious variation (motorcycles, cars, trucks need different spots), and an obvious place for things to go wrong (two cars, one spot). An interviewer can watch you make a dozen modelling decisions in half an hour and see exactly how you think about structure.

The interviewer rarely lets a tidy class diagram stand on its own. "Your lot has one spot left. Two cars pull up to two different entry gates at the same moment, and both of your entry panels call assignSpot() and get handed that same last spot. Walk me through what your code does, where the race is, and how you make sure only one of those cars actually gets the spot." That question — concurrency on a shared resource — is the one a pretty diagram can never survive, and the one the parking lot is really testing once the basics are on the board.

The rounds on Zynter are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: you put a class on the board, and the next sentence out of the interviewer's mouth adds a requirement or attacks a seam — a new vehicle type, a pricing change, a full lot, or the race for the last spot.

What the interviewer is really testing

A low-level design answer is read on the same four dimensions as any design round. Problem solving — did you model the domain cleanly and keep it extensible, or hard-code assumptions that break when a requirement changes? Communication — can you justify why pricing is its own class and not an if ladder inside the ticket? Technical execution — do you handle the real edge cases (a full lot, an invalid ticket, the concurrency race), or did you design only the happy path? Time management — did you clarify and prioritise before coding, and spend your half hour on the model that matters rather than perfecting one getter? Reading this guide teaches the design; it does not teach you to defend it while someone adds "now it's a valet lot" mid-sentence.

Step 1: Clarify the requirements

The single biggest mistake in an LLD round is writing a class before asking a question. Spend the first two minutes scoping out loud — it is graded, and it stops you building the wrong thing.

Functional requirements to confirm:

  • The lot has multiple levels, and each level has a number of parking spots.
  • Spots come in sizes — motorcycle, compact, large — and a vehicle fits certain sizes (a car takes a compact or large spot; a truck needs large).
  • A vehicle is issued a ticket on entry and the system assigns it a spot; the ticket records the spot and entry time.
  • On exit, the system calculates a fee (typically by duration) and frees the spot.
  • The system can report availability — how many spots of each type are free.

Non-functional / constraints to surface (this is where senior candidates separate themselves):

  • Extensibility — new vehicle types and new pricing rules should be addable without rewriting existing classes.
  • Concurrency — multiple entry and exit gates operate at once, so spot assignment must be safe when two vehicles compete for the last spot.
  • Scope boundaries — are we handling payments and change, reservations, a valet flow? Agree what is in and out, out loud, so you are not marked down for "missing" something you deliberately deferred.

State your assumptions explicitly: "I'll assume a fixed set of spot sizes, pricing by the hour, and payment handled by a separate component I'll stub — tell me if you want reservations in scope." That one sentence shows you prioritise, which is itself part of the score.

Step 2: Identify the core entities

With requirements agreed, name the classes before writing any. The nouns in the problem are your first draft of the object model:

  • ParkingLot — the top-level object (often a singleton); owns the levels and is the entry point for parkVehicle / unparkVehicle.
  • Level (or ParkingFloor) — owns a collection of spots and knows its own availability.
  • ParkingSpot — a single spot with a size/type, whether it is free, and the vehicle currently in it.
  • Vehicle — an abstract base with concrete Motorcycle, Car, Truck; each knows which spot sizes it can use.
  • Ticket — links a vehicle to its assigned spot, records entry time, and later the exit time and fee.
  • EntryPanel / ExitPanel (gates) — the interface to the outside world; an entry panel issues a ticket, an exit panel takes payment and opens the gate.
  • PricingStrategy — how a fee is calculated, kept separate so it can vary.
  • Payment — a stub for the transaction on exit.

Naming the relationships out loud matters as much as the classes: a ParkingLot has many Levels (composition), a Level has many ParkingSpots, a ParkingSpot holds zero or one Vehicle, and a Ticket references one vehicle and one spot. That "has-a" vocabulary is what an interviewer listens for.

A class diagram for a parking lot low-level design, showing a ParkingLot composed of multiple Level objects, each Level holding many ParkingSpot objects with a size enum, an abstract Vehicle base class with Motorcycle, Car and Truck subclasses, a Ticket class referencing a vehicle and a spot with entry and exit times, and a separate PricingStrategy interface, with the has-a and is-a relationships drawn as composition and inheritance arrows.

Step 3: Sketch the classes

Now write the classes — as skeletons you can talk through, not a finished program. Lead with the enums and the abstract types, because they carry the design decisions.

enum VehicleType { MOTORCYCLE, CAR, TRUCK }
enum SpotSize { MOTORCYCLE, COMPACT, LARGE }

abstract class Vehicle {
    protected String licensePlate;
    protected VehicleType type;
    // which spot sizes can this vehicle use? (decided per subclass)
    public abstract boolean canFitIn(SpotSize size);
}

class Car extends Vehicle {
    public boolean canFitIn(SpotSize size) {
        return size == SpotSize.COMPACT || size == SpotSize.LARGE;
    }
}

class ParkingSpot {
    private String id;
    private SpotSize size;
    private boolean free = true;
    private Vehicle vehicle;

    public synchronized boolean assign(Vehicle v) {
        if (!free || !v.canFitIn(size)) return false;
        this.vehicle = v;
        this.free = false;
        return true;
    }
    public synchronized void release() {
        this.vehicle = null;
        this.free = true;
    }
}

class Ticket {
    private String id;
    private Vehicle vehicle;
    private ParkingSpot spot;
    private Instant entryTime;
    private Instant exitTime;   // set on exit
    // fee is computed by a PricingStrategy, not here
}

interface PricingStrategy {
    double calculate(Ticket ticket);   // e.g. by duration and vehicle type
}

class ParkingLot {
    private List<Level> levels;
    private PricingStrategy pricing;

    public Ticket parkVehicle(Vehicle v) {
        ParkingSpot spot = findSpot(v);          // first fit across levels
        if (spot == null) throw new LotFullException();
        if (!spot.assign(v)) return parkVehicle(v); // lost the race, retry
        return new Ticket(v, spot, Instant.now());
    }

    public double unparkVehicle(Ticket t) {
        double fee = pricing.calculate(t);        // Strategy decides the number
        t.getSpot().release();
        return fee;
    }
}
Enter fullscreen mode Exit fullscreen mode

Talk through the choices as you write them: pricing lives behind a PricingStrategy interface so a weekend rate or a flat fee is a new class, not an edit to Ticket; canFitIn lives on the Vehicle so adding a Truck does not touch the spot logic; and assign / release are synchronized because that spot is a shared resource — which sets up the concurrency conversation.

Step 4: The design decisions interviewers probe

The diagram is the easy half. The follow-ups live in a handful of decisions, and having an answer ready for each is what the round rewards.

  • Spot assignment — how do you find a spot for a vehicle? The simplest is first fit: scan levels for the first free spot the vehicle can use. If the interviewer pushes on efficiency ("the lot has 10,000 spots"), move to keeping a per-size structure — for example a set or priority queue of free spots per SpotSize per level — so assignment is O(1) rather than a linear scan. Name the simple version first, then the optimisation.
  • Pricing — resist the urge to put a fee formula inside Ticket. Use the Strategy pattern: a PricingStrategy interface with HourlyPricing, FlatRatePricing, WeekendPricing implementations, chosen at runtime. When the interviewer says "now trucks are charged differently," you add a class; you do not reopen Ticket.
  • Extensibility (open/closed) — adding a Bus or an ElectricCar (which needs a charging spot) should mean a new Vehicle subclass and perhaps a new SpotSize, not edits scattered through the lot. If a new requirement forces you to change five existing classes, your boundaries are wrong — say that out loud and adjust.
  • Concurrency — the race for the last spot — this is the follow-up from the opening scenario, and the one most candidates miss. Two gates call parkVehicle at once and both find the same last free spot. The fixes to name: make the spot's assign atomic (synchronised, or a compare-and-set on the free flag) so exactly one caller wins and the loser retries or is told the lot is full; or serialise assignment through a thread-safe pool of free spots that hands each spot to one caller. The key insight to state: the free/occupied flag is shared mutable state, so the check-and-set must be atomic — otherwise two tickets point at one spot.
  • Edge cases — a full lot (throw or return "no spot"), an invalid or lost ticket, a vehicle that never exits, and payment failure on exit. You will not design all of them; naming them shows you see past the happy path.

A diagram of the parking lot design decisions, showing spot assignment moving from a linear first-fit scan to per-size free-spot pools for O(1) lookup, a PricingStrategy interface with hourly, flat-rate and weekend implementations selected at runtime, and the concurrency race where two entry gates call assignSpot on the same last free spot, resolved by an atomic compare-and-set on the spot so only one caller wins and the other retries.

Low-Level Design
LLD · Parking Lot
Design the parking lot and defend the race for the last spot out loud

Practise on Zynter →

Design patterns that fit the parking lot

You do not need to force patterns in, but naming the ones that fit — and why — is a strong signal in an OOD round.

  • Strategy — pricing. A PricingStrategy interface lets the fee calculation vary independently of the ticket and the lot. The cleanest, most reused pattern in this problem.
  • Factory — vehicle and spot creation. A VehicleFactory that turns a type into the right subclass keeps new Car() / new Truck() out of the business logic and centralises the "which class" decision.
  • Singleton — the ParkingLot itself is often a single shared instance for the whole building; note the trade-off that a singleton can complicate testing and must be thread-safe.
  • Observer — an availability display board that updates when spots fill or free can subscribe to the lot as an observer, so the lot does not need to know about the screens.

Say it crisply: Strategy for pricing is the one that pays off most; Factory keeps object creation tidy; Singleton models the single physical lot but I'd keep it thread-safe and injectable for tests. Naming the trade-off, not just the pattern, is what reads as experience.

A diagram mapping design patterns to the parking lot, showing the Strategy pattern applied to pricing with interchangeable pricing implementations, a Factory creating the correct Vehicle subclass from a type, a Singleton ParkingLot as the single shared instance, and an Observer availability display board that updates when spots fill or free.

Low-Level Design
LLD · Core skills
Apply Strategy, Factory and Singleton out loud

Practise on Zynter →

How to talk about a low-level design in an interview

The probes from every section rhyme. Master these five and you can defend any LLD, not just the parking lot.

  • "What are the core classes here?" → Name the nouns — ParkingLot, Level, ParkingSpot, Vehicle (with subtypes), Ticket, PricingStrategy — and the relationships between them (has-a, is-a) before writing a line. (communication)
  • "Where does pricing logic live?" → Behind a PricingStrategy interface, so a new rate is a new class, not an edit to Ticket — the open/closed principle in action. (problem solving)
  • "Add a new vehicle type — what changes?" → A new Vehicle subclass and maybe a new SpotSize; if it forced edits across five classes, my boundaries would be wrong. (technical execution)
  • "Two cars race for the last spot — what happens?" → The free flag is shared mutable state, so assign must be an atomic check-and-set (synchronised or compare-and-set); one caller wins, the other retries or is told the lot is full. (technical execution)
  • "What breaks on the unhappy path?" → A full lot, an invalid or lost ticket, a vehicle that never exits, payment failure — I design the main flow and name these so the model can absorb them. (time management)

Each maps to a debrief dimension. Reading them teaches the answers; it does not teach you to deliver them while someone says "now make it a valet lot" — that only comes from saying them out loud.

How to prepare: a short plan

You do not need to memorise one reference solution. You need the OOD process automatic, so any "design X" prompt becomes requirements → entities → classes → decisions.

  • Day 1: Drill the process on the parking lot — clarify, list entities, sketch classes with relationships — until you can get a clean diagram on the board in ten minutes.
  • Day 2: Drill the decisions — spot assignment and its O(1) optimisation, Strategy for pricing, extensibility for new types, and especially the concurrency race. These are where the follow-ups live.
  • Day 3: Do it out loud, timed, with someone adding a requirement mid-answer (electric-car charging spots, a valet flow, reservations), then move to a second LLD (elevator, vending machine) to prove the process transfers.

This explainer feeds the broader low-level design interview track — the parking lot is the gateway OOD problem, and the process it teaches transfers directly to the elevator, the vending machine and the rest.

Frequently asked questions

What is a parking lot low-level design interview actually testing?

It is testing object-oriented design, not algorithms. There is no puzzle to crack or test cases to pass; instead the interviewer watches how you turn a familiar real-world problem into a clean set of classes, how you name the relationships between them, where you decide behaviour should live, and whether your design stays open to change when a new requirement is added mid-interview. The parking lot is popular precisely because everyone understands the domain, so the entire conversation is about the quality of your model — your entities, your use of abstraction and interfaces, your handling of edge cases like a full lot and the concurrency race, and your ability to justify each decision out loud.

What are the main classes in a parking lot design?

A standard model has a ParkingLot as the top-level object (often a singleton) that owns one or more Level objects; each Level owns many ParkingSpot objects, and each spot has a size and holds zero or one vehicle. Vehicle is an abstract base with Motorcycle, Car and Truck subclasses that know which spot sizes they can use. A Ticket links a vehicle to its assigned spot and records entry and exit times. Supporting classes include EntryPanel and ExitPanel (the gates), a PricingStrategy interface so fee calculation can vary, and a stubbed Payment. The key is to state the relationships — a lot has levels, a level has spots, a spot holds a vehicle — not just list the classes.

How do you handle the concurrency problem in a parking lot?

The problem is that two entry gates can try to assign the same last free spot at the same time, because a spot's free-or-occupied flag is shared mutable state. If both gates read "free" before either writes "occupied," they both get the spot and you issue two tickets for one place. The fix is to make the check-and-set atomic: either synchronise the spot's assign method (or use a compare-and-set on the free flag) so exactly one caller succeeds and the other retries or is told the lot is full, or serialise assignment through a thread-safe pool of free spots that hands each spot to only one caller. Naming this explicitly — identifying the shared state and making its update atomic — is one of the strongest signals you can give in the round.

How do you make a parking lot design extensible?

You lean on the open/closed principle: the design should be open to extension but closed to modification, so adding a feature means adding a class rather than editing existing ones. Pricing goes behind a PricingStrategy interface so a new rate (weekend, flat, per-vehicle-type) is a new implementation, not a change to Ticket. A new vehicle type is a new Vehicle subclass whose canFitIn method expresses which spot sizes it uses, so the spot and lot code is untouched. If a proposed change forces edits across many existing classes, that is a signal your boundaries are drawn in the wrong place — a good candidate notices this out loud and adjusts the model rather than defending it.

Which design patterns are used in a parking lot?

The most valuable is the Strategy pattern for pricing: a PricingStrategy interface with concrete implementations lets the fee calculation vary independently of the rest of the system. A Factory pattern is a natural fit for creating the right Vehicle or ParkingSpot subclass from a type, keeping object-creation decisions out of the business logic. The ParkingLot is often modelled as a Singleton because it represents a single physical building, though you should note that a singleton can complicate testing and must be made thread-safe. An Observer pattern fits an availability display board that updates as spots fill and free. The point in an interview is to name the pattern and the trade-off, not to force patterns in where they add no value.

How do I practise a low-level design interview out loud?

Reading a parking lot solution is not the same as defending your class boundaries while an interviewer adds a valet flow or pushes on the concurrency race. On Zynter, the LLD track runs live voice rounds modelled on how real low-level design loops run — you write your classes and methods in the editor and a voice interviewer follows up one question at a time ("where does pricing live?", "two cars just raced for the last spot — what happens?", "now add electric-car charging spots"), then gives you a debrief on problem solving, communication, technical execution and time management. The score is a practice signal, not a hiring decision.

Practise it on Zynter

You can draw the class diagram. The round is won on defending the race for the last spot out loud.

Pick the Parking Lot low-level design round, write your classes in the editor, and defend them out loud to a voice interviewer that keeps asking "where does pricing live?" and "two cars just raced for the last spot — what does your code do?" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the low-level design track (Sep 2026).

Practise the Parking Lot LLD round →
Browse all interview tracks

Top comments (0)