MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
The LLD Interview Framework and UML
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

The LLD Interview Framework and UML

Reading45 min

High-level design asks "how many servers do you need?" Low-level design asks a completely different question: "what classes exist, what does each one own, and how do they talk to each other?"

Picture being asked to design a parking lot, or an elevator, or a movie-ticket app, in about 45 minutes. The interviewer is not counting how many design patterns you can name. They are watching whether your classes are clean, whether you could add a new feature without rewriting everything, and whether you know what breaks when two people use the system at the exact same moment.

Like HLD, this has a fixed order of steps. Learn the order once, and every problem in this section becomes the same six steps with different nouns.

The six steps — Requirements, Entities, Relationships, Interfaces, Concurrency, Extensibility. Say it as "Real Engineers Rarely Ignore Corner Errors."

What the interviewer is actually grading

Picture the interviewer holding a scorecard. It has four rows, and they matter in this order.

They're checking Good looks like Bad looks like
A clean object model Each class does one clear job, with a name a normal person would recognise One giant Manager class doing everything; classes named Helper, Util, Data
Sensible relationships Parts that can't exist without their whole are owned by it; the pieces likely to change sit behind an interface Long inheritance chains; everything wired directly to everything else
Room to grow "Add a new vehicle type" or "add a new payment method" means writing one new class Adding anything means editing five old files and hoping nothing breaks
Correctness when two things happen at once You can say out loud which piece of shared data is at risk and how it's protected Two users book the same seat and the bug ships to production

Two habits separate people who pass from people who don't:

  • They build small and finished, not big and half-done. Ten classes with real methods beat thirty class names with nothing inside them.
  • They talk about the actual problem, not about pattern names. "A ParkingSpot knows its size and whether it's free" is design. Saying "I'll use the Strategy pattern" without saying what actually varies is just vocabulary.

Remember: the strongest signal in an LLD interview is that a plausible new requirement fits in as one new class, not five edited ones.

Sign in to try this knowledge check.

Step 1 — Requirements: who uses this, and what do they do

Spend about five minutes here. It works the same way HLD's first step does, just one level closer to the code.

Ask who the actors are. For a parking lot: a driver, an attendant, an admin. Each actor's needs turn into use cases, and use cases turn into the public methods on your main class.

Write the use cases as verbs. Park a vehicle. Retrieve a vehicle. Pay. Check availability. These map almost directly onto the methods you'll write later, which is exactly why writing them down first is worth the minute it takes.

Ask questions that actually change the design, and skip the ones that don't:

Question Why it matters
How many kinds of X are there, and will more show up later? Decides between an enum, a family of classes, or a pluggable strategy
Is there more than one Y? (floors, branches, currencies) Decides whether Y is just a field, or its own class
Do we need history, or only the current state? Decides whether "events" need to exist as their own objects
Who is allowed to do what? Decides where permission checks live
Is this one process, or many at once? Decides whether you need locks, or immutable data, or database-level checks
Does this live in memory, or get saved somewhere? Decides whether you need a repository interface

Then say the scope out loud: "I'll build parking, un-parking, spot assignment, and fee calculation in memory. I'll define a PaymentProcessor interface, but I won't wire up a real payment gateway."

Remember: a question like "will this change later?" is the interviewer handing you your extension point. Use it.

Sign in to try this knowledge check.

Step 2 — Entities: turning nouns into classes

Start by listing every noun. "A driver parks a vehicle in a spot on a floor of a parking lot, gets a ticket, and makes a payment." That sentence alone hands you six candidate classes.

Not every noun deserves to be a class, though. Sort them:

If the noun is… Model it as…
Something with an identity that changes over time An entity (Vehicle, Ticket, User)
A value with no identity of its own A value object, ideally one that never changes (Money, TimeSlot, Address)
A small, fixed set of options An enum (VehicleSize, SpotStatus, PaymentStatus)
Behaviour that might vary An interface with several implementations (PricingStrategy, NotificationChannel)
Just a detail of something else A plain field, not a class (colour, licencePlate)
Something that coordinates several other things A service (ParkingLotService, BookingService)
A collection you need to search A repository (SpotRepository, TicketRepository)

Two habits worth picking up right away:

  • Reach for an enum before a boolean or a bare string. SpotStatus.OCCUPIED beats is_taken = True, because tomorrow there's a RESERVED status and an OUT_OF_SERVICE status, and a boolean has nowhere to put them.
  • Make value objects unchangeable. Money, Point, TimeRange should never change after they're built. That removes a whole category of bugs where two things secretly share the same mutable object, and it makes those objects safe to hand to another thread.

