How to Approach a Low-Level Design (LLD) Interview: The Framework
A repeatable framework for LLD and machine-coding rounds: clarify requirements, find the objects, define relationships (has-a vs is-a), apply design patterns where they fit, sketch the class diagram, then write clean SOLID code. With a worked parking-lot example in Java.
🟠 Senior · machine-coding round
If high-level design is about drawing boxes for millions of users, low-level design (LLD) is the opposite zoom level: how do you turn a problem into clean classes and working code? "Design a parking lot." "Design Splitwise." You get 45–90 minutes and a blank editor, and you're judged on your object-oriented design — are your classes well-chosen, your responsibilities clean, your code extensible? These "machine coding" rounds are huge for SDE-2 and senior roles (especially in India), and the good news is they follow a repeatable framework, just like HLD. This builds directly on object-oriented programming — if OOP feels shaky, skim that first.
The LLD framework (6 steps)
| Step | What you do |
|---|---|
| 1. Requirements & use cases | Clarify scope; list what the system must do |
| 2. Identify objects | Find the core classes (the nouns) |
| 3. Relationships | How classes connect (has-a / is-a) |
| 4. Behaviors + patterns | Methods, and design patterns where they fit |
| 5. Class diagram | Sketch the UML before coding |
| 6. Clean code | Implement with SOLID, interfaces, enums, thread-safety |
Step 1 — Requirements & use cases
Same rule as HLD: don't start coding blind. Pin the scope with a few questions, then list the concrete use cases. For "design a parking lot":
- Multiple spot sizes (small, medium, large)? Multiple vehicle types? → yes
- Multiple floors/entrances? → assume one floor to start; mention we can extend
- How is pricing calculated? Hourly? → yes, per hour
- Core use cases: park a vehicle, unpark and pay, find available spot
Writing the use cases down keeps you focused and shows the interviewer you scope before you build.
Step 2 — Identify the objects (the nouns)
A reliable trick: underline the nouns in the requirements — they're usually your classes. From the parking lot: ParkingLot, ParkingFloor, ParkingSpot, Vehicle, Ticket, Payment, EntryGate. Don't force every noun into a class, but this gets you 90% there fast.
Then look for things that come in types — those often become enums or a small inheritance hierarchy: VehicleType {CAR, BIKE, TRUCK}, SpotType {SMALL, MEDIUM, LARGE}.
Step 3 — Define relationships (the heart of LLD)
This is where good design is won or lost. For each pair of classes, ask: is this "is-a" (inheritance) or "has-a" (composition)? Interviewers watch this closely.
Caris-aVehicle→ inheritance (Car extends Vehicle)ParkingLothas-a list ofParkingFloor→ composition (the floors belong to the lot)ParkingFloorhas-a list ofParkingSpot→ composition
Prefer composition over inheritance when in doubt — it's more flexible and avoids fragile class hierarchies. (More on this in OOP concepts.) The distinction between association, aggregation, and composition is worth knowing cold — see OOD basics.
Step 4 — Behaviors and where patterns fit
Now add methods, and reach for a design pattern only where it genuinely simplifies — never to show off. A few that come up constantly in LLD:
- Strategy — swappable algorithms. Parking fee could be hourly, flat, or dynamic → a
PricingStrategyinterface. (Strategy pattern) - Factory — create the right object without hardcoding types. A
VehicleFactoryorSpotFactory. (Factory pattern) - Singleton — one shared instance, e.g. the
ParkingLotitself. (Singleton pattern) - State — an object that behaves differently by state, e.g. a vending machine or a spot (free/occupied). (State pattern)
- Observer — notify many parts on an event, e.g. displays updating when a spot frees up. (Observer pattern)
Step 5 — Sketch the class diagram
Before writing code, draw the classes, their key fields, and the arrows (relationships). A quick text sketch works on any whiteboard:
ParkingLot ◇──► ParkingFloor ◇──► ParkingSpot
(has floors) (has spots) │ isOccupied
│ SpotType
Vehicle ◄─── Car, Bike, Truck (extends) ▼
Ticket { vehicle, spot, entryTime } PricingStrategy (interface)
└─ HourlyPricing, FlatPricing
The ◇──► means composition ("has-a, owns"), the plain arrow means inheritance. This diagram is your design — coding it becomes almost mechanical. See UML class diagrams for the notation.
Step 6 — Write clean, working code
Now implement, keeping SOLID in mind — especially program to interfaces and single responsibility. A taste of the parking lot in Java:
enum SpotType { SMALL, MEDIUM, LARGE } abstract class Vehicle { protected String plate; abstract SpotType requiredSpot(); } class Car extends Vehicle { SpotType requiredSpot() { return SpotType.MEDIUM; } } // Strategy: pricing is swappable without touching ParkingLot interface PricingStrategy { double price(Duration d); } class HourlyPricing implements PricingStrategy { public double price(Duration d) { return Math.ceil(d.toHours()) * 20; } } class ParkingSpot { private final SpotType type; private Vehicle current; // null = free synchronized boolean park(Vehicle v) { // thread-safe: two cars can't grab one spot if (current != null) return false; current = v; return true; } }
Notice the small senior touches: an enum not magic strings, an interface for pricing (so a new pricing scheme adds a class, changes nothing else — that's the Open/Closed principle), and synchronized on park() because in a real lot two cars could race for the same spot (concurrency matters in LLD too).
What interviewers score
Clean class boundaries (each class does one thing); correct relationships (composition vs inheritance); sensible use of patterns (not too few, not forced); extensibility ("if I asked you to add electric-vehicle charging spots, how much changes?" — ideally very little); and code that actually compiles and handles edge cases. Talking through your choices matters as much as here as in HLD.
The mistakes that fail people
- The God class — a giant
ParkingLotdoing everything. Split responsibilities. - Pattern obsession — cramming in five patterns you don't need. Use one where it earns its place.
- No interfaces / hardcoded types — makes the design rigid; you'll fail the "now extend it" follow-up.
- Skipping the diagram and coding immediately — you'll design yourself into a corner.
- Ignoring concurrency — many LLD problems (booking, inventory) have race conditions; senior candidates call them out.
Practice on the classics
LLD is muscle memory — do the canonical problems until the framework is automatic. Start with the parking lot (the "hello world" of LLD), then a vending machine (great for the State pattern) and Splitwise.
What clicked for me: I stopped thinking "what pattern should I use?" and started thinking "what are the nouns, and who owns whom?" Get the objects and relationships right, and clean code almost writes itself — the patterns then show up naturally exactly where they belong, not because you forced them. So run these six steps on three or four classic problems, always sketching the class diagram before typing, always asking "how would I extend this?" Do that and machine-coding rounds stop being scary — you'll have a calm, repeatable process while other candidates are still staring at a blank file. That process is the whole skill, and now it's yours. You've got this.
What to read next
- Design a Parking Lot — the full worked LLD
- SOLID Principles — the rules behind clean OO code
- Design Patterns — your LLD toolkit
- ← Back to the full System Design guide