PracHub
QuestionsLearningGuidesInterview Prep

Low-Level Design Interview: What LLD Is and How to Crack It

This guide explains low-level design (LLD) interviews, covering what LLD entails, how it differs from high-level design, the expected interview flow......

Author: PracHub

Published: 6/23/2026

Home›Knowledge Hub›Low-Level Design Interview: What LLD Is and How to Crack It

Low-Level Design Interview: What LLD Is and How to Crack It

By PracHub
June 23, 2026
10 min read
0

Quick Overview

This guide explains low-level design (LLD) interviews, covering what LLD entails, how it differs from high-level design, the expected interview flow, object-oriented design principles for choosing abstractions and separating responsibilities, and a fully worked machine-coding example (parking lot) with runnable code.

Free

Low-Level Design (LLD) Interview: What It Is and How to Crack It

If you have a "machine coding" round or an "object-oriented design" round on your interview loop, that is the low-level design (LLD) interview. The interviewer hands you a small system - a parking lot, a rate limiter, an elevator, a vending machine - and watches you turn ambiguous requirements into classes, interfaces, and working code. Unlike a LeetCode round, there is no single correct answer and no hidden test suite. They are grading your design judgment: do you pick the right abstractions, keep responsibilities separated, and write code that another engineer could extend without rewriting?

This guide covers what LLD actually means, how it differs from high-level design (HLD), the exact flow interviewers expect, and one fully worked machine-coding problem (a parking lot) with running code. By the end you should be able to walk into the round with a repeatable process instead of improvising.

Low-Level Design Interview: What LLD Is and How to Crack It visual study map Visual study map Frame what matters Plan how to approach it Practice apply examples Review check gaps Use this map to decide what to practice first, then check each area against the examples in the guide.

Video companion: This verified YouTube video gives a second pass on the same prep area.

LLD vs HLD: two different rounds, two different skills

People conflate these because both have "design" in the name. They test almost disjoint skills.

High-Level Design (HLD)Low-Level Design (LLD)
Unit of designServices, databases, queues, cachesClasses, interfaces, methods
Typical prompt"Design Twitter's feed""Design the Tweet and Timeline classes"
OutputBox-and-arrow architecture diagramUML-ish class diagram + actual code
Core concernsScalability, latency, consistency, partitioningSOLID, design patterns, encapsulation, testability
You discussSharding, replication, CAP trade-offsInheritance vs composition, interface boundaries
DeliverableCapacity estimates, data flowCompilable code with the key methods filled in

A useful mental model: HLD decides you need a PaymentService; LLD decides what classes live inside that service and how Payment, Refund, and PaymentGateway talk to each other. Senior interviews often include both. The parking-lot-style question is squarely LLD - the interviewer rarely cares whether your lot scales to a million spots; they care whether adding a new vehicle type forces you to edit five existing classes.

The five concepts interviewers are actually grading

LLD rewards a small, concrete vocabulary. You do not need every Gang-of-Four pattern memorized, but you must apply these fluently.

Encapsulation and clear responsibilities. Each class should own one reason to change. A ParkingSpot knows whether it is free and what fits in it; it does not compute fees. When a class starts doing two unrelated things, split it.

The SOLID principles, in priority order for interviews:

  • S - Single Responsibility: one class, one job. The most common failure is a god-class ParkingLot that parks cars, prices tickets, and prints receipts.
  • O - Open/Closed: open for extension, closed for modification. Adding an ElectricCar or a new pricing scheme should mean adding a class, not editing a switch statement scattered across the codebase.
  • L - Liskov Substitution: any subclass must be usable wherever its base type is expected, without surprises.
  • I - Interface Segregation: prefer small, focused interfaces over one fat one.
  • D - Dependency Inversion: depend on abstractions (FeeStrategy), not concrete classes (FlatHourlyFee). This is what lets you swap behavior at construction time.

Composition over inheritance. Reach for inheritance only for true "is-a" relationships. Prefer holding a collaborator (ParkingLot has a FeeStrategy) over deep class hierarchies, which are brittle and hard to test.

A few load-bearing design patterns. You will reuse the same handful constantly:

