Low-level design cheat sheet
How LLD interviews work
- What an LLD round really tests: LLD rounds grade working code, clear classes, extensibility and naming. Use five steps every time: clarify, find entities, draw classes, code the core, then extend.
- From requirements to classes: Ask clarifying questions first. Nouns suggest classes and verbs suggest methods, but some nouns are only fields and some classes are missing from the text. Give each class one job.
Object-oriented basics, the way interviewers check them
- Encapsulation and abstraction: Keep fields private and expose actions, such as debit and credit, that guard the invariants. Tell objects what to do. Hide how a job is done behind a small interface.
- Inheritance, composition and polymorphism: Inherit only for a true is-a, because subclasses break when parent internals change. Prefer holding an object (composition). Replace a repeated switch on type with classes behind one interface.
Class diagrams you can draw in five minutes
- Reading and drawing a class box: A class box has a name, fields and methods. Visibility is + public, - private, # protected, ~ package. Mark interfaces, abstract classes, enums and static members, and draw only members that matter.
- The six relationships and multiplicity: Association keeps a reference; dependency uses one briefly. Composition (filled diamond) owns parts that die with the whole; aggregation (hollow diamond) groups parts that live on. Inheritance and realisation end in hollow triangles.
SOLID, without the slogans
- Single responsibility, open/closed, Liskov: SRP: one reason to change per class. OCP: add new behaviour as new classes behind an interface. LSP: a subtype keeps its parent's contract, not only its method signatures.
- Interface segregation and dependency inversion: ISP: shape interfaces by what each caller uses. DIP: business code owns the interfaces and vendors implement them. DI passes the parts in through the constructor, so tests can pass fakes.
Creational patterns
- Factory and abstract factory: A factory puts the choice of concrete class in one place, so callers depend only on an interface. Abstract factory creates matching families. Use a plain constructor when the choice never varies.
- Builder and singleton: Use a builder for objects with many optional parts: named steps, checks in build(). Avoid singletons for shared state; create one instance in main and pass it in.
Structural patterns
- Adapter and facade: An adapter makes one existing class fit an interface you own, translating units, statuses and errors. A facade gives callers one simple method over several classes. Neither should hold business rules.
- Decorator, composite and proxy: A decorator wraps an object with the same interface to add behaviour, avoiding a subclass per combination. A composite treats a leaf and a tree alike. A proxy keeps the interface but controls access.
Behavioural patterns I
- Strategy: Strategy puts each version of a rule in its own class behind one interface, and the context can swap it at runtime. If only numbers change, use data. For two fixed cases, keep the switch.
- Observer: Observer lets a subject announce a change to a list of listeners it knows only by an interface. It runs in-process and at once. A message broker adds storage, retries and separate services.
Behavioural patterns II
- State and command: State puts each lifecycle stage in its own class, and the state picks the next state. Strategy is chosen from outside. Command turns an action into an object for undo, queues or retries.
- Chain of responsibility and template method: A chain passes a request through small handlers, each able to stop it. Template method fixes the order of steps in a base class. It uses inheritance; strategy uses composition and can change at runtime.
Modelling behaviour: sequence and state diagrams
- Sequence diagrams: A sequence diagram shows one scenario over time: solid arrows for calls, dashed for returns, alt for if and else, loop for repeats. Many self-calls on one lifeline point to a missing class.
- State machines and state diagrams: A state diagram lists states, events, transitions and guards; any move without an arrow is rejected. Code it as an enum with a table of allowed moves, or as State classes when behaviour differs.
Concurrency in LLD
- Thread safety basics: A race happens when threads interleave a check and an act. volatile gives visibility, not atomicity. Use atomics for one value, a lock for a rule, and take locks in one fixed order.
- Double booking and producer-consumer: Double booking is check-then-act on shared capacity. Lock per slot when conflicts are common; use a version check when they are rare. A bounded BlockingQueue hands slow work to workers.
The machine-coding round
- Planning the 90 minutes: Clarify and write the scope first. Write models and repository interfaces early, keep data in memory behind them, and have a main demo running by minute 75.
- How you are graded, and extending live: Rubrics grade working code, clear classes, extensibility, names, errors and communication. Test the rules. For "now add X", find the seam, add a class, and rerun the demo.