← Back to Design & Development
LLD · In a Hurry · Part 2 of 3

The 5-Step LLD Framework

A 45-minute timeboxed playbook for any LLD prompt — from "design a parking lot" to "design a chess game" — with a full minute-by-minute walkthrough at the end.

Step 0

Why You Need a Framework — Even More Than in HLD

Picture Raj at his SDE-3 onsite. The interviewer says, "design a movie booking system." Raj knows Strategy. He knows Factory. He's read about every GoF pattern twice. So he opens the whiteboard, draws a class called Movie, then a class called Theater, then a class called Booking — and freezes. The classes are right but the relationships are vague. He hasn't named the requirements. He hasn't decided whether Seat is a class or a field on Theater. He hasn't thought about race conditions on bookings. Twenty-five minutes in he's drawing arrows between boxes that he's not sure point in the right direction. The interviewer asks "what does book() actually do?" and Raj realises he hasn't decided who owns the seat-locking logic.

The problem isn't that Raj doesn't know patterns. The problem is he has no playbook for the order of operations. LLD interviews need structure even more than HLD ones, because LLD has more degrees of freedom — every entity could be a class or a field, every method could live on the producer or the consumer, every variation point could be a Strategy or a Factory or just a switch statement. Without an order, you'll thrash.

The framework is the recipe, not the menu. A great chef doesn't decide what to cook by reading the entire pantry top-to-bottom; they pick a dish, then go in order — mise en place, then sear, then deglaze, then plate. The LLD framework is the same. Requirements before entities. Entities before relationships. Relationships before patterns. Patterns before code. Skip a step and the next one collapses.

This page lays out the 5 steps, gives you the timebox for each, then shows them in action on a "design a parking lot" prompt. By the end you should be able to walk into any LLD interview and know exactly what you're going to do at minute 5, minute 15, minute 25, and minute 35.

The Playbook

The 5-Step Framework — A 45-Minute Timeline

Here's the playbook on one page. Five distinct phases, ordered the way a senior engineer would actually approach a new domain in a real design review. Each step has a hard timebox — the goal isn't to finish fast, it's to spend exactly the right amount on each phase so you reach the code with the interviewer still engaged.

gantt title LLD Interview — 45 to 60 Minute Timeline dateFormat X axisFormat %s section Setup Step 1 — Requirements :crit, s1, 0, 5m Step 2 — Core Entities :s2, after s1, 5m section Design Step 3 — Class Diagram :crit, s3, after s2, 10m Step 4 — Patterns and Sequence :crit, s4, after s3, 10m section Code Step 5 — Java Code :crit, s5, after s4, 12m section Buffer Q and A and Trade-offs :s6, after s5, 5m

Step 1 · ~5 min

Requirements. 3–5 functional + 3 non-functional. Explicit out-of-scope. Get sign-off before drawing.

Step 2 · ~5 min

Core Entities. 5–8 nouns with a one-sentence responsibility each. Build the vocabulary.

Step 3 · ~10 min

Class Diagram. UML — fields, methods, relationships. Inheritance vs composition justified.

Step 4 · ~10 min

Patterns + Sequence. Find variation points, apply 2–4 patterns, draw the happy-path sequence.

Step 5 · ~12 min

Java Code. Enums → interfaces → entities → service → main(). One end-to-end happy path that compiles.

Buffer · ~5 min

Trade-offs & Q&A. Extension points, concurrency, "what would you change?"

The framework as a kitchen. Steps 1–2 are mise en place — the prep nobody admires but everyone needs. Step 3 is the sear — visible, dramatic, and where the dish takes shape. Step 4 is the deglaze — small move, huge flavour, where the design starts to feel professional. Step 5 is the plate — the version the interviewer photographs. Skip mise en place and you're going to be chopping onions while the pan smokes.
Step 1 · 5 min

Step 1 — Clarify Requirements

The single most undervalued step. Candidates who skip it always design the wrong thing. The interviewer's gentle "interesting, but what about X?" twenty minutes in lands like a wrecking ball, and there's no time to recover. Five minutes here saves twenty later.

Functional requirements — top 3 user actions

Phrase each as "a user should be able to..." Resist the urge to brainstorm 15 features. The interviewer doesn't have time to design 15 things in 45 minutes, and the loop is graded on depth, not breadth. Pick the 3 hardest, hardest-coupled features — they'll force out the most interesting design choices.

