Low Level Design Roadmap
16 topics · Foundational · Intermediate · Advanced
What to learn
The four pillars of OOP: encapsulation (hiding internal state), inheritance (reusing behaviour), polymorphism (same interface, different behaviour), and abstraction (exposing what matters, hiding how). Understand how classes and objects model real-world entities and why OOP improves modularity and reuse.
Resources
Covered by problems
📄 Read full notes →What to learn
Five principles for writing maintainable OO code: Single Responsibility (one reason to change), Open-Closed (open for extension, closed for modification), Liskov Substitution (subtypes must be substitutable), Interface Segregation (prefer narrow interfaces), Dependency Inversion (depend on abstractions, not concretions). SOLID violations are red flags in every OOD interview.
Resources
Covered by problems
📄 Read full notes →What to learn
How objects relate: association (uses-a, loose coupling), aggregation (has-a, independent lifecycle), composition (part-of, dependent lifecycle), and dependency (method parameter). Knowing when to use composition over inheritance is a core interview skill. Model these correctly and your class diagrams become self-documenting.
Resources
Covered by problems
📄 Read full notes →What to learn
Interfaces define contracts (what to do), abstract classes share partial implementations (how to do some of it). Know when each applies: prefer interfaces for capability definitions (Serializable, Comparable), abstract classes for shared state or template logic. In Java/C#, a class can implement multiple interfaces but extend only one abstract class.
Resources
Covered by problems
📄 Read full notes →What to learn
Beyond SOLID: DRY (Don't Repeat Yourself — one source of truth), YAGNI (You Ain't Gonna Need It — avoid premature abstraction), KISS (Keep It Simple), Law of Demeter (talk only to direct neighbours, avoid train wrecks), and Composition Over Inheritance (prefer delegation to deep hierarchies). These are the judgment calls interviewers watch for.
Resources
Covered by problems
📄 Read full notes →What to learn
Class diagrams show entities (classes/interfaces), their attributes, methods, and relationships. Sequence diagrams show message flow between objects over time. Interviewers expect a quick whiteboard sketch — not perfection. Focus on class names, key fields, relationships (solid line = association, hollow diamond = aggregation, filled diamond = composition, hollow arrow = inheritance), and the arrows' direction.
Resources
Covered by problems
📄 Read full notes →What to learn
Recognize bad design before it spreads. God Class (one class that does everything), Anemic Domain Model (data bags with no behaviour), Feature Envy (method uses another class more than its own), Data Clump (groups of fields that always appear together), and Primitive Obsession (using primitives instead of domain types). Interviewers often show broken code and ask what is wrong — this vocabulary lets you name the problem precisely.
Resources
📄 Read full notes →What to learn
NullPointerException is the most common Java runtime error and a red flag in interviews. The Null Object pattern returns a no-op object instead of null, eliminating defensive null checks throughout the codebase. Java Optional<T> lets you express "may or may not have a value" in the type system. Key rule: never call Optional.get() without isPresent(), and never return null from a public API.
Resources
📄 Read full notes →What to learn
Control object creation: Factory Method (let subclasses decide which class to instantiate), Abstract Factory (families of related objects), Builder (construct complex objects step-by-step), Singleton (ensure one instance), Prototype (clone existing objects). Factory and Builder are the most common in LLD interviews. Know the tradeoffs — Singleton is often a testing anti-pattern.
Resources
Covered by problems
What to learn
Adapter wraps an incompatible interface to make it compatible — like a power adapter. Use when integrating third-party APIs. Decorator wraps an object to add behaviour dynamically without subclassing — like stacking toppings. Use for cross-cutting concerns (logging, caching, validation) that should not pollute core classes.
Resources
Covered by problems
📄 Read full notes →What to learn
Facade provides a simplified interface to a complex subsystem — a single entry point that hides internal complexity. Proxy controls access to another object: virtual proxy (lazy init), protection proxy (access control), remote proxy (local stand-in for remote resource), caching proxy. Very common in LLD interviews involving authentication or lazy loading.
Resources
Covered by problems
📄 Read full notes →What to learn
Composite lets you treat individual objects and compositions uniformly — perfect for tree structures (file systems, UI hierarchies, org charts). Bridge separates an abstraction from its implementation so both can vary independently — use when you want to avoid a multiplicative explosion of subclasses across two dimensions.
Resources
Covered by problems
📄 Read full notes →What to learn
Observer defines a one-to-many dependency — when one object changes, all dependents are notified automatically. Core of event-driven systems and pub/sub. Strategy encapsulates interchangeable algorithms behind an interface — swap sorting, payment, or routing logic at runtime without changing the client. Both are extremely common in machine-coding rounds.
Resources
Covered by problems
📄 Read full notes →What to learn
Command encapsulates a request as an object, enabling undo/redo, queuing, logging, and macro-commands. Template Method defines the skeleton of an algorithm in a base class, letting subclasses override specific steps without changing the structure. Use Template Method when you have multiple algorithms with the same outline but different steps.
Resources
Covered by problems
What to learn
Share fine-grained objects to reduce memory when you have thousands or millions of similar objects. Split state into intrinsic (shared, immutable — stored in the flyweight) and extrinsic (per-instance — passed in by the caller). Classic example: a chess piece type object shared across all instances of that piece on the board. The FlyweightFactory caches and returns existing instances instead of creating new ones.
Resources
Covered by problems
📄 Read full notes →What to learn
Capture and restore an object's internal state without exposing its internals — the foundation of undo/redo. Three roles: Originator (creates and restores from memento), Memento (opaque snapshot of state), Caretaker (stores and manages mementos, does not inspect them). Pairs directly with Command: Command executes an action, Memento records the state to roll back to.
Resources
Covered by problems
📄 Read full notes →What to learn
Add new operations to a type hierarchy without modifying the types. A Visitor object implements one visit() method per type in the hierarchy; each type calls accept(visitor) which dispatches to the right visit() overload — this is double dispatch. Use when you have a stable set of types but frequently add new operations (serialise, render, export, validate). Hard conceptual question at Google/Amazon senior level.
Resources
Covered by problems
📄 Read full notes →What to learn
Iterator provides a standard way to traverse a collection without exposing its internal structure. State allows an object to change its behaviour when its internal state changes — the object appears to change its class. Essential for modelling state machines: elevator (idle/moving/open), vending machine (idle/selecting/dispensing/collecting).
Resources
Covered by problems
📄 Read full notes →What to learn
Chain of Responsibility passes a request along a chain of handlers — each decides to handle it or pass it on. Perfect for middleware pipelines, validation chains, and request filters. Mediator centralises complex communication between components behind a single object, reducing direct dependencies. Use for GUI components, chat rooms, air traffic control.
Resources
Covered by problems
📄 Read full notes →What to learn
Dependency Injection (DI) means providing an object's dependencies from outside rather than creating them internally — constructor injection, setter injection, or interface injection. Inversion of Control (IoC) is the broader principle: the framework calls your code, not the other way around. DI makes code testable (swap real DBs for mocks) and decoupled.
Resources
Covered by problems
📄 Read full notes →What to learn
Thread-safe design: Producer-Consumer with a bounded blocking queue, Reader-Writer lock (multiple readers OR one writer), Thread Pool (reuse threads to avoid creation overhead), Monitor pattern (synchronised methods + wait/notify). Key concepts: mutual exclusion, deadlock prevention, liveness. Essential for rate limiter, cache, and any shared-resource LLD problem.
Resources
Covered by problems
📄 Read full notes →What to learn
Immutable objects need zero synchronisation — the simplest concurrency strategy. Make fields final, return defensive copies of collections, and provide no setters. Value Objects have no identity — two Money(100, USD) instances are equal regardless of reference. Java 16+ records are value objects by default. Distinguish from Entities (identity-based equality, mutable): Order is an Entity, Money is a Value Object.
Resources
Covered by problems
📄 Read full notes →What to learn
Design exceptions that communicate domain intent. Checked exceptions (extends Exception) signal recoverable conditions — the caller must handle them. Unchecked exceptions (extends RuntimeException) signal programming errors — let them propagate. Build a hierarchy: BookingException → SeatUnavailableException, InsufficientFundsException. Fail-fast: validate inputs at boundaries and throw early rather than propagating bad state deep into the system.
Resources
Covered by problems
📄 Read full notes →What to learn
Java enums with abstract methods are a lightweight alternative to the class-per-state State pattern when states are fixed and transitions are simple. Each enum constant overrides the abstract method with its own behaviour. Add a transition() method that enforces valid transitions and throws IllegalStateException for invalid ones. Reach for this idiom first in interviews — it is concise, readable, and avoids the boilerplate of full State pattern classes.
Resources
Covered by problems
📄 Read full notes →What to learn
Java 8+ idioms expected in every modern interview. Stream pipeline: filter → map → collect. groupingBy() for aggregations. Optional chaining: map/flatMap/orElse instead of null checks. Functional interfaces: Function<T,R>, Predicate<T>, Supplier<T>, Consumer<T>. Comparator.comparing() for concise sorting. Method references (Class::method) over verbose lambdas. Writing for-loops when streams apply is a signal of dated knowledge.
Resources
📄 Read full notes →What to learn
Translate a problem statement into a class model. Entity: has identity, mutable, persisted (Order, User). Value Object: no identity, immutable, equality by value (Money, Address). Aggregate: consistency boundary with a root entity that controls all access to internal objects (Order owns OrderItems). Repository: collection abstraction that hides persistence details. Service: stateless operation that does not belong on any entity. Avoid the Anemic Domain Model — put behaviour on entities, not in service methods.
Resources
Covered by problems
📄 Read full notes →What to learn
Reuse expensive objects (DB connections, threads, HTTP clients) instead of creating and destroying them repeatedly. Pool maintains a bounded set of idle objects. Borrower calls acquire() — blocks or times out if none available. Returns object via release(). Implementation: Semaphore bounds total connections, BlockingQueue holds idle objects, health-check on borrow, scheduled eviction of idle-too-long objects. The canonical hard concurrency problem in LLD interviews.
Resources
Covered by problems
📄 Read full notes →What to learn
Decouple components by having them communicate through events rather than direct calls. Domain events are immutable data records (OrderPlaced, TripCompleted). Publisher raises events; handlers subscribe and react. Synchronous dispatch: handlers called inline in the same thread. Asynchronous: events queued and processed later. Distinguish from Observer: Observer is a pattern, event-driven is an architecture style. Use to model multi-actor workflows where each state transition triggers downstream reactions.
Resources
Covered by problems
📄 Read full notes →What to learn
Structure code so the domain layer has zero dependencies on infrastructure. Three layers: Domain (entities, value objects, domain services — pure Java, no frameworks), Application Service (orchestrates domain objects, no business logic itself), Infrastructure/Adapter (repositories, APIs, external services). The Dependency Rule: inner layers never import outer layers. Ports and adapters: domain defines interfaces (ports), infrastructure provides implementations (adapters). Makes domain logic testable without a database or HTTP stack.
Resources
📄 Read full notes →