Purpose: This document teaches you how to systematically create detailed design guidelines for any Low-Level Design problem — in interviews or practice. Use it as your reference to decide inputs/outputs, know what questions to ask, and build the insight needed to excel at LLD.
- Part I: The LLD Mindset
- Part II: The Clarification Framework
- Part III: Input/Output Decision Framework
- Part IV: Universal Question Bank
- Part V: Domain-Specific Question Banks
- Part VI: Requirement Parsing & Entity Extraction
- Part VII: Design Guideline Creation Process
- Part VIII: Templates & Checklists
- Part IX: Interview Scripts & What to Say
- Part X: Practice Strategies & Self-Assessment
- Part XI: Pattern Recognition
- Part XII: Detailed Worked Examples
- Part XIII: Requirement Ambiguity Catalog
- Part XIV: Input/Output Anti-Patterns
- Part XV: Domain-Specific I/O Examples
- Part XVI: Interview Time Management
- Part XVII: Self-Questioning Prompts
- Part XVIII: Repo Problem Mapping
- Part XIX: Interview Readiness Checklist
- Part XX: Final Thoughts
When you're stuck on inputs/outputs, clarification, or design guidelines, it's usually because:
- Requirements are underspecified — They leave room for multiple valid interpretations.
- You don't have a framework — You don't know which questions to ask or how to organize your thinking.
- You jump to code — You start designing classes before you've locked down behavior.
- You assume instead of clarifying — You pick one interpretation silently and build on it, only to be surprised when the interviewer had something else in mind.
The fix: Treat clarification as a first-class phase. Design your process for design.
Never design before clarifying. Never clarify without a checklist. Never code before writing a design guideline.
Your mental model:
Requirements (vague) → Clarification (questions + assumptions) → Design Guideline (structured doc) → Code
If you skip the middle steps, you'll thrash.
A design guideline is not magic. It's the crystallization of your clarified requirements into:
- Assumptions table — What you decided (or the interviewer confirmed).
- Entity model — Nouns and relationships.
- Core logic — How flows work, step by step.
- Validations & edge cases — What can go wrong.
- Implementation order — What to build first.
The insight: If you ask the right questions and record the answers, the design guideline almost writes itself.
| Pillar | What It Means |
|---|---|
| Clarification | Ask questions; state assumptions; get agreement before designing. |
| Abstraction | Model the domain with clear entities; avoid god objects and procedural code. |
| Extensibility | Use Strategy, State, Observer, etc., so new behavior = new class, not new if/else. |
This guide focuses heavily on Clarification because that's where most people get stuck.
For any LLD problem, you need to clarify across these dimensions:
| Dimension | What You're Clarifying | Example Questions |
|---|---|---|
| Scope | What's in/out of the problem | "Should I include authentication, or focus only on the booking flow?" |
| State & Lifecycle | How entities evolve over time | "Does the auction have states like OPEN, CLOSED, ENDED?" |
| Inputs & Outputs | What goes in, what comes out | "What does the user provide when placing a bid? Just amount, or more?" |
| Rules & Invariants | What must always be true | "Can a buyer bid multiple times in the same auction?" |
| Edge Cases | Boundary conditions, error handling | "What if two users book the same seat simultaneously?" |
| Non-Functional | Concurrency, persistence, performance | "Should we assume single-threaded or handle concurrent access?" |
| Extensibility | What might change later | "Could we add new payment methods or routing strategies?" |
- Listen — Hear the full problem statement. Don't interrupt.
- Restate — "So if I understand correctly, we need to build X that does Y and Z."
- List open questions — Mentally or on paper, list what's ambiguous.
- Prioritize — Ask the highest-impact questions first (scope, core flows).
- State assumptions — For each question: "If you don't have a preference, I'll assume X."
- Record — Put your assumptions in a table. Reference it while designing.
Good:
- "Can a buyer place multiple bids in the same auction, or only one?"
- "When the cache is full, should we evict using LRU, LFU, or something else?"
- "If you don't mind, I'll assume we're building this in-memory for the interview. Is that okay?"
Bad:
- "How do bids work?" (too vague)
- "Should I use a HashMap?" (implementation detail; too early)
- "I think we need a database." (assuming without asking)
Pattern: Ask about behavior and rules, not implementation.
Inputs and outputs are hard because:
- Requirements rarely spell them out.
- There are often multiple valid designs.
- You're not sure what level of granularity to use.
Solution: Use a systematic framework.
For any operation (e.g., "place a bid", "park a vehicle", "fire at coordinate"):
Who is performing the operation?
- User, System, External Service, Another component
What information would they realistically have at call time?
- IDs (user, auction, vehicle)
- Values (amount, coordinates, payment details)
- Context (session, game state)
- Provided: Caller must supply (e.g.,
auctionId,amount) - Derived: System can infer (e.g.,
buyerIdfrom session,timestampfrom system)
- Prefer minimal necessary input — don't ask for things the system can derive.
- But don't omit required identifiers — e.g., if booking seats, you need
showIdandseatIds.
- Actor identified?
- All required identifiers included?
- No redundant fields (that can be derived)?
- Polymorphic input? (e.g.,
PaymentDetails— UPI vs Card — different shapes)
- Success/failure?
- Created resource (ID, full object)?
- Side effects (e.g., receipt printed)?
- Partial results (e.g., list of violations)?
- Return value:
Optional<T>,Result<T, E>,Either<L, R> - Exception: Domain exceptions (e.g.,
SeatAlreadyBookedException) - Error object:
PaymentResult(success=false, errorCode=INSUFFICIENT_FUNDS)
- Same operation should return same shape (e.g.,
FireResultalways hashit,shipDestroyed,coordinate). - For list operations: empty list vs. null? → Prefer empty list.
- Success case: what is returned?
- Failure case: exception, error object, or null/empty?
- Is the return type immutable or mutable? (Prefer immutable)
- Does the caller need to distinguish multiple failure types?
- Explicit over implicit —
fire(attacker, target, coordinate)is clearer thanfire(coordinate)if turn is implicit. - Single responsibility per method —
placeShip()doesn't also display the board. - Avoid primitive obsession — Use
Coordinatenot(int x, int y); usePaymentDetailsnotMap<String, Object>. - Consistent naming —
createX,getX,updateX,deleteXorremoveX. - Idempotency when applicable — "Register subscriber" — if already registered, no-op or error?
Requirement: "Players take turns firing at the opponent's grid."
Input analysis:
- Actor: Game (orchestrator) or Player (via Game)
- What's needed: Who is firing (current turn), where to fire (coordinate)
- Derived: Target = opponent of current turn
- Input:
fire(Coordinate coordinate)— Game knows current turn, so coordinate alone suffices.
Output analysis:
- Caller needs: Did we hit? Was a ship destroyed? Game over?
- Output:
FireResult(hit: boolean, shipDestroyed: boolean, coordinate: Coordinate, message: String)— or includegameOver: boolean
Edge outputs:
- Wrong turn →
OutOfTurnException - Already fired there →
CoordinateAlreadyFiredException - Invalid coordinate →
InvalidCoordinateException
Requirement: "User books selected seats for a show."
Input analysis:
- Actor: User (via API)
- Required:
showId,seatIds(list) - Derived:
userIdfrom auth/session (out of scope for LLD, but assume passed) - Input:
bookSeats(showId: Long, seatIds: List<Long>)orBookSeatRequest(showId, seatIds)
Output analysis:
- Success: Created ticket with ID, seat details
- Output:
TicketorBookingResponse(ticketId, seats, amount) - Failure: Seat taken, show not found, invalid seat IDs
- Exception:
SeatAlreadyBookedException,ShowNotFoundException,InvalidSeatException
Requirement: "Client initiates payment; gateway routes to bank."
Input analysis:
- Actor: Client (merchant)
- Required:
clientId,amount,paymentMethod, payment-specific details (UPI: VPA, Card: number/expiry/cvv) - Polymorphic: Payment details vary by method
- Input:
capturePayment(clientId, amount, paymentMethod, PaymentDetails details)— wherePaymentDetailsis interface with UPI/Card/NetBanking implementations
Output analysis:
- Success:
PaymentResult(success=true, transactionId, bankId) - Failure:
PaymentResult(success=false, errorCode)— business failure, not exception - Design choice: Don't throw on bank rejection; return structured result (real-world APIs do this)
Use these questions for any LLD problem. Customize as needed.
| # | Question | When to Ask |
|---|---|---|
| 1 | What exactly is in scope for this problem? | Always, first |
| 2 | What should I explicitly exclude (e.g., auth, payments, search)? | When problem is broad |
| 3 | Is this a CLI, API, or library? Who is the consumer? | When interface type is unclear |
| 4 | Should I focus on one flow (e.g., booking only) or the full system? | When time-boxed (e.g., 1 hour) |
| 5 | Are there any "bonus" or "nice-to-have" features I should know about? | To prioritize |
| # | Question | When to Ask |
|---|---|---|
| 1 | Does [entity] have a lifecycle or states (e.g., OPEN, CLOSED)? | When entity can change over time |
| 2 | What triggers a state transition? | When lifecycle exists |
| 3 | Can [entity] be modified after creation? If so, what can change? | When mutation is possible |
| 4 | Is there a concept of "session" or "context" that spans operations? | For multi-step flows |
| 5 | What happens when [terminal state] is reached? (e.g., game over, auction closed) | For completion conditions |
| # | Question | When to Ask |
|---|---|---|
| 1 | What does the caller provide when invoking [operation]? | For each main operation |
| 2 | What should [operation] return on success? | For each main operation |
| 3 | How should failures be communicated — exceptions, error codes, or return values? | When failure modes exist |
| 4 | Are there different types of input for [polymorphic concept]? (e.g., UPI vs Card) | When multiple variants |
| 5 | Should the output be immutable? | When passing results around |
| # | Question | When to Ask |
|---|---|---|
| 1 | Can [entity A] be associated with multiple [entity B]? (e.g., one user, many orders) | For relationships |
| 2 | Is there a uniqueness constraint? (e.g., one bid per buyer per auction) | When duplicates might occur |
| 3 | What are the valid ranges or formats for [field]? | For validation |
| 4 | Are there any ordering guarantees? (e.g., FIFO, priority) | For queues, processing |
| 5 | Can [action] be performed more than once? Idempotent? | For retries, duplicate requests |
| # | Question | When to Ask |
|---|---|---|
| 1 | What if two users try to [competing action] at the same time? | For shared resources |
| 2 | What if [resource] is full/empty/not found? | For capacity, existence |
| 3 | What if input is invalid (null, negative, out of range)? | Always |
| 4 | What if [operation] is called in wrong order or wrong state? | For stateful systems |
| 5 | Are there any timeout or expiry scenarios? | For time-sensitive data |
| # | Question | When to Ask |
|---|---|---|
| 1 | Should we assume single-threaded or handle concurrency? | For shared mutable state |
| 2 | Where does data live — in-memory, or do we need persistence? | When data must survive restarts |
| 3 | Are there any performance constraints (e.g., O(1) eviction)? | When algorithms matter |
| 4 | Do we need to support multiple instances (distributed) or single process? | For scaling |
| 5 | Is thread safety a requirement? | For concurrent access |
| # | Question | When to Ask |
|---|---|---|
| 1 | Could we add new [variant] in the future? (e.g., new payment method, new vehicle type) | When variants exist |
| 2 | Should [algorithm/strategy] be pluggable or fixed? | When multiple algorithms possible |
| 3 | Will there be different types of [entity] with different behavior? | When polymorphism might help |
| 4 | Is this a library that others will extend? | When designing for reuse |
| Category | Question |
|---|---|
| Grid/Board | What is the grid size? Fixed or configurable? |
| Grid/Board | How is the grid divided (e.g., per player territory)? |
| Turns | Who goes first? How is turn order determined? |
| Turns | Does a miss/hit change turn? (e.g., hit = extra turn?) |
| Pieces/Units | What do pieces look like? Size, shape, orientation? |
| Pieces/Units | Can pieces overlap? Touch? |
| Winning | What defines a win? All cells, pattern, elimination? |
| Winning | Is there a draw condition? |
| View | What does each player see? Own pieces, opponent's? Fog of war? |
| Input | Manual input (coordinates) or automated (e.g., random targeting)? |
| Input | Is placement manual or random? |
| Category | Question |
|---|---|
| Concurrency | What if two users book the same seat/resource? |
| Concurrency | Locking strategy — optimistic or pessimistic? |
| Lifecycle | Is there a "hold" or "lock" period before confirm? |
| Lifecycle | Can a booking be cancelled? Refund? |
| Scope | Just booking, or also search, payments, notifications? |
| Scope | Single show/session or multiple? |
| Validation | What makes a seat "available"? |
| Validation | Can users book non-contiguous seats? |
| Category | Question |
|---|---|
| Payment methods | What methods? UPI, Card, NetBanking, etc.? |
| Payment methods | Does each method have different input schema? |
| Routing | How is the bank/processor selected? |
| Routing | Fixed routing, weighted distribution, or dynamic (success rate)? |
| Failure | How to handle bank rejection? Retry? |
| Failure | Do we return error codes or throw? |
| Onboarding | How does a client get onboarded? |
| Onboarding | Can one client use multiple banks? |
| Category | Question |
|---|---|
| Matching | Match by vehicle type or by capabilities/features? |
| Matching | Slot selection — first available, best fit, closest? |
| Slot types | Are slots typed (Car, Bike, EV) or feature-based? |
| Payment | How is fee calculated? Hourly, flat, tiered? |
| Display | Real-time display boards? Event-driven? |
| Capacity | What if lot is full? |
| Vehicle | What vehicle types? Do we need to add more later? |
| Category | Question |
|---|---|
| Eviction | What policy when full? LRU, LFU, FIFO, other? |
| Eviction | Can policy be changed at runtime? |
| Persistence | In-memory only, or persist to disk/DB? |
| Persistence | Write-through or write-back? |
| TTL | Do entries expire? Lazy or proactive cleanup? |
| Concurrency | Single-threaded or concurrent access? |
| Capacity | Fixed or dynamic? |
| Category | Question |
|---|---|
| Queue type | Bounded or unbounded? |
| Queue type | Custom implementation or use library? (Often "custom" in LLD) |
| Delivery | Push (callback) or pull (consumer polls)? |
| Delivery | Single consumer or fan-out (multiple subscribers)? |
| Failure | Retry on consumer failure? Backoff? DLQ? |
| Ordering | FIFO guaranteed? |
| Message format | What does a message look like? JSON, typed object? |
| Category | Question |
|---|---|
| Rule types | Single-entity rules vs. aggregate rules? |
| Rule types | Can rules depend on each other? Priority? |
| Output | All violations or first failure? |
| Output | What does a violation look like? |
| Extensibility | Add new rules without changing engine? |
| Input | What is being validated? Single item or batch? |
| Category | Question |
|---|---|
| States | What states exist? Idle, CardInserted, Dispensing, etc.? |
| Transitions | What triggers each transition? |
| Validation | How is card validated? PIN? (Scope?) |
| Invalid actions | What happens if user does wrong action in state? |
| Concurrency | One user at a time? |
Step 1: Underline all nouns in the requirement. These are candidate entities. Step 2: Underline all verbs (actions). These are candidate operations/methods. Step 3: Map nouns to entities, verbs to methods. Eliminate duplicates and group.
Example (Battleship):
- Nouns: grid, player, ship, cell, coordinate, turn, hit, miss, game
- Verbs: place, fire, destroy, view, alternate
- Entities: Grid, Player, Ship, Cell, Coordinate, Game, Turn
- Methods: placeShip(), fire(), isDestroyed(), getView(), nextTurn()
| Pattern | Description | Example |
|---|---|---|
| 1-to-many | One parent, many children | Game → Players, ParkingLot → Floors |
| Many-to-many | Both sides can have multiple | User ↔ Auction (via Bid) |
| Composition | Child can't exist without parent | Cell belongs to Battlefield |
| Aggregation | Child can exist independently | Car can exist without ParkingLot |
| Inheritance | Is-a relationship | Buyer, Seller extend User |
| Association | Uses or references | Game uses TurnManager |
For each user story or requirement, write:
- Trigger: What initiates the flow?
- Preconditions: What must be true before?
- Steps: Numbered sequence.
- Postconditions: What is true after?
- Alternate paths: What if X fails?
- Output: What is returned?
Template:
Flow: [Name]
Trigger: [Event/Action]
Preconditions: [List]
Steps:
1. ...
2. ...
Postconditions: [List]
Alternate: If [condition], then [action]
Output: [Type]
Invariants are things that must always be true. Ask:
- "What must never happen?"
- "What relationship must always hold?"
Examples:
- Battleship: A coordinate can be fired at most once per player.
- BookMyShow: A seat can only be booked once per show.
- Parking: A slot can hold at most one vehicle at a time.
- Auction: Bid amount must be within [lowestBid, highestBid].
List invariants in your design guide. They become validations.
Use this structure for any LLD problem. Fill in each phase after clarification.
- Table: Question | Your Assumption
- "Why this matters" — 1-2 sentences on interviewer focus
- List entities with attributes and key methods
- Relationship diagram (text or mermaid)
- Table: Pattern | Where | Why
- Step-by-step flow for each main operation
- Pseudocode or structured bullets
- Directory tree
- Table: Scenario | Validation
- Numbered list of components to build first
- Table: Attribute | How to Show It
- Table: Requirement | Primary Component
- For complex flows
| Phase | Source |
|---|---|
| Phase 1 | Your clarification questions + answers = Assumptions table |
| Phase 2 | Nouns from requirements + relationships = Entities |
| Phase 3 | "What might change?" + "How to extend?" = Patterns |
| Phase 4 | Flows you extracted (Section 6.3) = Core Logic |
| Phase 5 | Entities + patterns = Package structure (group by domain) |
| Phase 6 | Edge case questions + invariants = Validations |
| Phase 7 | Dependencies: build value objects first, then entities, then services |
| Phase 8 | What interviewers evaluate = Strong hire attributes |
| Phase 9 | Trace each requirement to a component = Quick reference |
| Phase | Suggested Time (45–60 min interview) |
|---|---|
| Clarify & Scope | 5–8 min |
| Entities & Relationships | 5–8 min |
| Design Patterns | 3–5 min |
| Core Logic (1–2 main flows) | 5–10 min |
| Start coding | 25–35 min |
| Validations (as you code) | Ongoing |
| Discussion | 5 min |
Rule: Don't over-document. A one-page design outline is enough. The guideline doc you're creating here is for practice and preparation, not for writing in real time.
## Clarification & Scope
| # | Question | Assumption |
|---|----------|------------|
| 1 | [Scope] | |
| 2 | [State/Lifecycle] | |
| 3 | [Input/Output] | |
| 4 | [Rules] | |
| 5 | [Edge cases] | |
| 6 | [Concurrency] | |
| 7 | [Extensibility] | |
Why this matters: [1 sentence]## Entity: [Name]
- **Attributes**: [list]
- **Methods**: [list]
- **Relationships**: [to other entities]
- **Invariants**: [what must hold]## Flow: [Name]
**Trigger**: [what starts it]
**Input**: [params]
**Output**: [return type]
**Steps**:
1. Validate [preconditions]
2. [Action 1]
3. [Action 2]
...
N. Return [output]
**Error cases**:
- [Condition] → [Exception/Handling]- Clarification done; assumptions recorded
- Core entities identified
- Main flows written (at least 1–2)
- Key invariants listed
- Design patterns chosen
- Implementation order decided
- Edge cases noted
- All requirements traced to code
- Exceptions for invalid operations
- No hardcoded values (use config)
- SOLID principles applied
- Tests for main flows
- README or design notes updated
"Thanks, that's clear. Before I start designing, let me clarify a few things to make sure I'm on the right track. [Ask 2–3 highest-impact questions]. If you don't have a preference, I'll assume [X]. Does that work?"
"I'll assume [X] for now. We can change it if you'd like."
"Given that, here's how I'm thinking about the design. I'll start with the core entities..."
"I'll use the Strategy pattern here because [reason]. This lets us add new [variants] without changing the core logic."
"For [edge case], I'll validate [condition] and throw [Exception]. Does that align with your expectations?"
"I'm considering two approaches: [A] and [B]. [A] is simpler but [trade-off]. [B] is more extensible but [trade-off]. Which direction would you prefer?"
"To summarize: I've built [components]. The main flows are [list]. I've handled [key edge cases]. What would you like me to extend or change next?"
Pick 20 LLD problems (including those in this repo). For each:
- Read the requirement (don't look at the design guide yet).
- Create your own clarification table using the question banks.
- Write your own design guideline using the 10-phase template.
- Compare with the existing DESIGN_GUIDE.md.
- Reflect: What did you miss? What did you get right?
Goal: After 20 problems, the question banks and template become automatic.
- Pick a problem you've never seen.
- Set a timer: 10 min clarification, 15 min design (no code).
- Produce: Assumptions table + Entity list + 1 main flow.
- Self-grade: Did you ask good questions? Did you catch the key entities?
For each problem you practice:
- List every public method/API you'd expose.
- For each: Write input params, output type, and 2–3 error cases.
- Compare with the implemented code or design guide.
After each problem, rate yourself (1–5):
| Criterion | 1 (Weak) | 5 (Strong) |
|---|---|---|
| Clarification | Didn't ask questions; made silent assumptions | Asked 5+ targeted questions; recorded assumptions |
| Entity design | Unclear entities; god objects | Clear, single-responsibility entities |
| Input/Output | Vague or inconsistent APIs | Explicit, minimal, consistent |
| Patterns | Procedural; lots of if/else | Strategy/State/Observer where appropriate |
| Edge cases | Forgot validations | Explicit validation table |
| Extensibility | Hard to add features | New feature = new class |
- Starting to code before clarifying — Always clarify first.
- Asking about implementation too early — "Should I use HashMap?" before "What are the entities?"
- One big class — Split by responsibility.
- Implicit state — Make turn, status, etc., explicit.
- Ignoring concurrency — Ask: "Single-threaded or multi?" when shared state exists.
- Polymorphism missed — When you have "if (type == A) ... else if (type == B)", consider polymorphism.
- No error handling — Every operation can fail; define how.
- Over-engineering — Don't add 10 patterns for a 1-hour problem. 2–3 well-chosen patterns suffice.
Use these DESIGN_GUIDE.md files as references after you've attempted the problem yourself:
- Battleship: Spatial modeling, turn management, view abstraction, strategy patterns
- Parking Lot: Capability-based matching, observer for display
- BookMyShow: Concurrency, pessimistic locking, DDD/Hexagonal
- Payment Gateway: Polymorphic input, routing strategies
- Rule Engine: Interface segregation, single vs multi rules
- Cache: Eviction policies, storage vs policy separation
- Message Queue: Custom queue, pub-sub, retry with backoff
- ATM: State pattern, state transitions
- Online Auction: Winner selection algorithm, P&L calculation
- Scope 2. State 3. Inputs/Outputs 4. Rules 5. Edge cases 6. Non-functional 7. Extensibility
Actor → What they know → Provided vs derived → Minimal but complete
Success shape → Failure mode (exception/result) → Consistent return type
- Clarify 2. Entities 3. Patterns 4. Core Logic 5. Package 6. Validations 7. Impl Order 8. Strong Hire 9. Quick Ref
Never design before clarifying. Never clarify without a checklist.
| Problem Type | Top 5 Questions to Ask |
|---|---|
| Game | Grid division? Turn order? Win condition? View (fog of war)? Placement manual/random? |
| Booking | Concurrency? Locking? Hold period? Scope (search, payment)? |
| Payment | Payment methods? Routing strategy? Failure handling? Polymorphic input? |
| Parking | Match by type or capability? Slot selection algo? Payment model? |
| Cache | Eviction policy? Persistence? TTL? Concurrency? |
| Queue | Bounded/unbounded? Push/pull? Retry? Custom queue? |
| Rule Engine | Single vs multi rules? Output (all violations)? Extensible? |
| ATM/State | States? Transitions? Invalid action handling? |
| Auction | Lifecycle? Multiple bids? Winner selection? P&L? |
| Question | Assumption |
|---|---|
| Scope? | Park, unpark, fee calculation only. No search, no display boards. |
| Vehicle types? | Car, Bike, Electric Car. Match by capabilities (CAR_SIZE, EV_CHARGER), not enum. |
| Slot selection? | Best-fit (minimize wasted features). Pluggable. |
| Payment? | Hourly. Pluggable strategy. |
| Concurrency? | Single-threaded for interview. |
ParkingLot, Floor, Slot, Vehicle, Ticket, Receipt, CompatibilityEngine, SlotStrategy, PaymentStrategy
- Get vehicle type → required features
- SlotStrategy.findSlot(vehicle) → first slot where slot.features ⊇ vehicle.required, minimize |slot.features - vehicle.required|
- Assign vehicle to slot
- Create Ticket(vehicle, slot, inTime)
- Return ticket
- Lot full → exception
- Invalid ticket on unpark → exception
That's the core. The rest (Package structure, Implementation order) follows from this.
Does behavior change based on STATE (e.g., different actions allowed in different modes)?
→ YES: State Pattern (ATM, Game status)
Do you have MULTIPLE ALGORITHMS for the same operation (slot selection, payment calculation, routing)?
→ YES: Strategy Pattern (Parking, Payment Gateway, Battleship targeting)
Do MULTIPLE OBSERVERS need to react to events (display boards, logging, notifications)?
→ YES: Observer Pattern (Cricbuzz, Parking display, Message Queue)
Does a request pass through a CHAIN of handlers (auth → log → parse → controller)?
→ YES: Chain of Responsibility (Route Handler, Middleware)
Do you need to build COMPLEX OBJECTS with many optional parts?
→ YES: Builder Pattern (Game setup, Configuration)
Do you have POLYMORPHIC INPUT (different shapes for same concept — UPI vs Card)?
→ YES: Interface + implementations (PaymentDetails)
Are you VALIDATING against multiple independent rules?
→ YES: Strategy/Plugin (Rule Engine)
Is there a REPEATABLE SKELETON with steps (setup → loop → cleanup)?
→ YES: Template Method (Game loop)
Do you need to ABSTRACT STORAGE (in-memory vs DB)?
→ YES: Repository Pattern (BookMyShow, E-Commerce)
Do you need a SINGLE ENTRY POINT that hides complexity?
→ YES: Facade (PaymentGateway, ParkingLotManager)
| Requirement Phrase | Likely Pattern | Example |
|---|---|---|
| "Different ways to..." | Strategy | "Different ways to find a slot" → SlotDeterminingStrategy |
| "Based on the current state..." | State | "Based on whether card is inserted" → ATMState |
| "Notify when..." | Observer | "Notify display when car leaves" → ParkingEventListener |
| "Validate against rules..." | Strategy/Plugin | "Validate expense rules" → SingleExpenseRule |
| "Route to different..." | Strategy | "Route to different banks" → PaymentRoutingRule |
| "Build with many options..." | Builder | "Build game with config" → GameBuilder |
| "Store/retrieve..." | Repository | "Store tickets" → TicketRepository |
| "Single point to..." | Facade | "Single point for parking operations" → ParkingLotManager |
| "Chain of..." | Chain of Responsibility | "Chain of middleware" → RouteHandler |
| "Different types of..." | Polymorphism | "Different payment methods" → PaymentDetails implementations |
| Code Smell | Fix with Pattern |
|---|---|
| Large if/else on type/enum | Strategy or Polymorphism |
| Large if/else on state | State Pattern |
| Method does too much | Extract to separate classes; Facade to orchestrate |
| Hard to add new X without changing existing code | Strategy, Plugin, or Polymorphism |
| Tight coupling between producer and consumer | Observer, Event-driven |
| Complex construction logic | Builder |
| Direct dependency on concrete storage | Repository interface |
| Repeated validation logic | Chain of Responsibility or Rule objects |
Requirement: "Design an elevator system for a building with N floors."
| Question | Assumption |
|---|---|
| One elevator or multiple? | Multiple elevators. |
| How does elevator choose direction? | Same direction priority; then nearest request. |
| Capacity? | Limited. Overload = reject. |
| Button types? | Floor buttons inside; Up/Down on each floor. |
| Real-time display? | Display current floor. Observer for display. |
Elevator, Floor, Request, ElevatorController, Direction (enum), RequestQueue
- requestElevator(floor, direction) → assigns elevator
- pressFloor(elevatorId, floor) → adds destination
- move() → one floor per tick (simplified)
- requestElevator(floor: int, direction: Direction) → elevatorId or null if all busy
- pressFloor(elevatorId: String, floor: int) → void (or exception if invalid)
Requirement: "Design a library system for borrowing and returning books."
| Question | Assumption |
|---|---|
| Single copy or multiple copies per book? | Multiple copies (BookItem). Book = title; BookItem = physical copy. |
| Member types? | Single type for now. |
| Late fees? | Out of scope. |
| Reservation? | Out of scope. |
| Fine calculation? | Out of scope. |
Library, Book (title, author), BookItem (barcode, book reference), Member, Loan (member, bookItem, dueDate)
- borrow(memberId, barcode) → Loan or exception
- return(loanId or barcode) → void
- search(criteria) → List (optional)
- borrow(memberId: String, bookItemBarcode: String) → Loan
- Fail: Member has max loans, book not available, member not found
- return(bookItemBarcode: String) → void
- Fail: Loan not found, already returned
Requirement: "Design a vending machine."
| Question | Assumption |
|---|---|
| Coin/note types? | Accept predefined denominations. |
| Change? | Return exact change if possible; else refund. |
| Item selection? | By code (A1, B2, etc.). |
| State? | Idle, Selecting, Payment, Dispensing. |
| Out of stock? | Show "sold out"; don't allow selection. |
VendingMachine, Item (code, price, quantity), State (Idle, Selecting, Payment, Dispensing), Inventory
- Idle + select(item) → Selecting (if item available)
- Selecting + insertCoin(amount) → accumulate; when >= price → Payment
- Payment + confirm → Dispensing → Idle
- Any state + cancel → refund, Idle
- selectItem(code: String) → void (throws if sold out)
- insertCoin(amount: int) → void
- confirmPurchase() → Item + List (change)
- cancel() → List (refund)
When you see these phrases, they usually need clarification:
| Phrase | Ambiguous Because | Questions to Ask |
|---|---|---|
| "Design a X" | Scope unclear | What exactly should X do? What's out of scope? |
| "Users can..." | Who are users? How many? | Single/multi? Roles? |
| "Handle multiple..." | Concurrency? | Single-threaded or concurrent? Locking? |
| "Support different..." | How many? Extensible? | Fixed set or pluggable? |
| "Efficient" | What metric? | Time? Space? Scalability? |
| "Real-time" | Latency? Push vs pull? | What's acceptable delay? |
| "Large scale" | How large? | Orders of magnitude? |
| "Similar to X" | Which features of X? | Which parts of X should we replicate? |
| "Basic/crud" | How basic? | What operations exactly? |
| "With authentication" | Scope? | In scope or mock? |
Bad: process(data: Map<String, Object>) — Caller passes everything in a map.
Fix: Typed input object or explicit parameters. process(request: PaymentRequest).
Bad: Method has side effects (prints, updates global state) but returns void. Caller can't get result.
Fix: Return the result. Use Observer for side effects (logging, display).
Bad: Using exceptions for "not found" when it's expected (e.g., cache miss).
Fix: Return Optional<T> or Result<T, E>. Reserve exceptions for unexpected failures.
Bad: Sometimes return object, sometimes null, sometimes empty list for "no result."
Fix: Pick one convention. Prefer Optional<T> or empty collection over null.
Bad: Returning JPA entity (with lazy loading, proxies) to caller.
Fix: Return DTO or domain object. Keep persistence details in infrastructure.
| Operation | Input | Output |
|---|---|---|
| placeShip | playerId, topLeft: Coordinate, size: int | void (exception on invalid) |
| fire | coordinate: Coordinate | FireResult(hit, shipDestroyed, gameOver) |
| getBoardView | playerId | BattlefieldView (string or matrix) |
| makeMove | playerId, position: int | GameResult(winner, draw, nextPlayer) |
| Operation | Input | Output |
|---|---|---|
| getAvailableSeats | showId | List |
| bookSeats | showId, seatIds, userId | Ticket |
| cancelBooking | ticketId | void (or RefundInfo) |
| Operation | Input | Output |
|---|---|---|
| onboardClient | name, supportedMethods | clientId |
| capturePayment | clientId, amount, method, PaymentDetails | PaymentResult |
| refund | transactionId, amount | RefundResult |
| Operation | Input | Output |
|---|---|---|
| get | key | Optional |
| put | key, value | void |
| put | key, value, ttlSeconds | void |
| evict | key | void |
| changePolicy | EvictionPolicy | void |
| Operation | Input | Output |
|---|---|---|
| createQueue | name, capacity? | void |
| publish | queueName, payload | void (or messageId) |
| subscribe | queueName, Subscriber | void |
| unsubscribe | queueName, subscriberId | void |
| Minute | Phase | Actions |
|---|---|---|
| 0–2 | Listen | Take notes. Don't interrupt. |
| 2–5 | Restate + Clarify | "So we need X. I have a few questions..." Ask 3–5. |
| 5–8 | Assumptions | State assumptions. Get nod. |
| 8–15 | High-Level Design | Entities, relationships. Draw or list. |
| 15–20 | Core Flows | 1–2 main flows. Pseudocode or steps. |
| 20–25 | Patterns | "I'll use Strategy for X because..." |
| 25–50 | Code | Implement core. Prioritize: entities first, then main flow. |
| 50–55 | Edge Cases | Add validations, exceptions. |
| 55–60 | Summary | "Here's what I built. I'd extend by..." |
| Minute | Phase |
|---|---|
| 0–5 | Listen + Clarify (fewer questions) |
| 5–12 | Entities + 1 main flow |
| 12–40 | Code |
| 40–45 | Validations + summary |
- Entities: "Have I captured all nouns? Is any entity doing too much?"
- Relationships: "Is this 1-to-many or many-to-many? Does the child need the parent's ID?"
- State: "What are the states? What triggers transitions? Is state explicit or implicit?"
- Input: "What does the caller have? What can I derive? Am I asking for too much?"
- Output: "What does the caller need? How do I communicate failure?"
- Invariants: "What must never happen? Have I added validation?"
- Extensibility: "If we add X tomorrow, do I need to change existing code?"
- Concurrency: "What if two threads call this? Is it a problem?"
- Testing: "Can I unit test this? What do I need to mock?"
- Naming: "Will another developer understand this in 6 months?"
| Problem | Primary Clarification Focus | Key Patterns | Input/Output Complexity |
|---|---|---|---|
| Battleship | Grid division, turn, view, ship model | Strategy, Value Object, Builder | Medium (Coordinate, FireResult) |
| Parking Lot | Capability vs type, slot selection | Strategy, Observer, Facade | Low |
| BookMyShow | Concurrency, locking | Hexagonal, Repository | Medium (BookingRequest) |
| Payment Gateway | Payment methods, routing | Strategy, Polymorphism, Facade | High (PaymentDetails variants) |
| Rule Engine | Single vs multi rules | Strategy, Interface Segregation | Low |
| Cache | Eviction, persistence | Strategy, Repository | Low |
| Message Queue | Push vs pull, retry | Observer, Strategy, Custom DS | Medium |
| ATM | State transitions | State | Low |
| Online Auction | Winner selection, P&L | Strategy, Repository | Medium |
| Tic-Tac-Toe | Winning rules, undo | Strategy, State, Factory | Low |
| E-Commerce | Filters, cart | Specification, Strategy | Medium |
| Route Handler | Middleware order | Chain of Responsibility | Low |
| Cricbuzz | Fan-out, filtering | Observer | Low |
| Movie CMS | Cache hierarchy, filters | Composite, Chain, Strategy | Medium |
| Banking System | Timestamp ordering, cashback vs other ops, merge + replay | Repository, Dependency Inversion, domain ledger | Medium (Optional-heavy API, timeAt replay) |
Use this table to know where to focus your clarification and design for each problem type.
- I have read and internalized the 7 dimensions of clarification (Part II)
- I can list 5+ questions from the universal bank for any problem (Part IV)
- I know the input framework: Actor → Provided vs Derived → Minimal (Part III)
- I know the output framework: Success shape → Failure mode → Consistency (Part III)
- I can extract entities from nouns and flows from verbs (Part VI)
- I know the 10-phase design guideline template (Part VII)
- I have practiced creating my own design guide for at least 5 problems
- I can explain when to use Strategy, State, Observer from requirement phrases (Part XI)
- I have practiced the "blind design" exercise (Part X)
- I have interview scripts ready (Part IX)
- I know the time management for 45- and 60-minute interviews (Part XVI)
Insight is pattern recognition. The more problems you solve with a process, the more you recognize:
- "This sounds like a state machine" → State pattern
- "Multiple algorithms for same thing" → Strategy
- "Different input shapes" → Polymorphism
- "Concurrent access to shared resource" → Ask about locking
- "Rules that can be added" → Plugin/Strategy
Your goal: Reach a point where, upon hearing a problem, you instantly think of 3–5 clarification questions and 2–3 likely patterns. That comes from deliberate practice using this guide.
How to use this document:
- Before practice: Skim Parts II, III, IV, V.
- During practice: Use Part VII template; fill using Parts IV, V, VI.
- After practice: Self-assess using Part X; compare with DESIGN_GUIDE.md.
- Before interview: Review Parts IX, XVI, Appendix A.
- Ongoing: Add your own questions to the banks when you encounter new ambiguities.
End of LLD Master Guide. Use this document as your reference. Revisit Sections II, III, IV, and V before every practice session or interview.