Essay
How to Approach LLD Interviews — Start Here
New to low-level design interviews? Learn why this round matters, a five-step approach you can reuse on any problem, and a full Parking Lot walkthrough in plain English you can understand on the first read.
TL;DR: Low-level design interviews ask you to turn a vague product request into clear pieces of code that each have one job, then show that the main path works. Use a five-step loop — clarify what to build, name the pieces, say how they connect, write the method names, then implement — and practice it on one timed problem. This guide walks through Parking Lot end to end without career-stage labels or unexplained jargon.

Use the same five steps on every low-level design prompt: agree on the problem, name the pieces, connect them, write the method names, then code.
You get the prompt: “Design a parking lot.” Your first instinct is often to open the editor and start typing something like class ParkingLot, because writing code feels productive and the clock is already running. Ten minutes later you may have one oversized class, three half-finished methods, and no clear story you can tell the interviewer about how the pieces fit together.
That moment is exactly what low-level design interviews are built to surface. The interviewer is not asking you to invent a new programming language. They are asking whether you can take a fuzzy product request and turn it into small pieces of software that each have one clear job, then show that the main path through the product works.
If you are new to this kind of interview, start here. This page explains what the round is asking for, why companies care about it, a five-step approach you can reuse on almost any prompt, and one full example — Parking Lot — with a detailed solution written in plain English. When you finish reading, practice on Practice LLD.
What LLD is (in simple words)
Low-level design means designing the shape of the code for a feature: which pieces exist (often called classes or modules), what each piece is responsible for, how those pieces call or contain each other, and which method names other code will use to talk to them.
In the interview room it feels a lot like sitting next to another engineer and designing a small product together. You start by agreeing on what to build. You sketch the model on a board or in a document so both of you can see it. You write code that matches that model. Then the interviewer often asks a follow-up such as “what if we add spots for electric vehicles?” or “what if the fee rules change?” to see whether your design can bend or whether everything has to be rewritten.
What this round is: designing objects and methods under time pressure, with clear names, clear jobs, and a working main path — for example park a vehicle, get a ticket, leave, and compute the fee — before you chase every rare case.
What this round is not: full system design. You usually do not spend this interview drawing load balancers, databases spread across many regions, or a content network for images. Those questions belong in system design interviews.
A simple side-by-side picture helps:
| LLD (this guide) | System design | |
|---|---|---|
| Main question | How do I structure the code for this feature? | How does the whole product handle many users and growth? |
| Building blocks | Classes, methods, and in-memory structures | Services, databases, caches, and queues |
| Typical prompt | Parking lot, cache, expense splitter | URL shortener, news feed, chat |
| What you deliver | A design story plus working code | An architecture sketch plus trade-offs |
If you mix the two, you can waste time drawing servers when the interviewer was waiting for a clear Ticket piece and a park method.
Why LLD interviews matter
Companies use this round because most engineering work day to day is writing and changing code for features, not inventing a worldwide network on the first day. Low-level design is a compressed version of that job: take a vague ask, break it into pieces, and leave the code in a shape that can grow when rules change.
Here is what interviewers are usually checking for.
Can you break a problem into pieces? Real features almost never stay as one file forever. A parking system that mixes “find a spot,” “create a ticket,” and “compute a fee” inside a single class becomes painful the first time pricing rules change, because every change risks breaking parking and tickets at the same time.
Can you name responsibilities? Each piece should answer a simple question: What am I responsible for? If the honest answer is “everything,” the design is not finished yet, even if the code compiles.
Can you leave room to grow? Interviewers often add a small extension such as “add reserved spots.” Strong answers change one place — for example how a spot decides whether a vehicle fits — instead of rewriting half the file.
Can you talk while you design? Coding in silence for a long stretch looks like guessing. Saying something like “a floor owns many slots, and the parking lot finds a free slot of the right size” shows that you have a plan the interviewer can follow and challenge.
You do not need a long war story from production to do well. You need a habit: think in pieces and jobs before you type large amounts of code.
What interviewers pay attention to
Companies use different score sheets, but the same four signals show up again and again.
1) Clarifying before coding
Do you ask what is in scope for this version? Do you state assumptions out loud so the interviewer can correct you early? A short spoken contract such as “I will support bike, car, and truck; one entry path for now; fee based on vehicle type and hours parked” is usually enough to start. Jumping into code with no shared picture of the problem is one of the fastest ways to lose an otherwise friendly interviewer, because they cannot tell whether you are solving the problem they care about.
2) A coherent model (not a pile of classes)
The pieces should connect in a story you can tell in about a minute. For parking, that story might be: a parking lot has floors, a floor has slots, a vehicle parks in a slot and receives a ticket. If the interviewer cannot repeat your model back to you in their own words, it is still too fuzzy, even if you have many class names on the board.
3) Clear method names that others can call
The public methods — the ones other code would call — should be small and easy to test, such as park(vehicle), unpark(ticketId), and getAvailability(). Hide the messy details inside private helpers that callers never need to see. Interviewers often read method names the way they read a short README: if the names tell a clear story, they already trust the design more.
4) Code that matches the design you described
Your implementation should look like the story you told. If you said fee calculation lives in its own piece, do not bury fee math inside park(). When talk and code match, the interviewer can follow you; when they diverge, it looks like the design was only decoration.
A five-step approach you can reuse
This matches the structured thinking guide on Practice LLD. You can use the same loop on Parking Lot, Elevator, an LRU cache, expense sharing, and most other machine-coding prompts.
Picture a round of about forty-five to fifty-five minutes:
| Time | Focus |
|---|---|
| First ~8 minutes | Clarify the problem and list the main pieces |
| Next ~7 minutes | Say how pieces connect and write method names |
| Middle of the round | Code the main path end to end |
| Last 5–10 minutes | Edge cases, future rules, and what you would improve |
Step 1: Clarify requirements
Turn the vague prompt into a short shared contract. Ask questions, or decide and say your decisions out loud so the interviewer can push back.
Useful questions include: Who uses this system — drivers, staff at the garage, or both? What must work in the first version — park, leave, fee, and a view of free spots? What is clearly out of scope for now — real payment, a mobile app screen, or a chain of garages in many cities? Which types matter — bike, car, truck, and matching spot sizes? Which rules might change later — electric-vehicle spots, reserved spots, or surge pricing — so you leave a place for them without building them yet?
Write four to six bullets. That list becomes your north star. If a feature is not on the list, do not build it in the first pass, because extra scope is how people run out of time with a broken main path.
Step 2: Identify the core pieces (the nouns)
List the things that exist in the problem — the nouns — such as vehicle, slot, floor, ticket, and parking lot. For most of these problems you want roughly three to seven main pieces. Fewer than three often means you mashed several jobs into one place. More than seven early on often means you split too finely before the main story was clear.
For each noun, ask: What is this responsible for? If two nouns share the same job, merge them until each piece has a single clear answer.
Step 3: Define how the pieces connect
Say how objects relate in ordinary language. A floor has many slots (the slots belong to that floor). The parking lot uses a fee calculator when someone leaves (the calculator does not own the parking lot; it helps with one job). A car is a kind of vehicle only when that truly helps; many designs work fine with a simple type field instead of a deep inheritance tree.
Draw a tiny diagram or a small table. You do not need perfect formal UML drawings. You need a story the interviewer can follow without guessing what you meant.
Step 4: Draft the method names (before the bodies)
Before you fill in implementation details, write the public methods and what they return:
ParkingLot.park(vehicle) -> Ticket
ParkingLot.unpark(ticketId) -> Fee
ParkingLot.getAvailability() -> map of floor -> free slots
Good method lists look a little boring on purpose. Boring names are easy to test and easy to explain, which is what you want under time pressure.
Step 5: Apply the design in code
Implement the main path first: park one car, leave with that ticket, and print the fee. Then add the next rule. Run small checks as you go so you know the path still works.
Do not start by trying to handle every rare case. Rare cases are much easier once the main path exists and you can point to where a new rule should live.
Worked example: Design a Parking Lot
We will walk the five steps on the same problem you can practice here: Design a Parking Lot.
The prompt (plain English)
You are writing software for a city parking garage with more than one floor. Bikes, cars, and trucks come in. The system should find a free spot that fits the vehicle, give a ticket, and later calculate the fee when the vehicle leaves. Build a clear design that assigns spots, tracks how full each floor is, and computes fees without mixing every job into one file.
Step 1 — Clarify (what we agree on)
In scope for the first version
- Multiple floors; each floor has many slots
- Vehicle types: bike, car, and truck
- Slot sizes: small, medium, and large (bike uses small, car uses medium, truck uses large)
- Park issues a ticket; leave frees the slot and computes the fee
- Show how many free slots each floor still has
Out of scope for the first version
- A real payment provider that charges a card
- Multiple entry gates where two cars might grab the same spot at the same moment (you can mention this later if asked)
- Reserved spots or electric-vehicle spots (leave the design able to add them later)
Assumptions we state out loud
- One vehicle per slot
- Fee equals an hourly rate by vehicle type, multiplied by hours parked (rounding up to the next hour is fine)
- Finding a slot means taking the first free slot of the right size while scanning floors in order
That short contract is enough. You have already shown the interviewer that you can bound a problem instead of building everything at once.
Step 2 — The main pieces (the nouns)
| Piece | Job (one clear sentence) |
|---|---|
Vehicle | Knows its type (bike / car / truck) and plate number |
Slot | One parking space; knows its size and whether it is free |
Floor | A group of slots; can report how many are still free |
Ticket | Proof of parking: ticket id, slot, vehicle, and entry time |
FeeCalculator | Turns a ticket and an exit time into a money amount |
ParkingLot | The entry point for park, leave, and availability |
Notice what is not a piece yet: a full payment service, a physical gate object, or an admin dashboard. Those can wait until the main path works.
Step 3 — How the pieces connect
ParkingLot
└── has many Floor
└── has many Slot
park():
ParkingLot finds a free Slot of the right size
marks that Slot occupied
creates a Ticket
returns the Ticket
unpark():
ParkingLot finds the Ticket
frees the Slot
FeeCalculator computes the fee from ticket + exit time
returns the fee
Why keep FeeCalculator separate? So when pricing rules change, you edit one place — not park(), not unpark(), and not a helper buried inside Floor where nobody expects money math to live.
Step 4 — Method names (before the bodies)
// Vehicle
Vehicle(type, plate)
// Slot
isFree() -> bool
canFit(vehicle) -> bool
occupy(vehicle)
release()
// Floor
findSlotFor(vehicle) -> Slot | null
freeSlotCount() -> int
// ParkingLot
park(vehicle) -> Ticket // error if no fitting spot
unpark(ticketId) -> number // fee amount
getAvailability() -> { floorId: freeCount }
// FeeCalculator
calculate(ticket, exitTime) -> number
If the interviewer stops you here and says the design looks good and you should start coding, you have already passed a large part of what this round measures: clear thinking under a vague prompt.
Step 5 — Detailed solution (code shape)
Below is a clear TypeScript-style sketch. In an interview, any language the company asks for is fine. The point is the structure of the design, not perfect syntax for one language.
Types and small classes
type VehicleType = "bike" | "car" | "truck";
type SlotSize = "small" | "medium" | "large";
class Vehicle {
constructor(
public readonly type: VehicleType,
public readonly plate: string
) {}
}
const SIZE_FOR_TYPE: Record<VehicleType, SlotSize> = {
bike: "small",
car: "medium",
truck: "large",
};
const HOURLY_RATE: Record<VehicleType, number> = {
bike: 10,
car: 20,
truck: 40,
};
Slot and Floor
class Slot {
private vehicle: Vehicle | null = null;
constructor(
public readonly id: string,
public readonly size: SlotSize
) {}
isFree() {
return this.vehicle === null;
}
canFit(vehicle: Vehicle) {
return this.isFree() && this.size === SIZE_FOR_TYPE[vehicle.type];
}
occupy(vehicle: Vehicle) {
if (!this.canFit(vehicle)) throw new Error("Slot cannot fit vehicle");
this.vehicle = vehicle;
}
release() {
this.vehicle = null;
}
}
class Floor {
constructor(
public readonly id: string,
private readonly slots: Slot[]
) {}
findSlotFor(vehicle: Vehicle): Slot | null {
return this.slots.find((s) => s.canFit(vehicle)) ?? null;
}
freeSlotCount() {
return this.slots.filter((s) => s.isFree()).length;
}
}
Each method does one job. Floor does not calculate fees. Slot does not know about tickets. That separation is what makes later changes safer.
Ticket and fee
class Ticket {
constructor(
public readonly id: string,
public readonly vehicle: Vehicle,
public readonly slot: Slot,
public readonly entryTime: Date
) {}
}
class FeeCalculator {
calculate(ticket: Ticket, exitTime: Date): number {
const ms = exitTime.getTime() - ticket.entryTime.getTime();
const hours = Math.max(1, Math.ceil(ms / (1000 * 60 * 60)));
return hours * HOURLY_RATE[ticket.vehicle.type];
}
}
ParkingLot — the piece that coordinates the others
class ParkingLot {
private tickets = new Map<string, Ticket>();
private nextTicketId = 1;
constructor(
private readonly floors: Floor[],
private readonly fees = new FeeCalculator()
) {}
park(vehicle: Vehicle): Ticket {
for (const floor of this.floors) {
const slot = floor.findSlotFor(vehicle);
if (!slot) continue;
slot.occupy(vehicle);
const ticket = new Ticket(
String(this.nextTicketId++),
vehicle,
slot,
new Date()
);
this.tickets.set(ticket.id, ticket);
return ticket;
}
throw new Error("Parking lot is full for this vehicle type");
}
unpark(ticketId: string, exitTime = new Date()): number {
const ticket = this.tickets.get(ticketId);
if (!ticket) throw new Error("Invalid ticket");
const fee = this.fees.calculate(ticket, exitTime);
ticket.slot.release();
this.tickets.delete(ticketId);
return fee;
}
getAvailability(): Record<string, number> {
const result: Record<string, number> = {};
for (const floor of this.floors) {
result[floor.id] = floor.freeSlotCount();
}
return result;
}
}
A short usage story (say this out loud)
const lot = new ParkingLot([
new Floor("F1", [new Slot("F1-S1", "medium"), new Slot("F1-S2", "large")]),
new Floor("F2", [new Slot("F2-S1", "small")]),
]);
const car = new Vehicle("car", "KA-01-1234");
const ticket = lot.park(car); // occupies F1-S1
console.log(lot.getAvailability()); // { F1: 1, F2: 1 }
const fee = lot.unpark(ticket.id); // frees slot, returns fee
console.log(fee);
That story is what interviewers want to hear in words: create the garage, park, check how full the floors are, leave, and see the fee. If you can narrate that path, the code has a purpose beyond “it compiles.”
What to say when they ask “how would you extend this?”
| Extension | Where you change |
|---|---|
| Electric-vehicle spots | Add a spot tag or type, and update canFit |
| Different pricing | Change or replace FeeCalculator so fee rules live in one place |
| Prefer filling one floor first | Change the search order inside park |
| Two gates at once | Mention protecting “find a free slot” and “mark it occupied” so two cars cannot take the same spot; do not build a full locking system in the first version unless asked |
This is the payoff of the earlier design work: new rules usually touch one place instead of the whole file.
Common mistakes on this problem
Putting everything into one ParkingLot class with raw arrays and no Slot or Floor makes every change risky. Burying fee logic inside park() mixes two jobs. Building a deep inheritance tree for every vehicle type when a simple type field would do wastes time. Building a full payment system before park and leave work means you may finish the interview with no working main path. Coding silently for twenty minutes with no model on the board leaves the interviewer guessing what you are doing.
A simple checklist before you hit “Run”
Use this on every practice problem, and treat each item as a full question rather than a rush through boxes:
- Did I write scope and assumptions in four to six bullets the interviewer could correct?
- Can I list the main pieces and one job for each in under a minute?
- Can I explain how the pieces connect in one short paragraph?
- Did I name the public methods before I filled in the method bodies?
- Does the main path work end to end — park, leave, fee, availability?
- Can I name one future rule and point to the single place I would change?
If you can answer yes to those six, you are in good shape for that problem even if some rare cases are still unfinished.
Your first 60 minutes (do this today)
Minutes 0–10: Skim this page again. Focus on the five steps and the Parking Lot tables, not on memorizing every line of sample code.
Minutes 10–50: Open Parking Lot on Practice LLD and run a timed attempt. Spend about eight minutes on clarify, pieces, connections, and method names — talking out loud or writing short comments. Spend about twenty-five to thirty minutes implementing park, leave, and availability. Spend about five minutes noting one extension and one mistake you made.
Minutes 50–60: Write five notes: what you skipped, where you got stuck, one class that did too much, one method you should have named earlier, and one thing to fix next time.
That written reflection is the real preparation. The code is the artifact that proves the reflection.
Next problems to try in order:
- LRU Cache — designing a structure for fast get and put while forgetting the oldest unused item
- Vending Machine — inventory and steps that depend on the current state of the machine
- Expense Sharing — domain rules and who owes whom
- Elevator System — requests and how cars choose floors
Where to go next
You now have the “why,” the five-step loop, and one full walkthrough you can reread when a prompt feels fuzzy.
- Practice with feedback: Practice LLD
- If you also need system design: System design interviews — start here
- A longer system-design study plan: How to Prepare for System Design Interviews
Keep the rule simple enough to remember under pressure: clarify the problem, name the pieces, connect them, write the method names, then code. One careful problem per week beats ten rushed pastes from memory that you never review.
Frequently asked questions
- What is a low-level design (LLD) interview?
- It is a timed round where you design and then write code for a small product-style problem — for example a parking garage, an elevator, a cache that forgets old data, or a tool that splits expenses. You name the main pieces of the software, say how they connect, write the method names others would call, and implement enough of the main path that the interviewer can see your thinking. They are not looking for a memorized diagram; they want a clear story and code that matches that story.
- How is LLD different from system design (HLD)?
- System design asks how the whole product should run when many people use it at once: how many services you need, where data lives, and what happens when traffic grows. Low-level design asks how you structure the code inside one feature: which pieces exist, what each piece owns, and how they call each other. A simple way to remember it is “objects and methods” for LLD, and “boxes across the network” for system design.
- Why do companies ask LLD questions?
- Because most day-to-day engineering work is writing and changing code, not drawing a worldwide network on day one. Interviewers want to see that you can keep jobs separate, name things clearly, and leave room for a new rule — such as a new spot type or a new fee formula — without rewriting half the file. That habit shows up later in code reviews and in features that grow over time.
- What do I need in order to do well in an LLD round?
- You need a repeatable approach and practice explaining your thinking out loud. People who pause to clarify scope, name the main pieces, and keep methods small usually do better than people who jump straight into typing and then get lost in one oversized class. The skill is the process, not a résumé line.
- What is the biggest mistake in LLD interviews?
- Opening the editor before you and the interviewer agree on scope and on the main pieces of the design. That often leads to one giant class that handles parking, tickets, fees, and floors together, which is hard to explain and hard to extend. Force yourself through clarify → name the pieces → say how they connect → write method names before you implement the bodies.
- Which LLD problem should I practice first?
- Start with Parking Lot or a simple game board such as Tic-Tac-Toe. Both push you to name objects and methods without needing heavy math. After that, try an LRU cache for data-structure design, then a vending machine or elevator when you want practice with steps that change based on the current state of the machine. You can practice on /practice-lld.
- How long should I spend on each LLD practice problem?
- Aim for about forty to fifty-five minutes: roughly ten minutes talking through the design, twenty-five to thirty-five minutes coding the main path, and five minutes on what you would improve. One careful problem per week with a short written reflection usually teaches more than five rushed attempts where you never look back at what went wrong.
- Do I need to memorize design patterns for LLD?
- Not as a list of names to recite. Learn a few ideas by using them when they fit — for example, keeping fee rules in one place so you can swap how money is calculated later, or modeling a vending machine as a set of steps that depend on whether money has been inserted. Say the pattern name only after you have explained the idea in plain words. Clean, clear classes matter more than dropping pattern names.
What's next?