✅ Good — Parking Lot top 3

  • A driver should be able to find and occupy a free spot appropriate for their vehicle size
  • A driver should be able to pay and exit, with the bill computed from time + spot type
  • An admin should be able to add a new floor or change pricing rules without redeploying core logic

Three actions, each one drives a different architectural slice. Park → spot allocation strategy. Pay → billing strategy. Admin → extension points / Open-Closed.

❌ Bad — kitchen sink

  • Park, reserve, cancel, transfer, refund
  • Pay by card, UPI, wallet, monthly subscription, corporate billing
  • SMS notification, app notification, license-plate recognition, EV charging, valet
  • Multi-operator, franchising, dynamic pricing, surge, reporting...

You'll spend 15 minutes just listing features and have no time for the class diagram, let alone code. The interviewer will start cutting features by force, which is a process failure on you.

Non-functional requirements — quantify or skip

NFRs in LLD are smaller in scope than HLD ones — you don't need to estimate QPS — but you still need to commit to a few. The good list: concurrency model extensibility direction performance budget durability. Each one constrains a later design choice.

✅ Good NFRs (Parking Lot)

  • Concurrency: 10K active drivers, two parking attempts on the same spot must serialise — second one fails fast
  • Extensibility: new vehicle types, new pricing rules, and new payment methods must be add-only
  • Performance: spot lookup under 50ms; the system holds state in-memory, persistence is out of scope
  • Out of scope: payment gateway integration, license-plate ML, multi-tenant operators

❌ Bad NFRs

  • "Highly available" — what's the SLO? Does the parking gate fall back to free entry?
  • "Scalable" — to what? 100 spots or 100,000?
  • "Secure" — secure against what? Drivers gaming pricing? Admins forging tickets?
  • "Maintainable" — meaningless without a stated extension axis

The "out of scope" line — the most underused move

Saying "I'm not designing X" is as valuable as saying "I'm designing Y". It tells the interviewer you've considered the trade-off and made a deliberate cut. "Payment gateway integration is out of scope — I'll use a PaymentProvider interface so production swaps in Stripe; the LLD focuses on the in-memory model" earns more credit than silently leaving payments unaddressed.

Anti-pattern: "Sure, design a parking lot, let me start drawing." The candidate has just decided the requirements unilaterally and will spend the next 40 minutes defending choices the interviewer never agreed to. The fix is one sentence — "Before I draw anything, can I confirm the top 3 features and what's out of scope?"
Step 2 · 5 min

Step 2 — Identify Core Entities

List the data nouns the system manipulates. One sentence of responsibility per entity. No fields yet, no relationships, no methods — just names and what each one is responsible for. This step exists to establish vocabulary with the interviewer so when you say "Spot" or "Ticket" later, you both mean the same thing.

How to find the entities — circle the nouns

Read the requirements out loud. Every concrete noun that has its own state or its own lifecycle is an entity candidate. Adjectives and verbs are not entities — they become fields and methods. "Park a car in a spot" gives you Car, Spot (entities) and park() (method). "in" isn't an entity.

Entity Responsibility (one sentence) Lifecycle
ParkingLotOwns all floors, exposes the entry/exit operationsSingleton — one per facility
FloorHolds a list of spots and answers "is anything free for this vehicle size?"Created at lot setup, mostly immutable
SpotRepresents a single parking slot with size and occupancy stateLong-lived; oscillates FREE ↔ OCCUPIED
VehicleRepresents the thing being parked; carries size + license plateTransient — exists for one parking session
TicketThe receipt that proves a vehicle entered; carries entry timeIssued on park, consumed on exit
BillComputed at exit from ticket + pricing strategyOne-shot — generated and paid

Six entities is the sweet spot for a parking lot. Less than four and you're hiding complexity in fat classes; more than nine and you're overdesigning. If you're tempted to add EntryGate, ExitGate, and DisplayBoard — pause. Those are interface concerns, not domain entities. Mention them in passing if asked, but don't pollute the diagram.

The three reasons this step earns its time

🎯 Anchors for later

When you draw park() in Step 5, you'll reach for "the Spot collection" — the interviewer already knows what that means.

📐 Forces a model