Here's the noun list turned into small, runnable code — about the level of detail an interviewer wants to see on the whiteboard:

from dataclasses import dataclass
from enum import Enum


class VehicleSize(Enum):
    MOTORCYCLE = 1
    COMPACT = 2
    LARGE = 3


class SpotStatus(Enum):
    FREE = "free"
    OCCUPIED = "occupied"
    OUT_OF_SERVICE = "out_of_service"


@dataclass(frozen=True)          # value object: never changes, has no identity of its own
class Money:
    paise: int

    def __add__(self, other: "Money") -> "Money":
        return Money(self.paise + other.paise)

    def __str__(self) -> str:
        return f"Rs {self.paise / 100:.2f}"


@dataclass
class Vehicle:                    # entity: identified by its plate
    plate: str
    size: VehicleSize


class ParkingSpot:                # entity: has a lifecycle
    def __init__(self, spot_id: str, size: VehicleSize):
        self.spot_id = spot_id
        self.size = size
        self.status = SpotStatus.FREE
        self.vehicle: Vehicle | None = None

    def can_fit(self, vehicle: Vehicle) -> bool:
        return self.status == SpotStatus.FREE and self.size.value >= vehicle.size.value

    def occupy(self, vehicle: Vehicle) -> None:
        if not self.can_fit(vehicle):
            raise ValueError(f"spot {self.spot_id} cannot take {vehicle.plate}")
        self.vehicle, self.status = vehicle, SpotStatus.OCCUPIED

    def release(self) -> None:
        self.vehicle, self.status = None, SpotStatus.FREE


spot = ParkingSpot("A-01", VehicleSize.COMPACT)
bike = Vehicle("KA-01-1234", VehicleSize.MOTORCYCLE)
truck = Vehicle("KA-05-9999", VehicleSize.LARGE)

assert spot.can_fit(bike) and not spot.can_fit(truck)   # a compact spot fits a bike, not a truck
spot.occupy(bike)
assert spot.status is SpotStatus.OCCUPIED and not spot.can_fit(bike)
spot.release()
assert spot.status is SpotStatus.FREE
print("entity model behaves:", Money(4990) + Money(1010))

Remember: if a "thing" in your design is really just two booleans pretending to be a state, turn it into one enum before you write another line.

Sign in to try this knowledge check.

Step 3 — Relationships and the UML you'll actually use

You will draw a class diagram at some point. You need five arrows for it, not the full UML spec.

 ┌──────────────────┐
 │   ParkingLot     │   class box: name / fields / methods
 ├──────────────────┤
 │ - name: str      │   -  private
 │ + floors: List   │   +  public
 ├──────────────────┤
 │ + park(v): Ticket│
 └──────────────────┘

RELATIONSHIPS

  A ──────▷ B     inheritance      "A IS-A B"          Car ──▷ Vehicle
  A ┈┈┈┈┈▷ B      implements       "A fulfils B"       CreditCard ┈▷ PaymentMethod
  A ◆────── B     composition      "A OWNS B, B dies with A"   Floor ◆── Spot
  A ◇────── B     aggregation      "A HAS B, B lives on"       Team ◇── Player
  A ───────> B    association      "A uses/knows B"    Order ──> Customer
  A ┈┈┈┈┈┈> B     dependency       "A mentions B briefly (a parameter)"

Put multiplicity on each end of an arrow: 1, 0..1, 1..*, *. ParkingLot 1 ◆── 1..* Floor reads as "one lot owns at least one floor."

The one distinction interviewers actually check for is composition vs. aggregation. Picture it this way:

  • Composition — think of a house and its rooms. A room without its house makes no sense. Delete the Floor, and its ParkingSpots go with it.
  • Aggregation — think of a sports team and its players. Delete the Team, and the Players are still real people who play elsewhere. A Playlist works the same way with its Songs.

Ask yourself one question to tell them apart: if I destroy the whole thing, does the part still make sense on its own? Yes → aggregation. No → composition.

Sketching a sequence diagram for the main use case is also worth thirty seconds, because it forces you to decide who calls whom:

Driver        ParkingLotService     SpotAllocator     TicketRepo
  │  park(vehicle)  │                     │                │
  ├────────────────>│                     │                │
  │                 │  findSpot(vehicle)  │                │
  │                 ├────────────────────>│                │
  │                 │<─── spot ───────────┤                │
  │                 │  spot.occupy(vehicle)                │
  │                 │  save(ticket)       │                │
  │                 ├─────────────────────────────────────>│
  │<──── ticket ────┤                     │                │

