Brain
EngineeringLLD

Delivery framework for LLD

Five phases and a bonus round for taking a low level design from a blank page to working classes, with a tic-tac-toe example worked through end to end.

Run a low level design question in five phases: requirements, entities and flows, interfaces, implementation, walkthrough, then extensibility as a sixth. Each phase feeds the next, so you are never inventing structure on the spot.

The phases

#PhaseYou leave with
1RequirementsScope, constraints, assumptions, what is out
2Entities and flowsThe nouns, their attributes, who owns whom, the use cases
3InterfacesClass names, signatures, responsibilities. No bodies
4ImplementationBodies for the methods that matter
5WalkthroughOne flow traced through the code you just wrote
6ExtensibilityWhere a new requirement plugs in
The six phases in order from requirements down to extensibility. Two extra arrows run alongside the chain: the flows from phase 2 are reused as the trace in phase 5, and a gap found during the walkthrough sends you back to phase 3.

Phase 6 is the one to drop when the work has to stop somewhere. The other five are the design itself.

The example below is tic-tac-toe, small enough that the rules need no explaining.

Phase 1: Requirements

Ask until you can write the spec down and have whoever owns the problem agree with it. Four things to pin: what it must do, what the rules are, what happens when someone breaks a rule, and what you are not building.

For tic-tac-toe:

  • Two players alternate on a 3x3 board, X goes first.
  • A player wins with three of their symbol in a row, column, or diagonal.
  • A full board with no winner is a draw.
  • Playing on a taken cell, or playing once the game is over, is rejected, and the turn does not pass.
  • Out of scope: persistence, networking, AI opponent, more than two players.

Say the out of scope list out loud, otherwise the question grows while you are answering it.

Phase 2: Entities and flows

Pull the nouns out of the spec, give each one attributes and a single responsibility, then say how they connect. Do the flows in the same breath: narrate a use case and the missing entities show up on their own.

Entities:

  • Board holds a grid of cells and knows what is at each position.
  • Player has a symbol, X or O.
  • Game owns the board and the two players, and tracks whose turn it is.

Relationships: one game owns one board and exactly two players. The board owns its cells. Nothing points back upward, so there are no cycles to reason about.

Flows: start a game, take a turn, reject an invalid turn, end on a win, end on a draw.

Keep the ownership direction explicit. The usual mistake here is a child holding a reference back to its parent for no reason.

Phase 3: Interfaces

Turn entities into classes. For each one, decide state and behaviour, and write the signatures. No method bodies yet: this phase is about what each class promises, and bodies hide that behind detail.

Work top down from the class that orchestrates, here Game. Its method list tells you what everything below it has to provide.

WinStrategy is an interface rather than a method on Board because the win rule is the part most likely to change. That is a guess about the future, so justify it in one sentence and move on.

Game sits at the top and owns one Board and two Players, and asks a WinStrategy whether the last move won. WinStrategy is an interface, and LineWinStrategy is the implementation that checks rows, columns, and diagonals.

Phase 4: Implementation

Fill in the methods that carry the logic. Skip getters. Happy path first, then the rejections.

Both guards run before the turn advances, so a rejected move leaves the same player on turn. That was a requirement from phase 1.

Leaving a body as a comment is fine when the logic is a loop anyone can picture. Spend the time on the methods where a reviewer would disagree with you.

Phase 5: Walkthrough

Take a flow from phase 2 and run it through the code. This catches the errors that reading cannot.

X plays (0,0). Status is in progress, cell is empty, X is placed. No win, board is not full, turn passes to O. O plays (1,1), same path. X plays (0,1), then O plays (2,2), then X plays (0,2). hasWon finds X across the top row, status becomes WON, and the turn never advances, so the board freezes with X as the winner.

Then try to break it. O calls play(0,0) after the win and the first guard throws.

Phase 6: Extensibility

Take a requirement that was out of scope and show where it lands. If the answer is a new class, or a different implementation of an existing interface, the design held.

  • 4x4 board: new Board(4). Board was never hardcoded to 3.
  • Connect four style, four in a row: new LineWinStrategy(4). Game does not change.
  • A bot player: make Player an interface with a nextMove method, add a second implementation. Game still calls the same thing.
  • Undo: Game keeps a stack of moves, Board gains a clear(row, col). This one touches existing classes, so say so rather than pretending it is free.

Undo is the useful one to raise. Saying which change does not fit cleanly is worth more than claiming every change is a one liner.

What usually goes wrong

People rush phase 3 because writing signatures feels slower than writing code. It is the phase worth the most of your attention.

The other common miss is phase 5. A short trace catches mistakes that rereading the code will not.

On this page