A study path for low-level design
Open in the interactive app: practice, quiz, mock interview →In one minute
- Low-level design is a skill, not a body of facts: turning a fuzzy requirement into classes, interfaces, state and interactions that are correct, testable and cheap to change. You learn it by producing designs, getting feedback and changing them.
- Learn in layers that depend on each other: OOP fundamentals, then class relationships, then principles, then UML for communication, then patterns, then full design problems.
- Every topic follows one loop: read, implement from memory, test the invariants, then apply a requirement change.
- Spread practice out: reviews 1, 3, 7 and 14 days after learning beat rereading four times in one evening.
- In the AI era the scarce skill is judgement: an assistant writes a plausible class hierarchy in seconds, and your value is knowing whether it is right.
How it works
What you are actually learning
High-level design decides which services exist and how data flows between them; low-level design decides what happens inside one: which objects exist, who owns which state, what each interface promises, and how behaviour varies without a pile of if statements. Three sub-skills make up the whole:
- Modelling. Reading a requirement and seeing the entities, their lifecycles and the rules that must always hold (a seat is never sold twice, a balance never goes negative).
- Judgement. Choosing between alternatives, such as composition or inheritance, an enum or a class hierarchy, a pattern or a plain function, and being able to say what each choice costs.
- Communication. Explaining a design so a reviewer can follow it in a few minutes: a class diagram, a sequence of calls, and the reasons.
Vocabulary (pattern names, the letters of SOLID) is the easy part; the path below gives each of these three skills something to practise on.
The learning path through this course
Each stage lists the lessons in this course that cover it.
- Foundations: objects and types. Classes and Objects, Enums, Interfaces, Encapsulation, Abstraction, Inheritance, Polymorphism. Goal: you can explain what an object is in memory, why fields are private, and how a call on an interface finds the right method.
- Relationships. Association, Aggregation, Composition, Dependency, Realization. Goal: for any two classes you can say who creates whom, who owns whom, and what breaks if one is deleted.
- Principles. DRY Principle, KISS Principle, YAGNI Principle, Law of Demeter, Coupling and Cohesion, then the SOLID set: Single Responsibility Principle, Open/Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, Dependency Inversion Principle. Goal: you can name the principle a piece of code violates and propose the smallest fix.
- Communication with UML. Class Diagram, Use Case Diagram, Sequence Diagram, Activity Diagram, State Machine Diagram. Goal: sketch a design in under five minutes using only the notation a reviewer needs.
- Patterns. Creational: Singleton, Factory Method, Abstract Factory, Builder, Prototype. Structural: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy. Behavioural: Strategy, Observer, State, Command, Template Method, Iterator, Chain of Responsibility, Mediator, Memento, Visitor, Null Object Pattern. Goal: for each one, the problem it solves, the simpler alternative, and when it is overkill.
- Design problems. Start with small, closed worlds (Design Tic Tac Toe, Design Snake and Ladder Game, Design LRU Cache, Design Bloom Filter), move to state machines (Design Vending Machine, Design Elevator System, Design Parking Lot), then time and concurrency (Design Rate Limiter, Design Task Scheduler, Design Logging Framework), and finish with money and contention (Design Splitwise, Design Movie Booking System).
The order is a prerequisite graph, not a strict line. Strategy needs Interfaces and Polymorphism; the Open/Closed Principle needs Strategy-like thinking; Design Vending Machine needs State and the State Machine Diagram. If a lesson feels like magic, walk back along its prerequisites rather than rereading it.
The practice loop for every topic
Reading gives recognition, which feels like understanding and is not. For each topic:
- Read once, slowly, and close it.
- Implement from memory the smallest version that shows the idea: a Strategy with two strategies, not a framework.
- Write tests first for the behaviour, then for the invariants. "A full parking lot rejects a car" is behaviour; "a spot is never assigned to two vehicles" is an invariant.
- Apply a change request. Add a new vehicle type, a new payment method, a second currency. Count the files you touched; that is the honest measure of your design.
- Port it to a second language. It shows which parts were the idea and which were the language: Go has no inheritance, TypeScript checks shapes rather than names.
Spacing and retrieval
Two findings from learning research matter here. Retrieving something from memory strengthens it more than re-reading it (the testing effect), and retrieval spread over growing gaps beats the same amount crammed together (the spacing effect). A practical schedule: after first learning a topic, review it 1, 3, 7, 14 and 30 days later. A review is not rereading; it is redoing a five-minute version of step 2 from a blank file, or answering the lesson's Check yourself questions without looking. If you fail a review, restart that topic's schedule from today. The practice task in this lesson builds exactly this scheduler.
Learning with an AI assistant
Use an assistant as a sparring partner, not an author. Ask it to play an interviewer who keeps changing requirements, to critique your diagram against a named principle, or to generate a design in which you find three problems before reading its own critique. Asking for "the design of a parking lot" and reading the answer only trains recognition. Agents tend to over-produce structure (an interface and a factory for everything), so reviewing generated designs is excellent practice for YAGNI and KISS.
The same shape elsewhere
Ordering topics by prerequisites is the ordering problem shape: a directed acyclic graph that must be walked so every node comes after its dependencies. Build systems order compile steps this way, package managers order installs, schema migration tools order migrations, and a task scheduler orders jobs. Recognising the shape means you reach for a topological sort, cycle detection and a tie-break rule, whatever the domain.
Down the stack
Layer 1The contract
"Knowing LLD" should be testable. A reasonable contract: given a two-paragraph requirement, within 45 minutes you produce a class diagram, the key call sequence, and working code for the core operations with tests for the invariants; when given a change request, you can predict which classes change before touching them, and be right. Each lesson's Practice and Mock interview are small instances of it.
Layer 2The mechanism
Experts do not store patterns as definitions; they store chunks: "a thing with modes that change behaviour" maps to State, "many listeners, one source" maps to Observer. Chunks form from many worked instances, not from one long chapter. Interleaving helps chunks form: mixing Strategy, State and Command problems in one session forces you to decide which applies, which blocked practice never asks. Each spaced review is a retrieval that strengthens a chunk; a failed review means the chunk never formed and needs a fresh worked example.
Layer 3The machine
Every design becomes memory and instructions, and "elegant" designs sometimes cost real performance. In CPython, an ordinary object carries a 16-byte header plus an attribute dict (classes with __slots__ drop the dict), so a million small objects can cost on the order of 100 MB. A Go struct has no header at all; wrapping it in an interface makes a two-word value (an itab pointer and a data pointer), and storing a non-pointer value in an interface usually forces a heap allocation. V8 gives objects that are constructed the same way a shared hidden class, so field access becomes a fixed offset; adding fields in different orders creates different hidden classes and slows property access. An interface call costs a few nanoseconds and usually blocks inlining, which matters only in hot loops; deep object graphs mean pointer chasing at about 100 ns per cache miss. The pattern lessons each end with these costs.
Why it's built this way
- Design skill is judgement under change, so the path ends in design problems with change requests, not in a catalogue.
- Judgement needs vocabulary, so principles and patterns come before problems.
- Patterns are combinations of interfaces, polymorphism and composition, so those come first.
- Memory for skills decays without retrieval, so the loop asks you to rebuild from a blank file on a spaced schedule.
- Designs run on machines and are maintained by teams, so every lesson ends in runtime cost and leadership concerns.
Diagram
flowchart LR A["OOP foundations"] --> B["Relationships"] A --> C["Principles and SOLID"] B --> D["UML diagrams"] C --> E["Design patterns"] B --> E D --> F["Design problems"] E --> F F --> L["Practice loop"] L --> R1["Implement from memory"] R1 --> R2["Test invariants"] R2 --> R3["Apply a change request"] R3 --> R4["Review in 1, 3, 7, 14 days"] R4 --> R1
Worked example
Priya has five hours a week and an interview loop in eight weeks: 40 hours. The full course (about 60 lessons, 45 minutes per concept and 2 hours per design problem) needs about 60, so she triages.
- Weeks 1 to 2: the 12 foundation and relationship lessons at 40 minutes each, 8 hours.
- Week 3: the five SOLID lessons plus KISS, YAGNI and Coupling and Cohesion, 5.3 hours.
- Week 4: Class Diagram, Sequence Diagram and State Machine Diagram, 2 hours.
- Weeks 5 to 6: the eight patterns that recur most in design problems (Strategy, Observer, State, Factory Method, Builder, Decorator, Command, Singleton) at 50 minutes each, 6.7 hours.
- Weeks 7 to 8: six design problems at 90 minutes each, 9 hours: 45 minutes against a timer, one change request, then comparison with the lesson.
That is 31 hours. The 31 topics with three five-minute reviews each (1, 3 and 7 days) add 7.75 hours, for a total just under 40. The practice scheduler below produces her daily agenda: a typical day in week 3 shows two new topics and four reviews.
Trade-offs
| Approach | Strengths | Weaknesses | Choose when |
|---|---|---|---|
| Catalogue first | Complete vocabulary | Patterns without problems are soon forgotten | You already design daily and want names |
| Problem first | Motivating; mirrors interviews | Weak fundamentals show as tangled designs | Interviews soon, fundamentals solid |
| Layered path with spaced review | Durable; each layer supports the next | Slower to feel productive | Building the skill for the long term |
| AI-generated designs to critique | Unlimited, varied review material | Easy to slide into passive reading | Practising judgement and code review |
Pitfalls in production
- Memorising patterns as templates. Factory plus Strategy plus Observer forced into every answer. Fix: learn each pattern's simpler alternative and when it is overkill.
- Designing without tests. A class diagram can look right and hide a broken invariant. Fix: write at least one test per invariant before calling a design done.
- One language's idioms as universal. Deep Java-style inheritance looks wrong in Go. Fix: port each design to a second language.
- Re-reading instead of retrieving. Three readings feel productive and leave little behind. Fix: every review starts from a blank file or a blank page.
- Never applying a change. A design is only good relative to the changes it absorbs. Fix: every practice session ends with a change request and a count of files touched.
Leadership lens
- Teams grow LLD skill through design reviews with a written rubric (invariants named, change scenarios considered, simpler alternative stated), not pattern lectures.
- Ask in review: "Which requirement change would hurt this design most, and what would it cost?"
- Pair juniors on change requests to existing code; most real LLD work extends someone else's design.
- Budget review time for structure, not just correctness: generated abstraction is cheap to write and expensive to maintain.
Check yourself
Why does the path put Interfaces and Polymorphism before any design pattern?
Show answer
Most patterns are arrangements of interfaces, polymorphic dispatch and composition, so without those a pattern is a shape to copy rather than a mechanism you understand and can adapt.
You reread the Observer lesson three times and still cannot write it from scratch. What should you change?
Show answer
Switch to retrieval: write the smallest Observer from a blank file, check it against the lesson, and retry a few days later; repeated failure calls for a new worked example, not another reading.
Why does interleaving Strategy, State and Command problems help more than ten Strategy problems in a row?
Show answer
Mixed practice forces you to decide which pattern applies, which is the skill you need in real design and interviews; blocked practice skips that decision.
Watch
- Simple Made Easy (Rich Hickey, Strange Loop 2011): a vocabulary for judging designs that outlasts any pattern catalogue.
- Low-Level System Design RoadMap (The Code Skool): one practitioner's ordering of OOP, principles and patterns, to compare with the path here.
Free resources
- Refactoring.Guru design patterns: a free, well-illustrated catalogue to use as a reference alongside the pattern lessons.
- Beck Design Rules (Martin Fowler): four rules of simple design to judge your practice designs against.
- Spaced repetition (Wikipedia): background on spacing schedules and the research behind them.
- Testing effect (Wikipedia): why retrieval practice beats rereading.
- Code katas (Dave Thomas): small, repeatable exercises in the deliberate practice style this lesson recommends.