Remember: ask "does the part still make sense if the whole is gone?" A room doesn't survive its house; a song survives its playlist.

Sign in to try this knowledge check.

Steps 4–6 — Interfaces, concurrency, extensibility

Step 4 — write the public surface of each class. What does it accept, and what does it return? Design mistakes usually surface right here, the moment you write it down.

from abc import ABC, abstractmethod

class PricingStrategy(ABC):                       # something that varies → an interface
    @abstractmethod
    def price(self, hours: float, size: "VehicleSize") -> int: ...

class ParkingLotService:                          # something that coordinates → a service
    def park(self, vehicle: "Vehicle") -> "Ticket": ...
    def unpark(self, ticket_id: str) -> int: ...   # returns the fee, in paise
    def availability(self) -> dict["VehicleSize", int]: ...

Three rules for this step:

  • Only put an interface where you genuinely expect change — pricing, payment, notifications, storage — and use plain concrete classes everywhere else. An interface with exactly one implementation and no realistic second one is just extra work with no payoff.
  • Return real objects, not raw primitives, whenever a primitive could be misread. Money is clearer than a bare int; a TicketId is clearer than a str when a plate number is also a string.
  • Check for valid input in the constructor, so an object can never exist in a broken state in the first place.

Step 5 — concurrency. Say out loud: "the shared mutable state here is the set of free spots" — or seats, or inventory, whatever fits the problem — then say what protects it. The full treatment lives in the Concurrency lesson later in this section, but at interview speed, your answer is always one of these:

Situation What protects it
Two threads might grab the same slot or seat A lock around "check, then take," or an atomic compare-and-swap
A number shared across threads An atomic counter, never a plain count += 1
Data that's shared but never changed Nothing needed — it can't go wrong if it never changes
Independent items A lock per item, not one giant lock for everything
Multiple processes or servers The database enforces it: a unique constraint, or a conditional UPDATE

Step 6 — extensibility. Close by walking a plausible new requirement through your design out loud: "if we add electric vehicles with charging spots, I add an ELECTRIC size and a ChargingSpot subclass. The allocator doesn't change, because it only ever asks can_fit." If that walkthrough means editing five existing classes, redesign before the interviewer points it out.

Three shapes of change to prepare for: a new type should mean a new class, a new rule should mean a new strategy, and a new listener for an event should mean a new observer.

Remember: an interface with one implementation and no plausible second one is a cost with no benefit. Only add one where change is actually expected.

Sign in to try this knowledge check.

Quick recap

The six steps and roughly how long each takes:

Step Minutes What you produce
1. Requirements 5 Actors, use-case verbs, the questions that matter, a stated scope
2. Entities 8 Nouns sorted into entities, value objects, enums, services, repositories
3. Relationships 8 A class diagram with the five arrows and multiplicities
4. Interfaces 10 Real method signatures on the core classes; interfaces where things vary
5. Concurrency 7 The shared mutable state, named, plus how it's protected
6. Extensibility 5 One new requirement, walked through the design out loud
  • Nouns become classes, verbs become methods, small fixed sets become enums, changing behaviour becomes an interface.
  • Prefer enums over booleans, prefer unchangeable value objects over mutable bags of fields, and validate inside the constructor.
  • Prefer composition over inheritance, and use "does the part survive the whole?" to tell composition from aggregation.
  • One job per class. No class named Manager, Helper, or Util.
  • Say out loud which piece of state is shared and mutable, and how it's protected — before anyone asks.
  • Finish by walking a plausible new requirement through your design.

What's next: the OOP and SOLID lessons make steps 2 through 4 much sharper. The pattern lessons give you ready answers to "what varies here." The concurrency lesson covers step 5 properly. And from lesson 9 onward, you'll run this whole framework end to end on the problems you're most likely to be asked.

PreviousPractice Test: System Design Case StudiesNextOOP Foundations for Design

Course progress

0%
0 of 177 modules complete

On this page

  • What the interviewer is actually grading
  • Step 1 — Requirements: who uses this, and what do they do
  • Step 2 — Entities: turning nouns into classes
  • Step 3 — Relationships and the UML you'll actually use
  • Steps 4–6 — Interfaces, concurrency, extensibility
  • Quick recap