π¨οΈ Print this page! This cheat sheet contains everything you need to review before an LLD interview.
β±οΈ The 45-Minute Framework
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 1: REQUIREMENTS (5 min) β
β β What are the core features? (ask for top 3-4) β
β β Who are the users/actors? β
β β Any scale/performance constraints? β
β β What's explicitly OUT of scope? β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PHASE 2: CORE DESIGN (20 min) β
β β Identify nouns β Classes β
β β Identify verbs β Methods β
β β Define relationships (is-a, has-a, uses) β
β β Draw class diagram with key attributes/methods β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PHASE 3: IMPLEMENTATION (15 min) β
β β Code the core happy path β
β β Apply relevant design patterns β
β β Handle important edge cases β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PHASE 4: DISCUSSION (5 min) β
β β Explain your trade-offs β
β β Discuss how to extend for new requirements β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Pro Move: If running low on time, skip some implementation and explain what you would do. Interviewers value thought process over perfect code.
π Requirements Gathering Questions
Always ask before designing:
| Category | Questions to Ask | Why It Matters |
|---|
| Scope | What are the must-have features? What can we skip? | Prevents over-engineering |
| Users | Who interacts with the system? (Customer, Admin, System) | Defines access control needs |
| Scale | Single machine or distributed? How many concurrent users? | Threading/locking decisions |
| Data | What needs to be persisted? Any real-time requirements? | Database design |
| Edge Cases | What happens on failure? Concurrent access handling? | Shows senior thinking |
ποΈ OOP Quick Reference
The Four Pillars - One-Liner Each
| Pillar | What It Means | Code Signal |
|---|
| Encapsulation | Hide internals, expose interface | private fields + public methods |
| Abstraction | Define WHAT, hide HOW | abstract classes, interfaces |
| Inheritance | Share behavior from parent | extends / : Base |
| Polymorphism | Same interface, different behavior | Override methods, common interface |
# 1. ENCAPSULATION - Bundle data + methods, hide internals
class Account:
def __init__(self):
self.__balance = 0 # Private (use __ prefix)
def deposit(self, amount): # Public interface
if amount > 0:
self.__balance += amount
@property
def balance(self): # Read-only access
return self.__balance
# 2. ABSTRACTION - Define what, not how
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass # Subclasses MUST implement
# 3. INHERITANCE - Reuse and extend
class Dog(Animal): # Dog IS-A Animal
def __init__(self, name):
super().__init__(name)
self.breed = None
def speak(self): # Override parent
return "Woof!"
# 4. POLYMORPHISM - Same interface, different behavior
def make_sound(animal: Animal):
print(animal.speak()) # Works for Dog, Cat, Bird...
make_sound(Dog("Rex")) # "Woof!"
make_sound(Cat("Luna")) # "Meow!"
β‘ SOLID Principles
| Principle | One-Liner | Code Smell |
|---|
| S - Single Responsibility | One class = one reason to change | Class has 10+ methods doing different things |
| O - Open/Closed | Open for extension, closed for modification | Adding feature requires editing existing classes |
| L - Liskov Substitution | Subtypes must be substitutable | Subclass throws βnot implementedβ exceptions |
| I - Interface Segregation | Many specific interfaces > one general | Class implements interface methods it doesnβt need |
| D - Dependency Inversion | Depend on abstractions, not concretions | Class instantiates dependencies with new |
Quick Examples
# β SRP Violation
class User:
def save_to_db(self): pass # Persistence
def send_email(self): pass # Notification
def generate_report(self): pass # Reporting
# β
SRP Applied
class User: pass
class UserRepository:
def save(self, user): pass
class EmailService:
def send(self, user, msg): pass
# β DIP Violation
class OrderService:
def __init__(self):
self.db = MySQLDatabase() # Concrete dependency
# β
DIP Applied
class OrderService:
def __init__(self, db: Database): # Abstract dependency
self.db = db
π§© Design Patterns Cheat Sheet
When to Use What?
| Situation | Pattern | Example |
|---|
| Need only ONE instance | Singleton | Database, Logger, Config |
| Create objects without specifying class | Factory | Vehicles, Notifications, Payments |
| Complex object with many optional parts | Builder | Pizza, HTTP Request, Query |
| Make incompatible interfaces work | Adapter | Legacy system integration |
| Add features dynamically | Decorator | Coffee toppings, Middleware |
| Simplify complex subsystem | Facade | Video converter, Payment gateway |
| Swap algorithms at runtime | Strategy | Sorting, Payment, Shipping |
| Notify many objects of changes | Observer | Stock price, Notifications |
| Object behavior changes with state | State | Order status, Elevator, ATM |
| Undo/redo operations | Command | Text editor, Transactions |
Pattern Code Templates
Singleton
Factory
Strategy
Observer
State
import threading
class Database:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock: # Thread-safe
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def query(self, sql):
pass
# Usage
db1 = Database()
db2 = Database()
assert db1 is db2 # Same instance
from abc import ABC, abstractmethod
class Notification(ABC):
@abstractmethod
def send(self, message: str): pass
class EmailNotification(Notification):
def send(self, message):
print(f"Email: {message}")
class SMSNotification(Notification):
def send(self, message):
print(f"SMS: {message}")
class NotificationFactory:
@staticmethod
def create(channel: str) -> Notification:
factories = {
"email": EmailNotification,
"sms": SMSNotification,
}
return factories[channel]()
# Usage
notification = NotificationFactory.create("email")
notification.send("Hello!")
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> bool: pass
class CreditCard(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} via Credit Card")
return True
class PayPal(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} via PayPal")
return True
class ShoppingCart:
def __init__(self, strategy: PaymentStrategy):
self.strategy = strategy
def checkout(self, amount):
return self.strategy.pay(amount)
# Usage - swap strategy at runtime
cart = ShoppingCart(CreditCard())
cart.checkout(100)
cart.strategy = PayPal() # Switch!
cart.checkout(50)
from abc import ABC, abstractmethod
class Observer(ABC):
@abstractmethod
def update(self, subject): pass
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer: Observer):
self._observers.append(observer)
def detach(self, observer: Observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update(self)
class Stock(Subject):
def __init__(self, symbol: str):
super().__init__()
self.symbol = symbol
self._price = 0
@property
def price(self):
return self._price
@price.setter
def price(self, value):
self._price = value
self.notify() # Notify on change
class Investor(Observer):
def update(self, subject):
print(f"Stock {subject.symbol}: ${subject.price}")
# Usage
stock = Stock("AAPL")
stock.attach(Investor())
stock.price = 150 # Triggers notification
from abc import ABC, abstractmethod
class State(ABC):
@abstractmethod
def handle(self, context): pass
class DraftState(State):
def handle(self, context):
print("Document is draft. Moving to review.")
context.state = ReviewState()
class ReviewState(State):
def handle(self, context):
print("Document in review. Moving to published.")
context.state = PublishedState()
class PublishedState(State):
def handle(self, context):
print("Already published!")
class Document:
def __init__(self):
self.state = DraftState()
def proceed(self):
self.state.handle(self)
# Usage
doc = Document()
doc.proceed() # Draft β Review
doc.proceed() # Review β Published
doc.proceed() # Already published!
π UML Class Diagram Notation
ββββββββββββββββββββββββββββββββββββββββββββββββ
β ClassName β
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β + publicAttr: Type β + = Public
β - privateAttr: Type β - = Private
β # protectedAttr: Type β # = Protected
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β + publicMethod(): ReturnType β
β - privateMethod(): void β
ββββββββββββββββββββββββββββββββββββββββββββββββ
RELATIONSHIPS:
βββββββββββββββββββββββββββββββββββββββββββββββ
A βββββββββ· B INHERITANCE: A extends B
A - - - - β· B IMPLEMENTATION: A implements B
A ββββββββββ B COMPOSITION: A contains B (B dies with A)
A ββββββββββ B AGGREGATION: A has B (B can exist alone)
A - - - - -> B DEPENDENCY: A uses B
A ββββββββββ> B ASSOCIATION: A knows B
βββββββββββββββββββββββββββββββββββββββββββββββ
MULTIPLICITY: 1, 0..1, *, 1..*, n..m
π¨ Common Interview Problems
Parking Lot System
Classes: ParkingLot, Floor, ParkingSpot, Vehicle, Ticket, Payment
Patterns: Strategy (payment), Singleton (parking lot)
Key: Different spot sizes for different vehicles
Elevator System
Classes: Elevator, ElevatorController, Floor, Button, Request
Patterns: State (elevator states), Strategy (scheduling)
Key: Multiple elevators, efficient scheduling algorithms
Library Management
Classes: Library, Book, BookCopy, Member, Lending, Reservation
Patterns: Strategy (search), Observer (notifications)
Key: Book vs BookCopy distinction, reservation queue
Chess Game
Classes: Game, Board, Piece (King, Queen, etc.), Move, Player
Patterns: Factory (piece creation), Command (moves for undo)
Key: Each piece type has unique move validation
β Interview Discussion Points
Be ready to answer:
- βWhy did you use inheritance here instead of composition?β
- βHow would you add a new payment method?β
- βWhat happens if two users try to book the same spot?β
- βHow would you handle this at 10x scale?β
- βWhere would you add logging/monitoring?β
- βHow would you test this design?β
Power phrases:
- βI chose X over Y becauseβ¦β
- βThe trade-off here isβ¦β
- βThis follows the Open/Closed principle becauseβ¦β
- βAdding new feature Z would just requireβ¦β
- βFor concurrency, we could useβ¦β
β
Pre-Interview Checklist
Remember: LLD interviews test your thought process as much as your design. A simple, well-reasoned design beats a complex, unexplained one every time.