If you can't list the entities, you don't understand the problem. Five minutes here exposes confusion early, while you can still recover.

⚡ Locks in vocabulary

"Slot" vs "Spot" vs "Bay" — pick one and the rest of the interview becomes shorter and clearer.

So what. Step 2 is small, fast, and almost mechanical — and it's the step that lets Steps 3, 4, and 5 each move twice as fast. Five minutes of vocabulary now buys you ten minutes back later.
Step 3 · 10 min

Step 3 — Class Diagram

Now the entities get fields, methods, and relationships. This is where most of the LLD score is decided. The interviewer is watching for two things: (a) does the class structure cleanly map to the domain you described in Step 2, and (b) do the relationships use the right kind of arrow — inheritance vs composition vs aggregation vs association?

The four relationships you must know cold

Inheritance — "is-a"

UML: solid line + hollow triangle (--|>). "A Car is a Vehicle." Use only when the subclass genuinely substitutes for the parent. Default away from inheritance — it's a one-way door.

Composition — "owns, dies-with"

UML: solid line + filled diamond (*--). "A Floor owns its Spots." If the parent dies, the children die with it. Spots can't exist without their floor.

Aggregation — "has-a, lives-on"

UML: solid line + hollow diamond (o--). "A Garage has Cars." Cars exist before, during, and after they're parked. The garage doesn't own them.

Association — "knows-about"

UML: solid line with arrowhead (-->). "A Ticket references the Spot it's for." A weak link, no ownership. The most common relationship.

The cheat code: if you can't decide between composition and aggregation, pick aggregation. Composition is a stronger commitment ("I will manage your lifetime") that you usually don't need. If you can't decide between inheritance and composition, pick composition. Inheritance only when the subclass passes the Liskov test in Section 6 of Part 1.

Mermaid example — the parking lot's class spine

classDiagram class ParkingLot { -List~Floor~ floors -PricingStrategy pricing -SpotAllocator allocator +parkVehicle(Vehicle) Ticket +exitVehicle(Ticket) Bill } class Floor { -int floorNo -List~Spot~ spots +findFreeSpot(VehicleSize) Spot } class Spot { <> -String spotId -boolean occupied +occupy(Vehicle) +vacate() } class CarSpot class BikeSpot class TruckSpot class Vehicle { -String licensePlate -VehicleSize size } class Ticket { -String ticketId -Spot spot -Instant entryTime } class PricingStrategy { <> +calculate(Ticket, Instant exit) Bill } class HourlyPricing class DayNightPricing ParkingLot *-- Floor : composition Floor *-- Spot : composition Spot <|-- CarSpot : inheritance Spot <|-- BikeSpot : inheritance Spot <|-- TruckSpot : inheritance ParkingLot --> PricingStrategy : association PricingStrategy <|.. HourlyPricing PricingStrategy <|.. DayNightPricing Ticket --> Spot : association

How to narrate this aloud

The diagram alone earns nothing if the interviewer can't follow why each arrow is the kind of arrow it is. As you draw, say: "ParkingLot composes Floor — floors don't exist outside their lot. Floor composes Spot for the same reason. Spot is abstract because Bike, Car, and Truck spots have different size constraints — that's inheritance because they truly substitute. PricingStrategy is an interface that ParkingLot holds by reference (association) because pricing rules change every quarter and I want a new rule to be a new file."

The senior signal in this step: every relationship has a one-sentence justification rooted in domain reality, not in pattern dogma. "It's composition because the lifetimes are bound" beats "composition because the book said composition."
Step 4 · 10 min

Step 4 — Apply Patterns & Draw the Sequence

Now you find the variation points in the design — the places where requirements are most likely to change next quarter — and you apply the GoF pattern that absorbs that change cleanly. Then you draw the happy-path sequence so the interviewer can see the runtime, not just the static topology.

How to spot a variation point

Ask one question per noun in the diagram: "if I had to add a new variant of this next month, would the existing code change?" If yes, that's a variation point. The pattern toolbox is in Part 3; the cheat-sheet for picking the right one is below.

