Skip to main content
Low-Level Design·Intermediate

LLD Interview Framework & Walkthrough

A repeatable 5-step framework for LLD interviews. Includes a complete walkthrough of the Parking Lot problem — the most commonly asked LLD problem — with class diagrams and code.

45 min read 5 sections 5 interview questions
OOPClass DiagramLLD FrameworkParking LotSOLID PrinciplesObject-Oriented DesignUMLEncapsulationAbstractionDependency InjectionLow Level Design Interview

The 5-Step LLD Framework

01

Clarify Scope (3-5 min)

Ask: What actors use the system? What are the core use cases? Any constraints (concurrency, scale)? For Parking Lot: 'Is this one lot or a network? What vehicle types? How is pricing structured?'

02

Extract Entities (5 min)

Read the requirements. Every noun is a potential class. Every verb is a potential method. For Parking Lot: ParkingLot, Floor, ParkingSpot, Vehicle, Ticket, PricingStrategy.

03

Design Class Structure (10-15 min)

Define classes, their attributes, and relationships. Use inheritance for is-a (CompactSpot is-a ParkingSpot). Use composition for has-a (ParkingLot has Floors). Define interfaces for extensibility points.

04

Implement Key Methods (15-20 min)

Focus on the most interesting 2-3 methods that demonstrate design thinking. For Parking Lot: park(), leave(), findAvailableSpot(). Show error handling and concurrency awareness.

05

Discuss Extensions (5 min)

Proactively raise: 'To add a new vehicle type, we'd just add a new Vehicle subclass — no changes to existing code.' This demonstrates Open/Closed awareness.

LLD Interview Framework — Design Process

Rendering diagram...

Parking Lot — Class Diagram with SOLID + Patterns Applied

Rendering diagram...

Parking Lot — Core Implementation

pythonFull Parking Lot Design
from abc import ABC, abstractmethod
from datetime import datetime
from enum import Enum
import threading
import uuid

class VehicleType(Enum):
    MOTORCYCLE = "motorcycle"
    CAR = "car"
    TRUCK = "truck"

class SpotType(Enum):
    COMPACT = "compact"    # motorcycles
    STANDARD = "standard"  # cars
    LARGE = "large"        # trucks

class Vehicle(ABC):
    def __init__(self, license_plate: str):
        self.license_plate = license_plate

    @property
    @abstractmethod
    def type(self) -> VehicleType: pass

    @property
    @abstractmethod
    def required_spot(self) -> SpotType: pass

class Car(Vehicle):
    @property
    def type(self): return VehicleType.CAR
    @property
    def required_spot(self): return SpotType.STANDARD

class Motorcycle(Vehicle):
    @property
    def type(self): return VehicleType.MOTORCYCLE
    @property
    def required_spot(self): return SpotType.COMPACT

class ParkingSpot(ABC):
    def __init__(self, spot_id: str, spot_type: SpotType):
        self.spot_id = spot_id
        self.spot_type = spot_type
        self._vehicle: Vehicle | None = None
        self._lock = threading.Lock()

    @abstractmethod
    def can_fit(self, vehicle: Vehicle) -> bool: pass

    def park(self, vehicle: Vehicle) -> bool:
        with self._lock:
            if self._vehicle or not self.can_fit(vehicle):
                return False
            self._vehicle = vehicle
            return True

    def leave(self) -> Vehicle | None:
        with self._lock:
            v = self._vehicle
            self._vehicle = None
            return v

    @property
    def is_available(self) -> bool:
        return self._vehicle is None

class StandardSpot(ParkingSpot):
    def can_fit(self, vehicle): return vehicle.required_spot == SpotType.STANDARD

class CompactSpot(ParkingSpot):
    def can_fit(self, vehicle): return vehicle.required_spot in (SpotType.COMPACT, SpotType.STANDARD)

class PricingStrategy(ABC):
    @abstractmethod
    def calculate_fee(self, ticket: "Ticket") -> float: pass

class HourlyPricing(PricingStrategy):
    RATES = {VehicleType.MOTORCYCLE: 1.0, VehicleType.CAR: 2.5, VehicleType.TRUCK: 4.0}
    def calculate_fee(self, ticket):
        hours = max(1, (ticket.exit_time - ticket.entry_time).seconds / 3600)
        return round(hours * self.RATES.get(ticket.vehicle.type, 2.5), 2)

class Ticket:
    def __init__(self, vehicle: Vehicle, spot: ParkingSpot):
        self.id = str(uuid.uuid4())[:8]
        self.vehicle = vehicle
        self.spot = spot
        self.entry_time = datetime.now()
        self.exit_time: datetime | None = None

class ParkingLot:
    _instance = None  # Singleton

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, spots: list[ParkingSpot], pricing: PricingStrategy):
        if hasattr(self, '_initialized'):
            return
        self.spots = spots
        self.pricing = pricing
        self.active_tickets: dict[str, Ticket] = {}
        self._initialized = True

    def park(self, vehicle: Vehicle) -> Ticket | None:
        for spot in self.spots:
            if spot.is_available and spot.can_fit(vehicle):
                if spot.park(vehicle):
                    ticket = Ticket(vehicle, spot)
                    self.active_tickets[ticket.id] = ticket
                    return ticket
        return None  # full

    def leave(self, ticket_id: str) -> float:
        ticket = self.active_tickets.pop(ticket_id, None)
        if not ticket:
            raise ValueError(f"Ticket {ticket_id} not found")
        ticket.exit_time = datetime.now()
        ticket.spot.leave()
        return self.pricing.calculate_fee(ticket)
TIP

Concurrency Note

Always mention thread safety for LLD problems in interviews. Parking lots will have concurrent park() calls. The lock in ParkingSpot.park() ensures two threads can't park in the same spot simultaneously. At senior level, discuss optimistic locking vs pessimistic locking for different scenarios.

Interview Questions

Click to reveal answers
Test your knowledge

Sign in to take the Quiz

This topic has 16 quiz questions with instant feedback and detailed explanations. Sign in to unlock quizzes.

Sign in to take quiz →