SLIDE 81: Section Intro: Pattern Selection Framework and Anti-Patterns
Section 7: Pattern Selection Framework and Anti-Patterns
Knowing individual design patterns is necessary but not sufficient for LLD interviews. The real skill is recognizing which pattern to apply when you hear a requirement, and equally important, recognizing when applying a pattern would make the design worse. This section builds a repeatable selection framework that maps requirement signals to patterns, walks through complete worked examples of multi-pattern selection, and covers the most common anti-patterns that interviewers test. Think of this section as the “pattern recognition” equivalent of the problem-pattern mapping you use in algorithm interviews.
What We Will Cover
- The pattern selection process: a step-by-step approach
- Complete signal-to-pattern mapping across all patterns from Sections 4-6
- Three complete worked examples: from requirements to pattern selection
- Over-engineering and minimum viable design
- Pattern testing frequency by company and level
- Six production anti-patterns: God Class, Feature Envy, Shotgun Surgery, Circular Dependencies, Premature Abstraction, Inappropriate Intimacy
- How to structure and present your LLD answer in an interview
Why This Section Matters
SLIDE 82: The Pattern Selection Process
Pattern selection is not intuition. It is a repeatable process that you can apply systematically during an LLD interview. Here are the five steps.
Step 1: Identify the Objects and Their Responsibilities
Before reaching for any pattern, identify the core objects in the system and assign each a single responsibility. This is OOP fundamentals (Section 2) and SRP (Section 3). If your objects are wrong, no pattern will save the design.
Step 2: Identify the Dimensions of Variation
Ask: “What in this system changes or varies?” This is the most important question for pattern selection.
- If the algorithm varies: Strategy
- If the object’s behavior varies by state: State
- If the reaction to an event varies: Observer
- If the object creation varies: Factory Method
- If the construction complexity varies: Builder
Step 3: Identify the Cross-Cutting Concerns
Ask: “What behaviors need to be added without modifying core logic?”
- Logging, caching, metrics, encryption: Decorator
- Access control, lazy loading: Proxy
- Interface translation for external systems: Adapter
- Multi-service coordination: Facade
Step 4: Check for Undo, Queuing, or Pipeline Needs
- Operations need to be undone or queued: Command
- Requests pass through sequential checks: Chain of Responsibility
- Algorithm structure is shared but steps differ: Template Method
Step 5: Validate Against the Requirements
For each pattern you selected, verify: “Does the requirement actually demand this pattern, or am I adding it because I know it?” If a simpler solution works (a plain interface, a simple method call, a constructor), prefer that. Patterns add indirection. Indirection is only justified when it solves a specific extensibility, decoupling, or maintainability problem.
Interview Relevance: Walking through these steps out loud during your interview shows the interviewer a structured thought process, not ad-hoc pattern guessing.
SLIDE 82B: Step-by-Step: From Requirements to Patterns
Here is the five-step process applied to a concrete example.
Requirement: “Design a notification service that sends alerts through email, SMS, and push. Different notification types (marketing, transactional, alert) should be routed to different channels. When a notification is sent, log it for compliance and update analytics.”
Step 1: Core Objects
NotificationService (orchestrator), NotificationChannel (delivery), NotificationRouter (routing logic), ComplianceLogger (logging), AnalyticsTracker (analytics).
Step 2: Dimensions of Variation
The delivery channel varies (email, SMS, push). This is a Strategy signal. The routing logic selects which channel to use. This is a Factory signal.
Step 3: Cross-Cutting Concerns
Compliance logging and analytics tracking are reactions to the “notification sent” event, not part of the core delivery logic. This is an Observer signal.
Step 4: Undo/Queuing/Pipeline
No undo needed. No pipeline of checks. No shared algorithm structure.
Step 5: Validate
Three patterns identified: Strategy (channels), Factory (routing), Observer (post-send reactions). Each solves a specific requirement. No pattern is added speculatively.
The Result