Smell Pattern Parking Lot Example
An if/else over a "kind" enumStrategyPricing rules — hourly, day/night, weekend
Object construction has many switchesFactoryCreating the right Spot subclass for a vehicle
One write must update many readersObserverSpot freed → notify reservation holders
Behaviour depends on lifecycle stageStateReservation: PENDING → CONFIRMED → EXPIRED
Optional features stack at runtimeDecoratorPeak-hour surcharge wraps base pricing
Exactly one instance, globally accessibleSingletonThe ParkingLot registry
Constructor with >3 paramsBuilderConfiguring a Lot at startup
The two-to-four rule. Aim for 2–4 patterns. One pattern looks like you flinched. Six patterns looks like resume-driven design — the interviewer will start asking "why Visitor here?" and you'll fold. Each pattern you name should be tied to a specific class plus a one-sentence reason that mentions a concrete future change.

Sequence diagram — show one user action end-to-end

Pick the most important user action — usually the one from your top functional requirement — and draw the sequence of method calls between objects. A sequence diagram is worth ten paragraphs of explanation; the interviewer can see the runtime.

sequenceDiagram actor Driver participant Gate as EntryGate participant Lot as ParkingLot participant Alloc as SpotAllocator participant Floor participant Spot participant Ticket Driver->>Gate: drive in (vehicle) Gate->>Lot: parkVehicle(vehicle) Lot->>Alloc: findSpot(vehicle.size) Alloc->>Floor: findFreeSpot(size) Floor->>Spot: tryOccupy(vehicle) alt CAS success Spot-->>Floor: occupied Floor-->>Alloc: spot Alloc-->>Lot: spot Lot->>Ticket: new Ticket(spot, now) Lot-->>Gate: ticket Gate-->>Driver: print ticket, raise barrier else CAS failed (race lost) Spot-->>Floor: BUSY Floor->>Spot: try next free spot end

Notice two things in the sequence. One: the alt block makes the race condition visible. Two drivers hitting the same spot is a real risk and showing the CAS retry path scores points without anyone asking. Two: every participant is a real class from your Step 3 diagram. If a sequence message has no class to send it to, you're missing an entity.

So what. Step 4 is the step that turns a static class diagram into a system the interviewer can imagine running. Patterns explain why the design will survive next quarter's changes; the sequence diagram explains how the runtime behaves today. Both, together, in 10 minutes.
Step 5 · 12 min

Step 5 — Write the Java

Twelve minutes is not a lot. The temptation is to start with the most exciting class and write it in detail. The right move is the opposite — write the boring scaffolding first (enums, interfaces) so the meat in the middle has something to lean on, and end with one main() that exercises the happy path. If the interviewer can read your main() top-to-bottom and see the design come alive, you win the loop.

The order of operations

1. Enums (1 min)

VehicleSize, SpotStatus, anything finite. Cheap to write, locks in vocabulary.

2. Interfaces (2 min)

PricingStrategy, SpotAllocator, PaymentProvider. The variation points from Step 4.

3. Entity classes (4 min)

Spot, Vehicle, Ticket. Records or POJOs — skip getter/setter ceremony.

4. Service (3 min)

ParkingLot — the orchestrator. Where the parking + billing logic lives.

5. main() (2 min)

Three lines: park a car, sleep, exit. Show the design works end-to-end.

A skeleton in 60 lines (the kind that fits on a whiteboard)

Enums + interfaces — vocabulary first
enum VehicleSize { BIKE, CAR, TRUCK }

interface PricingStrategy {
  double calculate(Duration stay, VehicleSize size);
}

interface SpotAllocator {
  Optional<Spot> findAndOccupy(VehicleSize size);
}
Entity classes — Spot is the abstract base, vehicle is a record
abstract class Spot {
  protected final String id;
  protected final VehicleSize size;
  protected final AtomicReference<Vehicle> occupant = new AtomicReference<>();

  Spot(String id, VehicleSize size) { this.id = id; this.size = size; }

  boolean tryOccupy(Vehicle v) {
    return v.size().ordinal() <= size.ordinal()
        && occupant.compareAndSet(null, v);   // race-safe
  }
  void vacate() { occupant.set(null); }
}

class CarSpot   extends Spot { CarSpot(String id)   { super(id, VehicleSize.CAR); } }
class TruckSpot extends Spot { TruckSpot(String id) { super(id, VehicleSize.TRUCK); } }