PatternWhen it shows up in LLD rounds
StrategySwappable algorithms: pricing rules, rate-limiting algorithms, matching logic
FactoryCentralizing object creation: building the right Vehicle or Notification subtype
SingletonA single shared resource: one ParkingLot or one config registry (use sparingly - it hides dependencies)
ObserverReacting to events: notify displays when a spot frees up; alert subscribers on price change
StateAn object whose behavior changes by mode: a VendingMachine in Idle / HasMoney / Dispensing

Testability. If you cannot instantiate a class in isolation and assert on its behavior, the design is too coupled. Dependency injection (passing collaborators in via the constructor) is the cheap fix, and it signals seniority.

The interview format: a repeatable five-step flow

Almost every LLD round follows the same arc. Run it explicitly and narrate as you go.

1. Clarify requirements and scope (3–5 min). Pin down what is in. For a parking lot: How many vehicle types? Multiple floors? Is pricing flat or tiered by spot size? Do we handle payments, or just entry/exit? Lost tickets? Resist the urge to build everything - agree on a v1 scope out loud. This step alone separates strong candidates; weak ones start coding immediately and design the wrong system.

2. Identify the core entities and relationships (5 min). Name the nouns: Vehicle, ParkingSpot, Ticket, ParkingLot, FeeStrategy. Sketch how they relate - a ParkingLot has many ParkingSpots; a Ticket references one Vehicle and one ParkingSpot. A quick class diagram (even ASCII) keeps you and the interviewer aligned.

3. Define interfaces and apply SOLID + patterns (5 min). Decide where polymorphism lives. Vehicles differ by type, so Vehicle is an abstract base. Pricing varies independently, so it becomes a FeeStrategy interface (Strategy pattern) injected into the lot. State which principle each decision serves - "I'm putting pricing behind an interface so we satisfy Open/Closed when a new rate plan arrives."

4. Write the code (15–20 min). Implement the core classes and the one or two methods that carry the system's logic (here: park and unpark). You do not need every getter. Make it compile and run in your head - interviewers notice when method signatures do not line up.

5. Walk through scenarios and discuss extensions (5 min). Trace a car parking and leaving. Then handle the follow-ups: "How would you add electric-vehicle charging spots?" or "Make it thread-safe." Show your design absorbs change without surgery.

Worked example: design a parking lot

This is the canonical LLD warm-up. Here is a clean design and code that runs.

Scope we agreed on: three vehicle types (motorcycle, car, truck); three spot sizes (small, medium, large) with fit rules; flat hourly pricing with a one-hour minimum; single floor; single entry/exit. We use the Strategy pattern for pricing and the abstract base + enum combo for vehicles and spots so new types are additive.

Entities and relationships

ParkingLot ──has many──> ParkingSpot ──holds──> Vehicle (abstract)
 │ ├─ Motorcycle
 ├──uses (Strategy)──> FeeStrategy ├─ Car
 │ └─ FlatHourlyFee └─ Truck
 └──issues──> Ticket ──references──> Vehicle, ParkingSpot

The code

from abc import ABC, abstractmethod
from datetime import datetime
from enum import Enum

class VehicleType(Enum):
 MOTORCYCLE = 1
 CAR = 2
 TRUCK = 3

class Vehicle(ABC):
 def __init__(self, plate: str, vtype: VehicleType):
 self.plate = plate
 self.vtype = vtype

class Motorcycle(Vehicle):
 def __init__(self, plate): super().__init__(plate, VehicleType.MOTORCYCLE)

class Car(Vehicle):
 def __init__(self, plate): super().__init__(plate, VehicleType.CAR)

class Truck(Vehicle):
 def __init__(self, plate): super().__init__(plate, VehicleType.TRUCK)

class SpotType(Enum):
 SMALL = 1
 MEDIUM = 2
 LARGE = 3

# Fit rules: a motorcycle fits anywhere; a car needs MEDIUM+; a truck needs LARGE.
FIT = {
 VehicleType.MOTORCYCLE: {SpotType.SMALL, SpotType.MEDIUM, SpotType.LARGE},
 VehicleType.CAR: {SpotType.MEDIUM, SpotType.LARGE},
 VehicleType.TRUCK: {SpotType.LARGE},
}