Three patterns, each justified by a specific requirement, with no over-engineering.
Interview Relevance: This walkthrough is exactly what interviewers want to see: a structured approach that maps requirements to patterns with explicit justification, not a memorized pattern list applied to every problem.
SLIDE 83: Complete Signal-to-Pattern Mapping
This is the master reference table. Every pattern from Sections 4, 5, and 6 with its recognition signal and one-line justification.
Creational Patterns
Structural Patterns
Behavioral Patterns
Interview Tip: You do not need to memorize pattern names to succeed in an LLD interview. You need to recognize the signal in the requirements and know the structural solution. If you hear “support multiple types of X” and instinctively extract an interface with one implementation per type, you have applied Strategy, whether you name it or not.
Interview Relevance: This table is the equivalent of an algorithm pattern recognition table. Internalizing these signals is the single highest-leverage preparation for LLD interviews.
SLIDE 84: Worked Example: E-Commerce Checkout System
Requirements
Design the checkout flow for a platform like Shopify. The system must:
- Support multiple payment methods (credit card, bank transfer, digital wallet)
- Apply discount codes with different discount types (percentage, flat amount, buy-one-get-one)
- Validate the order through a series of checks (inventory, payment method validity, shipping address, fraud detection)
- Process post-checkout actions (send confirmation email, update inventory, generate invoice)
- The invoice generator is expensive to initialize and not needed for every order (some orders are digital-only)
Pattern Selection Walkthrough
What Is NOT a Pattern
The checkout orchestration (sequence of steps) is a method in the CheckoutService. Not every piece of coordination needs a Facade. If only one caller performs the checkout, a well-structured method is sufficient. Patterns solve extensibility and decoupling problems, not sequencing problems.
Interview Relevance: This worked example demonstrates selective pattern application. Six requirements map to six patterns. The seventh consideration (checkout orchestration) explicitly does not get a pattern. This selectivity is what earns a “strong hire” signal.
SLIDE 84B: Worked Example: Chat Messaging System
Requirements
Design the messaging subsystem for a platform like Slack. The system must:
- Support multiple message types (text, image, file, code snippet) with different rendering
- Messages transition through states (draft, sent, delivered, read, deleted)
- When a message is sent, notify the recipient, update the unread count, and index for search
- Messages can be edited and deleted, with full edit history
- The system integrates with a third-party spam detection API that has a proprietary interface
- Message content should be optionally encrypted and compressed before storage
Pattern Selection Walkthrough
The Architecture