record Vehicle(String licensePlate, VehicleSize size) {}
record Ticket(String id, Spot spot, Instant entry) {}
record Bill(Ticket ticket, double amount, Duration stay) {}
Service + main() — the happy path you can read top-to-bottom
class ParkingLot {
  private final SpotAllocator allocator;
  private final PricingStrategy pricing;
  private final Map<String, Ticket> openTickets = new ConcurrentHashMap<>();

  ParkingLot(SpotAllocator allocator, PricingStrategy pricing) {
    this.allocator = allocator;
    this.pricing   = pricing;
  }

  Ticket park(Vehicle v) {
    Spot spot = allocator.findAndOccupy(v.size())
                .orElseThrow(() -> new LotFullException(v.size()));
    Ticket t = new Ticket(UUID.randomUUID().toString(), spot, Instant.now());
    openTickets.put(t.id(), t);
    return t;
  }

  Bill exit(String ticketId) {
    Ticket t = openTickets.remove(ticketId);
    if (t == null) throw new UnknownTicketException();
    Duration stay = Duration.between(t.entry(), Instant.now());
    t.spot().vacate();
    return new Bill(t, pricing.calculate(stay, t.spot().size), stay);
  }
}

public class Demo {
  public static void main(String[] a) throws Exception {
    SpotAllocator  alloc   = new SimpleAllocator(List.of(new CarSpot("S-1")));
    PricingStrategy pricing = new HourlyPricing(40.0);
    ParkingLot     lot     = new ParkingLot(alloc, pricing);

    Ticket t = lot.park(new Vehicle("KA-01-AB-1234", VehicleSize.CAR));
    Thread.sleep(3000);
    Bill b = lot.exit(t.id());
    System.out.println("Pay: ₹" + b.amount());
  }
}
What this code demonstrates without saying a word. (1) Concurrency: AtomicReference.compareAndSet on the spot makes the race-condition discussion concrete. (2) Open/Closed: a new PricingStrategy implementation is one new class — no edits to ParkingLot. (3) Composition over inheritance: ParkingLot holds SpotAllocator by reference instead of extending it. (4) Java 17+ idioms: record for value types, Optional for "not found", ConcurrentHashMap for the ticket registry. Each one is a senior signal even if the interviewer never asks.
What to skip without apology. Getters, setters, equals()/hashCode(), exception class definitions, the trivial SimpleAllocator body. Say out loud "I'd Lombok these in production" or "I'll skip the SimpleAllocator body — just iterates the spot list — happy to write it if you want." The interviewer almost always says skip it. Use the time saved on the methods that matter.
The Senior Tell

Specifying Implementations — Where Senior Beats Junior

Of all the things that separate a junior-level LLD answer from a senior one, the biggest is specificity. Junior candidates name a class; senior candidates name the class, the data structure inside it, the concurrency primitive, the failure mode, and the extension point. Same five seconds, ten times the signal.

🟥 "I'll use a list of spots"

Which list? ArrayList? Synchronised? Indexed how? Iterated under contention?

🟩 The senior version

"Per-floor I'll keep an EnumMap<VehicleSize, ConcurrentLinkedDeque<Spot>> of free spots so allocation is O(1) and lock-free. Occupied spots leave the deque entirely; on vacate, they re-enter at the head. Re-entry at head means the same spot gets re-used most often, which keeps the working set hot and helps with cache-friendly lookups in tests."

🟥 "The Spot has a synchronised method"

Synchronised on what monitor? What's the contention pattern? What's the timeout?

🟩 The senior version

"Each Spot holds an AtomicReference<Vehicle>. tryOccupy does a single CAS — if it returns false, the caller (the allocator) tries the next free spot. No blocking, no monitor, no deadlock surface. The whole 'two drivers hit the same spot' problem becomes one CPU instruction."

🟥 "Pricing is configurable"

Configurable how? Where does the config live? How is it reloaded?

🟩 The senior version

"PricingStrategy is an interface with one method, calculate(Duration, VehicleSize). Implementations live in their own files — HourlyPricing, DayNightPricing, WeekendSurcharge. The lot holds the strategy by reference, so an admin endpoint can hot-swap it without restarting. Decorator on top — PeakHourSurcharge wraps any strategy and adds 30% between 9–11am."