class ParkingSpot:
 def __init__(self, spot_id: str, spot_type: SpotType):
 self.spot_id = spot_id
 self.spot_type = spot_type
 self.vehicle = None

 def is_free(self) -> bool:
 return self.vehicle is None

 def can_fit(self, vehicle: Vehicle) -> bool:
 return self.spot_type in FIT[vehicle.vtype]

 def park(self, vehicle: Vehicle):
 self.vehicle = vehicle

 def vacate(self):
 self.vehicle = None

class Ticket:
 def __init__(self, ticket_id: str, vehicle: Vehicle, spot: ParkingSpot):
 self.ticket_id = ticket_id
 self.vehicle = vehicle
 self.spot = spot
 self.issued_at = datetime.now()

# --- Strategy pattern: pricing varies independently of the lot ---
class FeeStrategy(ABC):
 @abstractmethod
 def compute(self, ticket: Ticket, exit_time: datetime) -> float: ...

class FlatHourlyFee(FeeStrategy):
 def __init__(self, rate_per_hour: float):
 self.rate = rate_per_hour

 def compute(self, ticket: Ticket, exit_time: datetime) -> float:
 seconds = (exit_time - ticket.issued_at).total_seconds()
 hours = max(1, -(-int(seconds) // 3600)) # ceil, minimum 1 hour
 return hours * self.rate

class ParkingLot:
 def __init__(self, spots, fee_strategy: FeeStrategy):
 self.spots = spots # composition: lot HAS spots
 self.fee_strategy = fee_strategy # dependency injection
 self.tickets = {}
 self._counter = 0

 def _find_spot(self, vehicle: Vehicle):
 for spot in self.spots:
 if spot.is_free() and spot.can_fit(vehicle):
 return spot
 return None

 def park(self, vehicle: Vehicle) -> Ticket:
 spot = self._find_spot(vehicle)
 if spot is None:
 raise RuntimeError("Lot full for this vehicle type")
 spot.park(vehicle)
 self._counter += 1
 ticket = Ticket(f"T{self._counter}", vehicle, spot)
 self.tickets[ticket.ticket_id] = ticket
 return ticket

 def unpark(self, ticket_id: str, exit_time: datetime) -> float:
 ticket = self.tickets.pop(ticket_id)
 fee = self.fee_strategy.compute(ticket, exit_time)
 ticket.spot.vacate()
 return fee

Why this design scores well

  • Single Responsibility: ParkingSpot tracks occupancy, FeeStrategy prices, ParkingLot coordinates. No god-class.
  • Open/Closed: a new ElectricCar is one subclass plus one entry in FIT. A "weekend surge" price is a new FeeStrategy - zero edits to ParkingLot.
  • Dependency Inversion: ParkingLot depends on the FeeStrategy abstraction, so pricing is swapped at construction:
lot = ParkingLot(spots, FlatHourlyFee(2.0))
# later, no change to ParkingLot:
# lot = ParkingLot(spots, WeekendSurgeFee(2.0, multiplier=1.5))
  • Testable: every class is constructible in isolation. You can unit-test FlatHourlyFee.compute without a lot, or assert that a truck never lands in a small spot.

A quick trace: park a Car, the lot scans for the first free MEDIUM-or-LARGE spot, occupies it, returns ticket T1. On exit after 90 minutes, FlatHourlyFee ceilings to 2 hours and bills 2 × $2.00 = $4.00; the spot vacates and is reusable. (You can practice this and the rate-limiter variant on PracHub's LLD problem set.)

How to answer this in the interview

Narrate your reasoning - the interviewer is grading your process, not just the final code.

  • Lead with scope, not classes. Your first sentence should be a clarifying question. "Single floor or multi-floor? Do we price by time, spot size, or both?" Silence-then-coding reads as junior.
  • State the trade-off when you make a choice. "I'll model pricing as a Strategy rather than an if vehicle.type == chain, so new rate plans don't touch existing code." Naming the principle (Open/Closed) shows intent.
  • Prefer composition; justify any inheritance. Use an abstract Vehicle because the subtypes genuinely are vehicles. Do not subclass ParkingLot to make a PaidParkingLot - inject behavior instead.
  • Write less, but make it real. A compiling core (entities + the two methods that carry logic) beats fifteen half-finished stub classes. Leave getters implied.
  • Call out what you are deferring. "I'm skipping concurrency for v1 but I'd guard park with a lock or a per-spot CAS." This shows you see the gap and chose to defer it deliberately.

The anti-patterns that sink candidates: a single 200-line god-class, deep inheritance trees, hardcoded if/elif chains where polymorphism belongs, and code that would not actually compile.

Common follow-up questions

Interviewers extend the base problem to probe depth. Be ready for:

  • "Make it thread-safe." Concurrent park calls can hand the same spot to two cars. Discuss a per-lot lock (simple, low throughput) versus per-spot atomic compare-and-set on the is_free → occupied transition (more concurrency). Mention that _find_spot + park must be one atomic step.
  • "Add a new vehicle type / spot size." Walk them through it live: one new enum value, one new Vehicle subclass, one line in FIT. The fact that nothing else changes is the point.
  • "Support multiple floors." Introduce a ParkingFloor owning spots; ParkingLot aggregates floors and delegates the search. A spot id becomes floor.spot.
  • "Price by spot size, not a flat rate." A new FeeStrategy (e.g., SizeBasedFee) - no change to ParkingLot. This is the payoff of the Strategy pattern; say so.
  • "How would you find the nearest available spot?" Move from a linear scan to a priority queue of free spots keyed by distance to entrance, updated on park/vacate.
  • "How do you test this?" Name concrete cases: truck rejected when only small spots remain, fee ceiling at the hour boundary, double-unpark of one ticket, lot-full behavior.

How to Use This Page as a Prep Plan

Do not treat this as passive reading. Convert the ideas in this page into a short weekly loop: learn one idea, practice it under interview conditions, then write down what changed. That is the fastest way to turn advice into visible interview behavior.

Prep areaWhat you need to provePractice artifact
UnderstandTurn the prompt into a concrete goal.Clarifying questions and success criteria.
PracticeUse realistic constraints and timed reps.Worked examples with edge cases.
ExplainMake reasoning visible.Tradeoffs, assumptions, and test strategy.
ImproveReview misses quickly.A short feedback log and next action.

For Low-Level Design Interview: What LLD Is and How to Crack It, the strongest candidates usually do three things well: they make their assumptions explicit, they use concrete examples instead of vague claims, and they review mistakes quickly enough that the next practice rep is better than the last one.

Conclusion

LLD interviews are won by judgment, not by memorizing the 23 design patterns. Internalize one repeatable flow - clarify, model entities, define interfaces with SOLID, write running code, then trace and extend - and lean on the five or six patterns that actually recur. The parking lot, rate limiter, elevator, and vending machine all yield to the same moves: find the axis of change, put it behind an interface, inject it, and keep each class responsible for exactly one thing. Drill three or four of these end-to-end until the structure is muscle memory, and the round stops being a guessing game.

FAQ

How should I use this guide?

Read it once for the structure, then turn each section into a practice task with a visible artifact.

What should I do if I am short on time?

Prioritize the skills most likely to be tested, then do one mock or timed drill to expose the largest gap.

How do I know I am ready?

You can explain your approach clearly, recover from hints, and name tradeoffs without relying on memorized wording.


Comments (0)


Related Articles

From Non-CS Major to Software Engineer: A Practical Guide to Cracking the Technical Interview

Prepare for technical interviews with a practical guide to DSA practice, live coding, mock interviews, communication, and interview mindset.

Software Engineer

From Non-CS Major to Software Engineer: A Practical Guide to Cracking the Technical Interview

Prepare for technical interviews with a practical guide to DSA practice, live coding, mock interviews, communication, and interview mindset.

Software Engineer

Design WhatsApp: the presence and receipt problems most candidates ignore

Design WhatsApp-style chat with WebSockets, offline inboxes, Kafka partitions, presence TTLs, receipts, and reliable delivery.

Software Engineer

I Pinned Our Autoscaler for a Month to See What Would Break. Nothing Did.

Learn when Kubernetes autoscaling helps, when CPU-based HPA wastes money, and how capacity planning can cut cloud costs safely.

Software Engineer
PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.