Six patterns, each solving a distinct requirement. The Decorator chain for storage (encryption wrapping compression wrapping database) is independent of the State machine for message lifecycle. Each pattern is isolated and testable.
Interview Relevance: A chat messaging system is one of the most common LLD interview questions at companies like Meta and Slack. Having a pre-practiced pattern mapping for this domain saves valuable interview time.
SLIDE 85: Worked Example: File Storage and Processing Service
Requirements
Design a file storage service like Dropbox. The system must:
- Support uploading, downloading, and deleting files
- Files pass through a processing pipeline: virus scan, metadata extraction, thumbnail generation (for images), and indexing for search
- Processing steps vary by file type (images get thumbnails, documents get text extraction, videos get transcoding)
- Large files should be lazy-loaded (metadata first, content on demand)
- The system integrates with multiple cloud storage backends (AWS S3, Google Cloud Storage, Azure Blob Storage)
- All operations should be logged for audit compliance
Pattern Selection
Key Insight: Not Every Requirement Needs a Pattern
The core CRUD operations (upload, download, delete) are methods on a FileStorageService interface. They do not need a pattern. The Adapter wraps the cloud backends behind this interface. The Decorator adds logging on top. But the operations themselves are just methods. Wrapping simple method calls in Command objects or Strategy objects when there is only one algorithm is over-engineering.
Interview Tip: After identifying which patterns you will use, explicitly state which requirements do NOT get a pattern. “Upload and download are simple interface methods. I did not add a pattern here because there is no extensibility requirement and no variation to manage.” This demonstrates the restraint that separates senior designers from pattern-enthusiastic juniors.
Interview Relevance: File storage is a common LLD question at companies like Dropbox and Google. The key differentiator is the processing pipeline design (Chain of Responsibility vs Template Method) and the lazy-loading decision (Virtual Proxy).
SLIDE 85B: Interview Practice: Rapid Pattern Recognition
Instructions: For each requirement below, identify the primary pattern in under 10 seconds. Pause after each one and check your answer.
Requirement 1: “Users can export reports in PDF, CSV, or Excel format.”
Answer: Strategy (ExportStrategy). Three algorithms for the same operation, selected based on user choice.
Requirement 2: “When a payment fails, send an alert to the operations team, retry the payment in 5 minutes, and update the customer’s dashboard.”
Answer: Observer. Three independent reactions to a single event. The payment system should not know about ops alerts, retries, or dashboards.
Requirement 3: “The search query object has: search term (required), filters (optional, 0-N), sort order (optional), page size (optional, default 20), date range (optional), and include-archived flag (optional, default false).”
Answer: Builder. Six parameters, five optional, with defaults.
Requirement 4: “We need to integrate with a legacy inventory system that uses XML-RPC while our system uses REST-style JSON interfaces.”
Answer: Adapter. Two incompatible interfaces that need to work together.
Requirement 5: “Add request timing, authentication logging, and rate limiting to all API endpoints without modifying the endpoint handlers.”
Answer: Decorator (or Chain of Responsibility). Three cross-cutting concerns layered on top of existing handlers. Decorator if they wrap the handler; Chain of Responsibility if they form a pipeline.
Requirement 6: “A support ticket moves through states: Open, In Progress, Waiting on Customer, Resolved, Closed. Each state allows different actions.”
Answer: State. Object behavior changes based on lifecycle state, with explicit valid transitions.
SLIDE 86: Over-Engineering Anti-Pattern
Over-engineering is the most common anti-pattern in LLD interviews. It occurs when a candidate applies patterns, abstractions, or extensibility mechanisms that are not justified by the current requirements. Over-engineering signals to the interviewer that the candidate cannot distinguish between “what might change someday” and “what the requirements actually demand.”
What Over-Engineering Looks Like
A candidate designing a parking lot system creates: a VehicleFactory (there are only 3 types, a simple enum works), a ParkingStrategyFactory that creates ParkingStrategy objects (there is only one strategy: find the nearest spot), a SpotObserver that fires events when spots are taken (no one subscribes to these events), and a SpotStatePattern for each spot (spots are either available or occupied, a boolean suffices).
Four patterns applied, none justified by requirements. The design is harder to understand, harder to implement, and harder to maintain than a straightforward solution with enums, simple classes, and boolean fields.
The Root Cause
Over-engineering usually comes from one of three mindsets:
- “I want to show the interviewer that I know many patterns” (interviewers penalize this, not reward it)
- “What if the requirements change in the future?” (design for today’s requirements, not hypothetical future ones)
- “This is how I was taught to do it” (textbooks teach patterns in isolation; production code uses them selectively)
Interview Relevance: Interviewers specifically watch for over-engineering. A design with 2 well-justified patterns scores higher than a design with 6 unjustified patterns. Less is more when each choice is deliberate.
SLIDE 86B: Minimum Viable Design Principle
The minimum viable design (MVD) principle states: apply the fewest patterns and abstractions that satisfy the stated requirements and make the design testable. Add more only when the interviewer explicitly asks for extensibility or when a requirement demands it.
The MVD Process
- Start with plain classes, simple constructors, and direct method calls
- Extract an interface only when there are (or the requirements state there will be) multiple implementations
- Apply a pattern only when you can name the specific requirement it satisfies
- If the interviewer says “what if we need to add X?”, then apply the pattern that enables X
MVD Applied: Parking Lot
The MVD approach has ~4 classes. The over-engineered approach has ~15 classes solving problems that do not exist.
When MVD Does Not Apply
If the requirements explicitly state: “support multiple parking strategies” or “notify when a floor is full,” then the corresponding patterns are justified. MVD means matching your design to the requirements, not minimizing patterns for their own sake.
Interview Tip: After presenting your design, tell the interviewer: “This design satisfies the stated requirements with [N] patterns. If you would like me to add extensibility for [specific scenario], I can show how [specific pattern] would enable that.” This gives the interviewer the option to probe deeper while demonstrating that your initial design is intentionally minimal.
Interview Relevance: The MVD approach is what senior engineers practice in production. Interviewers reward it because it demonstrates the judgment to apply patterns selectively rather than reflexively.
SLIDE 87: Patterns Interviewers Test Frequently vs Rarely
Not all patterns are equally likely to appear in LLD interviews. Focusing your preparation on high-frequency patterns gives you the best return on study time.
Pattern Frequency by Interview Likelihood
Where to Focus
Tier 1 patterns appear in 80%+ of LLD interviews. If you deeply understand Strategy, Observer, Factory Method, and State, and you can recognize their signals instantly, you will handle the majority of LLD rounds.
Tier 2 patterns appear in 40-60% of interviews. They are the patterns that differentiate a “hire” from a “strong hire” because they solve secondary requirements (undo, logging, validation pipelines) that many candidates overlook.
Tiers 3 and 4 are worth knowing conceptually but not worth deep preparation unless you have already mastered Tiers 1 and 2.
Interview Relevance: Spending 80% of your prep time on Tier 1 and Tier 2 patterns gives you the highest coverage across companies and levels.
SLIDE 87B: Pattern Testing Frequency by Company and Level
Different companies and levels emphasize different aspects of LLD. Knowing this helps you allocate preparation time.
By Company Type
By Level
Interview Tip: At mid-level, showing you know the patterns is sufficient. At senior level and above, showing restraint (not using a pattern when it is unnecessary) and connecting your class design to broader system concerns (scalability, team ownership, deployment boundaries) is what earns top ratings.
Interview Relevance: Calibrate your preparation to your target level. Mid-level candidates should focus on pattern mechanics. Senior candidates should focus on pattern selection and anti-pattern recognition.
SLIDE 88: God Class Anti-Pattern
The God Class (also called a Blob class) is a single class that has grown to handle too many responsibilities. It typically has 20+ methods across unrelated domains, 10+ dependencies injected through its constructor, and is the class that every developer dreads modifying because changes to any feature risk breaking unrelated features.
How God Classes Form
God Classes rarely start as God Classes. They start as a reasonable service class with 3-4 methods. As the product evolves, developers add methods to the existing class rather than creating new classes because it is faster and avoids the “where does this go?” decision. After 18 months of incremental additions, the class has 1500 lines, 12 dependencies, and 25 methods spanning authentication, billing, notifications, and reporting.
Detection Signals
- Class has methods from 3+ unrelated domains
- Constructor takes 8+ dependencies
- Class is modified in every sprint by different developers for different features
- Unit tests require mocking 10+ dependencies
- Class name is vague:
UserService,AppManager,CoreHandler
Interview Relevance: Interviewers present God Classes and ask “what is wrong with this design?” The answer is SRP violation. The refactoring is to identify change drivers and extract each into a focused class.
SLIDE 88B: God Class: Concrete Example and Refactoring
Before: The God OrderService
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentGateway paymentGateway;
private final InventoryService inventoryService;
private final ShippingService shippingService;
private final EmailClient emailClient;
private final SmsGateway smsGateway;
private final AnalyticsTracker analyticsTracker;
private final FraudDetector fraudDetector;
private final TaxCalculator taxCalculator;
private final DiscountEngine discountEngine;
private final InvoiceGenerator invoiceGenerator;
private final AuditLogger auditLogger;
public OrderResult placeOrder(OrderRequest request) { ... }
public void cancelOrder(String orderId) { ... }
public RefundResult processRefund(String orderId) { ... }
public void updateShippingAddress(String orderId, Address address) { ... }
public InvoiceDocument generateInvoice(String orderId) { ... }
public void sendOrderConfirmation(String orderId) { ... }
public void sendShippingNotification(String orderId) { ... }
public List<Order> getOrderHistory(String customerId) { ... }
public OrderAnalytics getOrderAnalytics(DateRange range) { ... }
public FraudCheckResult checkForFraud(OrderRequest request) { ... }
public Money calculateTax(OrderRequest request) { ... }
public Money applyDiscounts(OrderRequest request) { ... }
}
Twelve dependencies, twelve methods, six unrelated domains (ordering, payment, shipping, notifications, analytics, fraud).
After: Focused Services
public class OrderPlacementService {
private final OrderRepository orderRepository;
private final PaymentService paymentService;
private final InventoryService inventoryService;
private final OrderEventPublisher eventPublisher;
public OrderResult placeOrder(OrderRequest request) {
inventoryService.reserve(request.getItems());
PaymentResult payment = paymentService.charge(request);
Order order = Order.create(request, payment.getTransactionId());
orderRepository.save(order);
eventPublisher.publish(new OrderPlacedEvent(order));
return OrderResult.success(order.getId());
}
}
public class OrderPricingService {
private final TaxCalculator taxCalculator;
private final DiscountEngine discountEngine;
public PricingBreakdown calculatePricing(OrderRequest request) {
Money subtotal = request.calculateSubtotal();
Money discount = discountEngine.bestDiscount(request);
Money tax = taxCalculator.calculate(subtotal.subtract(discount));
return new PricingBreakdown(subtotal, discount, tax);
}
}
Each service has 2-4 dependencies and 1-3 methods in a single domain. The OrderPlacementService orchestrates the core flow. Notifications are handled by Observer listeners on the OrderPlacedEvent. Analytics and fraud detection are separate services.
Interview Relevance: Refactoring a God Class into focused services is one of the most common LLD interview exercises. Showing the before and after with explicit dependency counts demonstrates practical refactoring skill.
SLIDE 89: Feature Envy and Inappropriate Intimacy
Feature Envy
Feature Envy occurs when a method in one class uses more data from another class than from its own. The method is “envious” of the other class’s data and should probably live there instead.
This method accesses items, price, quantity, taxRate, and weight from Order but uses nothing from its own class. The calculation logic belongs in Order or a dedicated OrderPricingService.
The Fix: Move the method to the class whose data it uses, or create a service class that encapsulates the calculation.
Inappropriate Intimacy
Inappropriate Intimacy occurs when two classes are too tightly coupled, accessing each other’s internal details. This often manifests as classes reaching into each other’s private data through getters, or two classes that cannot be modified independently.
Detection Signals for Both
Interview Relevance: Interviewers test Feature Envy by showing you a method and asking “is this in the right class?” If the method uses more data from another class, the answer is “this method should be moved to the class it envies.”
SLIDE 90: Shotgun Surgery Anti-Pattern
Shotgun Surgery is the opposite of the God Class. While a God Class has too many responsibilities in one place, Shotgun Surgery scatters one responsibility across too many places. A single logical change requires editing 10+ files.
Example
Adding a new customer notification type requires editing:
CustomerService.java(add notification logic)NotificationTemplates.java(add new template)EmailFormatter.java(add formatting for new type)SmsFormatter.java(add formatting for new type)NotificationConfig.java(add configuration entry)NotificationValidator.java(add validation for new type)NotificationMetrics.java(add metrics tracking)NotificationTest.java(add test cases)
Eight files modified for one logical change. If a developer forgets to update SmsFormatter, SMS notifications for the new type silently fail in production.
The Fix
Consolidate the scattered responsibility. Each notification type should be a self-contained class (a Strategy implementation) that encapsulates its template, formatting, validation, and configuration. Adding a new type means creating one new file, not editing eight existing ones.
public class WelcomeNotification implements NotificationType {
public String getTemplateName() { return "welcome"; }
public String formatForEmail(Customer customer) { ... }
public String formatForSms(Customer customer) { ... }
public boolean isValid(NotificationRequest request) { ... }
public Map<String, String> getDefaultConfig() { ... }
}
One file per notification type. Adding a new type is one new class. This is the OCP principle applied to resolve Shotgun Surgery.
Interview Tip: Shotgun Surgery and God Class are two sides of the same coin. God Class means too much in one place. Shotgun Surgery means too little in each place. The fix for both is finding the right boundary: each class owns one complete responsibility, no more and no less.
Interview Relevance: Interviewers test Shotgun Surgery by describing a change that touches many files and asking “how would you restructure this?” The answer is always: consolidate the scattered responsibility into a cohesive class or module.
SLIDE 91: Circular Dependencies
A circular dependency occurs when class A depends on class B, and class B depends on class A (directly or through a chain). Circular dependencies create systems where you cannot understand, test, or deploy one class without the other. They are a strong signal of a design flaw.
The Problem
public class OrderService {
private final BillingService billingService;
public void placeOrder(Order order) {
billingService.createInvoice(order);
}
}
public class BillingService {
private final OrderService orderService;
public void processPayment(String invoiceId) {
Order order = orderService.getOrder(invoiceId);
chargeCustomer(order);
}
}
OrderService depends on BillingService and BillingService depends on OrderService. You cannot instantiate either one without the other. You cannot test either one without a real (or mocked) instance of the other. If both classes are in different modules or services, you have a deployment cycle: neither can be deployed independently.
Three Fixes
Fix 1: Extract Shared Interface
Both classes depend on an interface that neither owns. BillingService depends on OrderRepository (an interface) instead of OrderService directly. The cycle is broken because the dependency arrow points to the interface, not to the concrete class.
Fix 2: Introduce an Event
OrderService publishes an OrderPlacedEvent. BillingService listens for it. Neither class references the other. The Observer pattern breaks the cycle by introducing an indirection through events.
Fix 3: Extract a Third Class
The shared logic lives in a new class (OrderBillingCoordinator) that depends on both OrderService and BillingService. Neither OrderService nor BillingService depends on the other. The coordinator manages the interaction.
Interview Relevance: Circular dependencies are a design smell that interviewers ask you to detect and resolve. The three fixes (shared interface, events, coordinator extraction) cover the most common interview scenarios.
SLIDE 91B: Premature Abstraction
Premature abstraction occurs when you create interfaces, abstract classes, or pattern-based indirection before you have evidence that the abstraction is needed. It is the abstraction equivalent of premature optimization: it adds complexity now for a benefit that may never materialize.
The Problem
public interface UserRepository {
User findById(String id);
void save(User user);
}
public class PostgresUserRepository implements UserRepository {
private final DataSource dataSource;
public PostgresUserRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public User findById(String id) {
return JdbcTemplate.queryForObject(dataSource, "SELECT * FROM users WHERE id = ?", id);
}
@Override
public void save(User user) {
JdbcTemplate.update(dataSource, "INSERT INTO users VALUES (?, ?)", user.getId(), user.getName());
}
}
If there is only one implementation and no plan to add another, the interface adds a layer of indirection with zero benefit. Every developer who navigates from the interface to the implementation wastes time. Every refactoring tool that renames a method must update the interface and the implementation. The interface exists “just in case” the database changes, but the database has not changed in five years.
When Abstraction IS Justified
- There are currently 2+ implementations (Strategy, Factory)
- The requirement explicitly states that the component will be swapped (DIP for third-party integrations)
- The abstraction enables testability that would otherwise be impossible (mocking external services)
- Multiple consumers depend on the contract (the interface stabilizes the API)
When Abstraction Is Premature
- Single implementation with no concrete plan for a second
- The interface mirrors the implementation exactly with no behavioral contract
- The abstraction is added “for flexibility” without a specific flexibility requirement
- Adding the abstraction makes the codebase harder to navigate for new developers
The Guideline
Wait until you need the abstraction, then add it. Extracting an interface from an existing class takes 30 seconds with modern IDE tooling. There is no penalty for adding it later and a real cost to adding it too early.
Interview Relevance: In an LLD interview, do not add interfaces for every class. Add them where the requirements demand multiple implementations or where DIP is needed for testability. The interviewer will respect your restraint.
SLIDE 92: Interview Practice: Spotting Anti-Patterns in Code
Scenario
An interviewer shows you this class and asks: “What design problems do you see?”
public class ReportManager {
private final DatabaseConnection dbConnection;
private final SmtpClient smtpClient;
private final PdfRenderer pdfRenderer;
private final CsvWriter csvWriter;
private final SlackWebhook slackWebhook;
private final S3Client s3Client;
private final MetricsCollector metricsCollector;
private final UserRepository userRepository;
public Report generateReport(ReportRequest request) {
List<DataRow> data = dbConnection.query(request.getSqlQuery());
Report report = new Report(data);
metricsCollector.increment("reports_generated");
return report;
}
public void emailReport(Report report, String recipientEmail) {
byte[] pdf = pdfRenderer.render(report.getData());
smtpClient.sendWithAttachment(recipientEmail, "Your Report", pdf);
}
public void uploadToS3(Report report, String bucketPath) {
byte[] csv = csvWriter.write(report.getData());
s3Client.putObject(bucketPath, csv);
}
public void notifySlack(String channel, String message) {
slackWebhook.post(channel, message);
}
public User getReportOwner(String reportId) {
return userRepository.findById(reportId);
}
}
Pause the video and identify all anti-patterns for 60 seconds before continuing.
Anti-Patterns Identified
A strong answer identifies at least three of these anti-patterns, names the SOLID principle each violates, and sketches the refactored structure with focused classes and interfaces.
SLIDE 93: How to Present Your Design in an Interview
Knowing the patterns is not enough. How you communicate your design in real time determines your interview score. This slide covers the presentation structure that earns the strongest evaluations.
The Five-Phase LLD Interview Structure
Phase 1: Clarify Requirements (3-5 minutes)
Ask clarifying questions to narrow scope. “What types of X do we need to support? Will there be more types in the future? Do we need undo support? How many concurrent users?” Do not design for every possible requirement. Design for the stated ones and ask about ambiguous ones.
Phase 2: Identify Core Objects (3-5 minutes)
List the 4-6 core classes and their responsibilities. State one sentence per class: “OrderService orchestrates the checkout flow. PaymentProcessor handles payment execution. NotificationService sends post-order notifications.” This establishes the vocabulary for the rest of the discussion.
Phase 3: Define Relationships and Interfaces (5-10 minutes)
Draw or describe the relationships between classes. Define key interfaces. This is where patterns emerge. “Since we need multiple payment types, PaymentProcessor is an interface with one implementation per type. Since notifications should not block checkout, NotificationService subscribes to order events through an Observer.”
Phase 4: Detailed Class Design (10-15 minutes)
Write key method signatures and constructors. Show one or two critical methods in detail. This is where encapsulation, SOLID, and clean code are evaluated.
Phase 5: Extensibility and Trade-offs (5 minutes)
Discuss what you would add if requirements changed. “If we needed undo support, I would introduce Command objects for each order action.” Proactively mention one trade-off you made: “I chose composition over inheritance for the pricing strategies because we have two independent dimensions of variation.”
Interview Relevance: This five-phase structure maps directly to how interviewers evaluate LLD candidates. Each phase corresponds to a rubric dimension: requirements clarification, object identification, OOP/SOLID compliance, design depth, and extensibility thinking.
SLIDE 93B: Structuring Your LLD Answer: Common Timing Mistakes
Mistake 1: Spending 15 Minutes on Requirements
Over-clarifying delays the design phase. Ask 3-5 targeted questions, state your assumptions for anything ambiguous, and start designing. The interviewer can redirect if your assumptions are wrong.
Mistake 2: Jumping Straight to Code
Writing code before establishing the class structure means you are designing while coding, which produces messy, unplanned results. Spend 5 minutes on the class diagram before writing any method.
Mistake 3: Drawing a Full UML Diagram with No Explanation
A diagram without verbal explanation leaves the interviewer guessing why you made each decision. Narrate as you draw: “This is an interface because we need multiple implementations. This class depends on the interface, not the concrete class, for testability.”
Mistake 4: Designing for Every Possible Future Requirement
“What if we need to support 50 notification channels and 12 payment providers and multilingual templates and…” Stop. Design for the stated requirements. Mention extensibility points at the end.
Recommended Time Allocation for a 45-Minute LLD Round
Interview Tip: Practice the timing with a stopwatch. Most candidates spend too long on clarification and run out of time before reaching the detailed design phase, which is where the strongest evaluation signals come from.
Interview Relevance: Time management in an LLD interview is a meta-skill that directly affects your score. A complete, well-paced answer with 2 patterns scores higher than a perfect but incomplete answer with 5 patterns.
SLIDE 94: Note It Down: Complete Pattern Selection Reference
This is the master reference for pattern selection. Screenshot this slide or write it down.
The Three Questions
- What varies? Answer maps to: Strategy, State, Factory, Template Method
- What reacts? Answer maps to: Observer, Command, Chain of Responsibility
- What wraps? Answer maps to: Decorator, Proxy, Adapter, Facade
The Danger Signals (Stop and Reconsider)
The Anti-Pattern Quick Check
SLIDE 95: Section 7 Interview Practice and Common Mistakes
Practice Scenario
You are in an LLD interview designing a task management system like Jira. The requirements are: tasks can be created, assigned, and commented on. Tasks move through states (To Do, In Progress, In Review, Done). When a task changes state, the assignee and watchers should be notified. Tasks can have different priority levels that affect sorting in the board view.
You have 45 minutes. Walk through your design.
Pause the video and plan your five-phase approach for 2 minutes before continuing.
Strong Approach
Phase 1 (3 min): Clarify. “How many task states? Are transitions restricted? What notification channels? Is priority fixed or configurable?”
Phase 2 (3 min): Core objects. Task, TaskState, TaskBoard, NotificationService, PriorityComparator.
Phase 3 (7 min): Relationships. Task lifecycle = State pattern. Notifications on state change = Observer. Priority sorting = Strategy (if configurable) or simple Comparator (if fixed). No Factory needed since there is one task type. No Builder needed since tasks have few required fields.
Phase 4 (15 min): Detail the TaskState interface and two state implementations. Show TaskEventListener interface with EmailNotifier and SlackNotifier. Write Task.transition() method.
Phase 5 (5 min): “If we need undo for state transitions, I would wrap transitions in Command objects. If we need custom workflows per project, I would make the state machine configurable.”
Common Pattern Selection Mistakes
Interview Relevance: This scenario tests pattern selection restraint. The correct answer uses 2-3 patterns (State, Observer, and possibly Strategy). Using more than that is a red flag for over-engineering.
SLIDE 96: Section Summary and Key Takeaways
Concepts Covered
Common Interview Mistakes
How This Connects to Other Sections
- Sections 2-3 (OOP + SOLID): Pattern selection is justified by OOP principles and SOLID violations. “I chose Strategy because the if/else chain violates OCP” is the connection.
- Sections 4-6 (All Patterns): This section synthesized the individual patterns into a unified selection framework with signal mapping and worked examples.
- Section 8 (Cheat Sheet): The master reference table from this section is compiled with all other section references into the final course cheat sheet.