If you remember five things
This is a method, not a template. Everything below is the defense of these five moves.
- Scope before you type. Spend the first five minutes on nouns, verbs, and what you are leaving out. A wrong first model costs you ten minutes you never get back.
- Nouns become classes, verbs become methods. The hard part is the relationships between them. Get ownership right and the design almost writes itself.
- Put behavior next to data. A `ParkingSpot` that cannot tell you whether a vehicle `fits` should not exist. Tell, Don't Ask beats anemic data bags.
- A pattern must name the change it absorbs. "Pricing will change, so pricing is a Strategy" is good. "I added a Factory because factories are good" fails you.
- Name concurrency even if you do not solve it. "Two threads could grab the same spot here, so I would guard this." At senior and staff level this one line is often the deciding signal.
1The problem it solves#
The trap is the open-ended prompt. The interviewer hands you "Design a parking lot" and stops. No constraints, no class list, no hint about how far to go.
Most candidates do one of two bad things:
- Start typing
class ParkingLot {within thirty seconds, before they know what they are building. - Freeze, because the problem feels enormous and the whiteboard is blank.
Both lose points, and in a timed round both are expensive.
What the round actually tests is a single question: can you take ambiguity and produce a design that is correct, extensible, and small enough to explain in 45 minutes? You are graded on judgment, not typing speed:
- Can you pick the right objects?
- Do you know when to stop adding features?
- Can you defend a decision when I push back with "what if pricing changes next quarter"?
A good approach kills the panic. It gives you a sequence to follow so you are never staring at a blank board wondering what comes next. I treat the first five minutes as pure scoping and I say so out loud, because that one sentence buys me room to think.
I start scoring before you draw a single box. The candidate who says "let me pin down scope first, I am leaving payments out unless you want them" has already told me they have done this for real. The one who opens a code editor and types a class name has told me the opposite. Narrate the plan, then execute it.
2The idea (mental model)#
Think of LLD as four passes over the same problem, each one narrower than the last.
- Scope. Agree on what you are building and what you are ignoring. Nouns and verbs. Budget five minutes.
- Model. Turn the nouns into classes and the verbs into methods. Draw relationships. Budget ten.
- Behavior. Walk one real flow end to end. Make the objects talk. Budget ten to fifteen.
- Stress. Poke at your own design. Concurrency, a new feature, an edge case. Show you see the cracks. Whatever time is left.
That is the whole thing. Every strong interview I have seen follows this shape, even when the candidate never named it.
The mental hook:
- Nouns become classes.
- Verbs become methods.
- The hard part, and where points are won or lost, is the relationships between them.
The one principle under all of it is the Single Responsibility Principle: one class, one reason to change. If I cannot say in one sentence what a class is responsible for, it is doing too much.
They turn a scary open prompt into a checklist you can run on autopilot. You stop improvising and start executing a known sequence, which is exactly what keeps you calm and talking. The interviewer reads that composure as experience, because it is.
3Structure#
Make it concrete with a parking lot, the classic warm-up. Say I have scoped it to: multiple floors, three vehicle sizes, a ticket on entry, pay on exit, assign the nearest free spot that fits.
- Nouns jump out:
ParkingLot,Floor,ParkingSpot,Vehicle,Ticket. - Verbs: park, unpark, calculate fee.
- Relationships are where candidates get sloppy, so slow down here.
The relationships, said out loud as I draw:
- A
ParkingLothas floors, and those floors die with the lot: that is composition. - A
Floorcontains spots: composition again. - A
Spotreferences aVehiclewhen occupied but does not own it: a loose association. CarandTruckare kinds ofVehicle: inheritance.
Say the words while you draw. "The lot owns its floors. A spot just points at whatever vehicle is sitting in it." That running commentary is half your score. The distinction between composition (filled diamond, owned lifecycle) and association (plain arrow, borrowed reference) is exactly the judgment I am listening for.
Why the diagram earns its keep:
- It makes the ownership rules visible instead of implied.
- It gives both of you something to point at while you talk.
- I draw this by hand in a real interview: boxes and arrows, no fancy tooling.
4Implementation in Java#
Now turn the diagram into code. I do not write every getter. I write the parts that show the design decisions: how a spot gets chosen, how the fee is computed, where the strategy lives.
enum SpotSize { SMALL, MEDIUM, LARGE }
abstract class Vehicle {
final String plate;
final SpotSize size;
Vehicle(String plate, SpotSize size) {
this.plate = plate;
this.size = size;
}
}
class Car extends Vehicle {
Car(String plate) { super(plate, SpotSize.MEDIUM); }
}
class Truck extends Vehicle {
Truck(String plate) { super(plate, SpotSize.LARGE); }
}
class ParkingSpot {
final SpotSize size;
private Vehicle current;
ParkingSpot(SpotSize size) { this.size = size; }
boolean fits(Vehicle v) { return current == null && v.size.ordinal() <= size.ordinal(); }
void assign(Vehicle v) { this.current = v; }
void release() { this.current = null; }
}
class Floor {
final int level;
private final List<ParkingSpot> spots;
Floor(int level, List<ParkingSpot> spots) {
this.level = level;
this.spots = spots;
}
Optional<ParkingSpot> findSpot(Vehicle v) {
return spots.stream().filter(s -> s.fits(v)).findFirst();
}
}
class Ticket {
final String id;
final long entryTime;
final ParkingSpot spot;
Ticket(String id, ParkingSpot spot) {
this.id = id;
this.entryTime = System.currentTimeMillis();
this.spot = spot;
}
}
interface FeeStrategy {
double fee(long entryTime, long exitTime);
}
class HourlyFee implements FeeStrategy {
public double fee(long entryTime, long exitTime) {
long hours = Math.max(1, (exitTime - entryTime) / 3_600_000);
return hours * 40.0;
}
}
class ParkingLot {
private final List<Floor> floors;
private final FeeStrategy feeStrategy;
ParkingLot(List<Floor> floors, FeeStrategy feeStrategy) {
this.floors = floors;
this.feeStrategy = feeStrategy;
}
synchronized Ticket park(Vehicle v) {
for (Floor f : floors) {
Optional<ParkingSpot> spot = f.findSpot(v);
if (spot.isPresent()) {
spot.get().assign(v);
return new Ticket(UUID.randomUUID().toString(), spot.get());
}
}
throw new IllegalStateException("lot full");
}
synchronized double unpark(Ticket t) {
double fee = feeStrategy.fee(t.entryTime, System.currentTimeMillis());
t.spot.release();
return fee;
}
}
Three things I would point out to the interviewer as I write this:
FeeStrategyis the Strategy pattern, an interface because pricing always changes: flat rate today, surge pricing tomorrow, free first hour next quarter. I will not hardcode a pricing rule into the lot. I inject the strategy through the constructor, which is Dependency Inversion in practice:ParkingLotdepends on theFeeStrategyabstraction, never onHourlyFeedirectly.- The fee math is deliberate:
3_600_000milliseconds per hour, with a one-hour minimum viaMath.max(1, ...)at 40.0 per hour, so a 10-minute stay still costs 40. parkandunparkaresynchronizedbecause two cars can hit the entrance at the same instant and I do not want to hand the same spot to both. That one word opens the concurrency conversation, which I want.
Writing park without synchronized and never mentioning it. If two threads both call findSpot before either calls assign, they get the same free spot and you have double-booked it. Saying nothing reads as not seeing it. Even better than the lock: flag its limit before I do. A single synchronized lock serializes the whole lot, so at real scale I would move to a lock per floor, or a lock-free scan with an atomic claim on the spot.
5A real-world example#
This exact shape shows up everywhere once you see it. Swap the nouns and the structure survives.
Cinema seat booking is the same skeleton.
TheaterownsScreens, a screen hasSeats, aBookingreferences the seats it holds.- "Hold a seat under concurrency" is identical to "hand out one parking spot."
- The one twist: a seat hold is usually time-boxed, released after 5 minutes if payment does not land, which adds a little state the parking lot never needed.
An elevator reuses the strategy idea.
- The lot had a
FeeStrategy; the elevator has aSchedulingStrategythat decides which car answers a call: nearest-car today, energy-saving mode at night. - Same move: pull the decision that changes into its own interface.
- It also leans on the State pattern, since a car behaves differently when idle, moving up, or moving down.
Even Splitwise fits.
Groupowns members, anExpensereferences who paid and who owes.- The split logic (equal, exact, percentage) is a strategy.
The takeaway I give candidates: master two prompts, the parking lot and one stateful one like a vending machine, and you have covered roughly 80 percent of what gets asked. Internalize one well-modeled problem and you can reshape it into most of the others.
6When to use it, and when not to#
Use the four-pass approach for any LLD or object-oriented design round.
- It scales from a forty-minute screen to a long onsite.
- If the prompt is a single class or an algorithm with a clear signature, skip the ceremony and just code. This method is for open-ended design.
Do not over-apply the patterns. Strategy, factory, observer: these are tools, not trophies.
- I have watched candidates bolt an
AbstractParkingSpotFactoryBuilderonto a problem that needed three plain classes. That hurts you and burns minutes you will miss later. - Reach for a pattern only when you can name the change it absorbs. "Pricing will change, so pricing is a Strategy." Good. "I added a Factory because factories are good." Bad.
- This is the YAGNI principle doing real work: you are not gonna need the abstraction until the second variation shows up.
Reveal the answer
When in doubt, build the simplest thing that satisfies the scope you agreed on, then let me ask for more. I would rather see a clean small design you can extend than a sprawling one you cannot finish.
7Common mistakes#
Coding before scoping. The number one failure. You design the wrong thing beautifully. Spend the first five minutes on nouns, verbs, and what is out of scope. "I am leaving payments out unless you want them" signals seniority on its own.
Anemic classes. Data bags with only getters and setters, and all the logic sitting in one giant service. If ParkingSpot cannot tell me whether a vehicle fits, why does it exist? Put behavior next to the data it touches. That is the Tell, Don't Ask principle.
God objects. One ParkingLotManager that does everything. Spread responsibility: a floor should find its own spot. A God object is a Single Responsibility violation wearing a cape.
Ignoring concurrency. Even if you do not fully solve it, name it. "Two threads could grab the same spot here, so I would guard this." Saying nothing reads as not seeing it, and at senior and staff level this is often the deciding signal.
Enum-driven type checks. Writing if (vehicle.type == CAR) all over the place instead of using polymorphism. If you are branching on a type field everywhere, your inheritance is in the wrong spot. It is also an Open-Closed violation: every new vehicle type forces you to edit every one of those branches.
Going silent. You stop narrating and just think. I cannot score silence. Think out loud, even the dead ends.
The interviewer scores what you say, not what you think. Silence is an unforced error.
8Where it shows up in interviews#
Almost every company that runs an LLD round reaches for one of a dozen classic prompts.
- The usual suspects: parking lot, elevator, vending machine, cinema booking, Splitwise, rate limiter, a card game, a logging library.
- Who asks: Amazon, Uber, and most senior and staff loops at India-based product companies run at least one.
- At staff level the follow-ups get sharper, usually concurrency and extensibility.
A strong runtime flow usually seals it. After the class diagram, I love when a candidate walks me through one request. Here is the park flow I expect someone to narrate:
When you can draw the classes, write the key methods, and then trace a single call through the objects, you have shown the whole loop. That is what gets a yes from me. Keep it simple, scope it first, and never stop talking.
"Two cars reach the entrance at the same instant. What stops a double-booking?"
"Pricing changes next quarter to free-first-hour, then surge. How much rework?"
"Add electric-vehicle spots with charging. Where does that go?"
"Why Strategy for the fee but not a Factory for the vehicles here?"
"How would you unit test the fee logic?"
What you can now explain in the room
- The four-pass method (scope, model, behavior, stress) and roughly how many minutes each gets.
- Why nouns become classes and verbs become methods, and why relationships are the hard part.
- The difference between composition and association, and how to show it on a diagram with arrow shapes.
- Where the Strategy pattern belongs and how injecting it gives you Dependency Inversion for free.
- How to raise concurrency with `synchronized`, and why one lock on the whole lot does not scale.
- Why a finished small design beats an abandoned large one, and how to resist pattern-stuffing with YAGNI.
Next, try the same method on a vending machine or an elevator, and read up on the Strategy and State patterns since they carry most LLD prompts.
Get a prep plan built around your How to Approach an LLD Interview interview
Tell us the role and your interview date. We will send back a dated, day by day plan. Free.