The pattern in one sentence: for every component you name, also name (1) the specific data structure or interface, (2) the concurrency primitive, (3) the extension point (how would I add a new variant?), (4) the failure mode (what happens if this throws?). That's the senior signal — and it costs maybe 10 extra seconds per component.
Worked Example

Walkthrough — "Design a Parking Lot" in 45 Minutes

Below is a minute-by-minute script of an idealised candidate (call her Priya) running the framework on the parking-lot prompt. Read it as the tempo and tone you should aim for — concise, structured, narrating the framework out loud as she builds.

sequenceDiagram actor P as Priya (candidate) actor I as Interviewer Note over P,I: Minute 0 — Prompt I->>P: Design a parking lot. Note over P,I: Minutes 0 to 5 — Step 1 Requirements P->>I: Top 3 features park, exit and bill, admin extends rules? I-->>P: Yes. Skip payment gateway and ML license-plate. P->>I: NFRs 10K drivers, race-safe spot allocation, add-only extensions Note over P,I: Minutes 5 to 10 — Step 2 Entities P->>I: Six entities ParkingLot, Floor, Spot, Vehicle, Ticket, Bill Note over P,I: Minutes 10 to 20 — Step 3 Class Diagram P->>I: Lot composes Floor, Floor composes Spot. Spot is abstract Bike Car Truck. P->>I: PricingStrategy is an interface. Lot holds it by reference (association). I-->>P: Why composition, not aggregation, for spot to floor? P->>I: Spot can't exist without floor parent dies, child dies. That is composition. Note over P,I: Minutes 20 to 30 — Step 4 Patterns + Sequence P->>I: Strategy on pricing. Factory on Spot creation. Singleton on Lot. State on Reservation. P->>I: Sequence Driver Gate Lot Allocator Floor Spot.tryOccupy (CAS). I-->>P: What if the CAS loses? P->>I: Allocator catches the false return and tries the next free spot. No retry storms. Note over P,I: Minutes 30 to 42 — Step 5 Code P->>I: Enums first. Then PricingStrategy interface. Then abstract Spot with AtomicReference. P->>I: ParkingLot.park() and exit(). One main() with park, sleep, exit, print bill. I-->>P: How would you add EV charging spots? P->>I: New EvSpot subclass. New EvPricing decorator. Zero edits to ParkingLot. Note over P,I: Minutes 42 to 45 — Trade-offs & Q&A I->>P: What would you change with more time? P->>I: Persistence layer. The map of openTickets is in-memory. ParkingTicketRepo interface, prod implementation backed by Postgres.

The same script, with timing annotations

