Skip to main content

Low Level Design Roadmap

16 topics · Foundational · Intermediate · Advanced

Progress0 / 29 completed (0%)
Level 1 — Foundational8 topics
#1OOP FundamentalsFoundational

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.

📄 Read full notes →
#2SOLID PrinciplesFoundational

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.

📄 Read full notes →
#3Object RelationshipsFoundational

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.

📄 Read full notes →
#4Interfaces vs Abstract ClassesFoundational

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.

📄 Read full notes →
#5Design PrinciplesFoundational

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.

📄 Read full notes →
#6UML & Class DiagramsFoundational

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.

📄 Read full notes →
#7Design Anti-Patterns & Code SmellsFoundational

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.

📄 Read full notes →
#8Null Safety & Null Object PatternFoundational

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.

📄 Read full notes →
Level 2 — Intermediate9 topics
#7Creational PatternsIntermediate

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.

📄 Read full notes →
#8Structural: Adapter & DecoratorIntermediate

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.

📄 Read full notes →
#9Structural: Facade & ProxyIntermediate

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.

📄 Read full notes →
#10Structural: Composite & BridgeIntermediate

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.

📄 Read full notes →
#11Behavioral: Observer & StrategyIntermediate

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.

📄 Read full notes →
#12Behavioral: Command & Template MethodIntermediate

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.

📄 Read full notes →
#17Flyweight PatternIntermediate

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.

📄 Read full notes →
#18Memento PatternIntermediate

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.

📄 Read full notes →
#19Visitor PatternIntermediate

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.

📄 Read full notes →
Level 3 — Advanced9 topics
#13Behavioral: Iterator & StateAdvanced

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).

📄 Read full notes →
#14Behavioral: Chain of Responsibility & MediatorAdvanced

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.

📄 Read full notes →
#15Dependency Injection & IoCAdvanced

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.

📄 Read full notes →
#16Concurrency PatternsAdvanced

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.

📄 Read full notes →
#20Immutability & Value ObjectsAdvanced

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.

📄 Read full notes →
#21Exception Hierarchy DesignAdvanced

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.

📄 Read full notes →
#22Enum-Based State MachinesAdvanced

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.

📄 Read full notes →
#23Functional Java PatternsAdvanced

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.

📄 Read full notes →
#24Domain Modeling BasicsAdvanced

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.

📄 Read full notes →
Level 4 — Expert3 topics
#25Object Pool & Resource ManagementExpert

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.

📄 Read full notes →
#26Event-Driven DesignExpert

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.

📄 Read full notes →
#27Clean Architecture & Layered DesignExpert

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.

📄 Read full notes →