00:00
Interviewer: "Design a parking lot."
00:30
Priya: "Got it. Before I draw, can I pin down requirements? Top 3 functional features I'd focus on: (1) a driver finds and occupies a spot for their vehicle size, (2) on exit, the system computes a bill from time and spot type, (3) an admin can add new vehicle types or pricing rules without redeploying core logic. Sound right?"
01:30
Interviewer: "Yes. Skip payment gateway integration and license-plate ML."
02:00
Priya: "Non-functional: 10K active drivers, two parking attempts on the same spot must serialise (one wins, one fails fast). Spot lookup under 50ms. Extensibility — adding new vehicle types or pricing rules must be add-only. State stays in memory; persistence is out of scope but I'll leave a repository interface so it's swappable."
05:00
Priya (Step 2): "Six core entities — ParkingLot (the registry), Floor (groups spots), Spot (one slot, has size + occupancy), Vehicle (transient, has plate + size), Ticket (issued at entry), Bill (computed at exit). I'm leaving out EntryGate and DisplayBoard — those are interface concerns, not domain entities."
10:00
Priya (Step 3): [draws UML] "ParkingLot composes Floor — composition because floors don't exist outside their lot. Floor composes Spot for the same reason. Spot is abstract because Bike, Car, and Truck spots have different size constraints — that's inheritance because the subclasses truly substitute. PricingStrategy is an interface and the lot holds it by reference (association) — pricing rules change every quarter and I want a new rule to be a new file."
17:00
Interviewer: "Why composition for Spot-to-Floor and not aggregation?"
17:15
Priya: "Aggregation says the parts can outlive the whole — a car outlives the garage. A spot can't outlive its floor; if we demolish the floor, the spot is gone. That's the composition test."
20:00
Priya (Step 4): "Four patterns. Strategy on PricingStrategy — pricing is the most-likely-to-change axis. Factory on Spot creation — the lot doesn't want to know which subclass to instantiate. Singleton on the lot itself — one per facility. Decorator for surge pricing — wraps any strategy without subclassing it. State pattern is overkill here because parking has only two states (free/occupied)."
25:00
Priya: [draws sequence diagram] "Happy path — driver enters, gate calls lot.park(vehicle), lot delegates to allocator, allocator picks a free spot from the floor, calls spot.tryOccupy(vehicle) which is a single CAS. If false, allocator tries the next spot. If true, lot creates a Ticket and returns it."
28:00
Interviewer: "What if the CAS loses?"
28:15
Priya: "Allocator catches the false return and just tries the next spot. The free-spot deque is per-size, so the contention is naturally low — only when two drivers of the same size hit the gate the same millisecond. Worst case it walks the deque twice. No retry storms because there's no exponential backoff loop — just iteration."
30:00
Priya (Step 5): [starts coding] "Enums first — VehicleSize. Then interfaces — PricingStrategy, SpotAllocator. Then abstract Spot with AtomicReference<Vehicle> and tryOccupy(v) doing the CAS. Concrete CarSpot, TruckSpot. Vehicle, Ticket, Bill as records — no boilerplate."
36:00
Priya: "ParkingLot service — holds the allocator, the pricing, and a ConcurrentHashMap of open tickets. park() calls allocator, creates a ticket, inserts it. exit() removes the ticket, vacates the spot, runs pricing, returns the bill."
40:00
Priya: "main() — instantiate a SimpleAllocator with one CarSpot, an HourlyPricing at ₹40/hr, build the lot, park a vehicle, sleep 3 seconds, exit, print the bill. That's the end-to-end happy path."
42:00
Interviewer: "How would you add EV charging spots?"
42:15
Priya: "Three changes, all add-only. (1) New EvSpot subclass with a chargeRate field. (2) New EvPricing decorator that wraps the existing strategy and adds an energy line. (3) Allocator already returns the right spot for a given size — extend VehicleSize with EV_CAR. Zero edits to ParkingLot — it never sees the difference."
43:30
Interviewer: "What would you change with more time?"
43:45
Priya: "Three things. (1) Persistence — the in-memory openTickets map needs a TicketRepository interface backed by Postgres in production. (2) Reservation flow — that has its own state machine (PENDING → CONFIRMED → EXPIRED) and would use the State pattern. (3) Observability — emit a domain event on every park/exit so analytics can subscribe."
What this script demonstrates. Priya spent 5 minutes on requirements, 5 on entities, 10 on the class diagram, 10 on patterns + sequence, 12 on code, 3 on Q&A — and never wandered. The senior moves: (1) explicitly named out of scope in Step 1, (2) defended composition vs aggregation with a one-line domain reason, not pattern dogma, (3) showed the race condition in the sequence diagram before being asked, (4) when the EV question came, answered with extension points, not new code. Run this loop yourself on three problems from the question bank in Part 1 and the framework will feel like muscle memory.
Reference Map

Mapping This Site's LLDs to the Framework

Each existing LLD on this site emphasises different framework steps and showcases different patterns. When you're practising, pick a page based on the step you want to drill.

LLD Page Steps Emphasised Patterns Showcased Best for Practising
Parking Lot All 5 steps end-to-end Strategy, Factory, Singleton, State, Decorator, Observer The canonical resource-allocation problem
Vending Machine Step 4 (State pattern deep dive) State, Strategy State machine modelling — when to use State vs enum
Notification Service Steps 3 + 4 (multi-channel fan-out) Strategy, Factory, Decorator, Observer Variation along multiple axes (channel, retry, rate-limit)
Hotel Management Steps 1 + 3 (entity-rich domain) Composite, Strategy, State for booking lifecycle Domains with many entities and lifecycle states
MakeMyTrip Step 4 (10 patterns mapped to variability) The full GoF tour applied to a marketplace Reading "what pattern fits where" at scale
The meta-lesson: every LLD on this site was structured using the same 5-step framework you just learned. When you read them, watch for the framework underneath — Requirements first, then Entities, then the Class Diagram, then Patterns + Sequence, then Code. Once you see the skeleton, you can apply it to any prompt.