Implement Key Components in LLD Interviews

Updated 2026-03-11

TL;DR

Implementing key components means writing working code for the critical parts of your design first, not trying to build everything at once. Focus on core functionality that demonstrates your understanding of the problem, then expand incrementally. This approach helps you manage time, catch design flaws early, and show interviewers you can prioritize effectively.

Prerequisites: Basic understanding of OOP principles (classes, methods, encapsulation), familiarity with at least one programming language (Python, Java, or C++), ability to read class diagrams, and understanding of interface design.

After this topic: Identify which components are critical to implement first in an OOP design problem, write working code for core functionality within interview time constraints, demonstrate a systematic approach to building complex systems incrementally, and explain your implementation priorities to interviewers.

Core Concept

What Are Key Components?

Key components are the classes, methods, and relationships that form the backbone of your system. They’re the parts that:

  • Directly solve the core problem
  • Other components depend on
  • Demonstrate your understanding of the domain
  • Are most likely to reveal design flaws

In a 45-minute interview, you cannot implement everything. You must identify what matters most.

The Priority Framework

Use this hierarchy to decide what to implement:

1. Core Domain Classes — The main entities in your problem (e.g., User, Account, Vehicle). These represent the “nouns” of your system.

2. Critical Operations — The methods that perform the primary use case (e.g., transfer_money(), book_ride(), process_payment()). These are the “verbs” that make your system useful.

3. Key Relationships — How core classes interact (e.g., composition, inheritance, associations). Show one or two important relationships with actual code.

4. Essential Data Structures — Internal collections or storage mechanisms that enable core operations (e.g., a dictionary mapping user IDs to accounts).

5. Error Handling — Basic validation for the happy path. Don’t over-engineer edge cases initially.

The Implementation Strategy

Follow this sequence:

Step 1: Stub Out Core Classes — Create class definitions with key attributes and method signatures. Use comments or pass statements for method bodies initially.

Step 2: Implement One Complete Flow — Pick the most important use case and implement it end-to-end. This proves your design works.

Step 3: Add Supporting Methods — Fill in helper methods and utilities that your core flow needs.

Step 4: Expand Incrementally — If time permits, add secondary features or refine existing code.

This approach gives you a working system quickly, allowing you to demonstrate functionality and adjust based on interviewer feedback.

Visual Guide

Implementation Priority Flow

graph TD
    A[Design Complete] --> B[Identify Core Classes]
    B --> C[Stub Out Class Definitions]
    C --> D[Choose Primary Use Case]
    D --> E[Implement Core Flow End-to-End]
    E --> F{Does It Work?}
    F -->|No| G[Debug & Refine]
    G --> E
    F -->|Yes| H[Add Supporting Methods]
    H --> I{Time Remaining?}
    I -->|Yes| J[Expand Features]
    I -->|No| K[Code Review & Explain]
    J --> K

Follow this systematic approach to implement key components efficiently during interviews. Always get something working before adding complexity.

Component Priority Levels

graph LR
    A[All Components] --> B[P1: Core Domain Classes]
    A --> C[P2: Critical Operations]
    A --> D[P3: Key Relationships]
    A --> E[P4: Data Structures]
    A --> F[P5: Error Handling]
    A --> G[P6: Edge Cases]
    A --> H[P7: Optimizations]
    
    style B fill:#ff6b6b
    style C fill:#ff8787
    style D fill:#ffa07a
    style E fill:#ffd93d
    style F fill:#6bcf7f
    style G fill:#95e1d3
    style H fill:#a8dadc

Prioritize implementation from P1 (must-have) to P7 (nice-to-have). In a 45-minute interview, focus on P1-P3, touch P4-P5 if time allows.

Examples

Example 1: Parking Lot System — Identifying Key Components

Problem: Design a parking lot system that can park and remove vehicles.

Step 1: Identify Core Classes

# Core domain classes identified:
# - ParkingLot (manages the entire system)
# - ParkingSpot (represents a single spot)
# - Vehicle (represents cars, motorcycles, etc.)
# - Ticket (proof of parking)

from enum import Enum
from datetime import datetime
from typing import Optional, List

class VehicleType(Enum):
    MOTORCYCLE = 1
    CAR = 2
    TRUCK = 3

class SpotSize(Enum):
    SMALL = 1   # Motorcycles
    MEDIUM = 2  # Cars
    LARGE = 3   # Trucks

Step 2: Stub Out Classes with Key Methods

class Vehicle:
    def __init__(self, license_plate: str, vehicle_type: VehicleType):
        self.license_plate = license_plate
        self.vehicle_type = vehicle_type

class ParkingSpot:
    def __init__(self, spot_id: int, size: SpotSize):
        self.spot_id = spot_id
        self.size = size
        self.vehicle: Optional[Vehicle] = None
    
    def is_available(self) -> bool:
        return self.vehicle is None
    
    def can_fit(self, vehicle: Vehicle) -> bool:
        # Map vehicle types to required spot sizes
        required_size = {
            VehicleType.MOTORCYCLE: SpotSize.SMALL,
            VehicleType.CAR: SpotSize.MEDIUM,
            VehicleType.TRUCK: SpotSize.LARGE
        }
        return self.size.value >= required_size[vehicle.vehicle_type].value
    
    def park_vehicle(self, vehicle: Vehicle) -> bool:
        if self.is_available() and self.can_fit(vehicle):
            self.vehicle = vehicle
            return True
        return False
    
    def remove_vehicle(self) -> Optional[Vehicle]:
        vehicle = self.vehicle
        self.vehicle = None
        return vehicle

class Ticket:
    def __init__(self, ticket_id: int, vehicle: Vehicle, spot: ParkingSpot):
        self.ticket_id = ticket_id
        self.vehicle = vehicle
        self.spot = spot
        self.entry_time = datetime.now()

Step 3: Implement Core Flow (Park a Vehicle)

class ParkingLot:
    def __init__(self, name: str):
        self.name = name
        self.spots: List[ParkingSpot] = []
        self.tickets: dict[int, Ticket] = {}  # ticket_id -> Ticket
        self.next_ticket_id = 1
    
    def add_spot(self, spot: ParkingSpot):
        """Initialize parking lot with spots"""
        self.spots.append(spot)
    
    def park_vehicle(self, vehicle: Vehicle) -> Optional[Ticket]:
        """Core operation: Park a vehicle and return a ticket"""
        # Find first available spot that fits the vehicle
        for spot in self.spots:
            if spot.is_available() and spot.can_fit(vehicle):
                if spot.park_vehicle(vehicle):
                    # Create ticket
                    ticket = Ticket(self.next_ticket_id, vehicle, spot)
                    self.tickets[ticket.ticket_id] = ticket
                    self.next_ticket_id += 1
                    return ticket
        return None  # No available spot
    
    def remove_vehicle(self, ticket_id: int) -> bool:
        """Core operation: Remove a vehicle using ticket"""
        if ticket_id not in self.tickets:
            return False
        
        ticket = self.tickets[ticket_id]
        vehicle = ticket.spot.remove_vehicle()
        
        if vehicle:
            del self.tickets[ticket_id]
            return True
        return False

# Expected Output:
parking_lot = ParkingLot("Downtown Lot")

# Add spots
parking_lot.add_spot(ParkingSpot(1, SpotSize.SMALL))
parking_lot.add_spot(ParkingSpot(2, SpotSize.MEDIUM))
parking_lot.add_spot(ParkingSpot(3, SpotSize.LARGE))

# Park vehicles
car = Vehicle("ABC123", VehicleType.CAR)
ticket = parking_lot.park_vehicle(car)

if ticket:
    print(f"Vehicle parked. Ticket ID: {ticket.ticket_id}, Spot: {ticket.spot.spot_id}")
    # Output: Vehicle parked. Ticket ID: 1, Spot: 2

# Remove vehicle
success = parking_lot.remove_vehicle(ticket.ticket_id)
print(f"Vehicle removed: {success}")
# Output: Vehicle removed: True

Try it yourself: Add a method get_available_spots_count() that returns how many spots are currently available.


Example 2: Library Management System — Incremental Implementation

Problem: Design a library system where users can borrow and return books.

Step 1: Core Classes (Stubbed)

from datetime import datetime, timedelta
from typing import Optional, List

class Book:
    def __init__(self, isbn: str, title: str, author: str):
        self.isbn = isbn
        self.title = title
        self.author = author
        self.is_borrowed = False
        self.borrower: Optional['User'] = None

class User:
    def __init__(self, user_id: int, name: str):
        self.user_id = user_id
        self.name = name
        self.borrowed_books: List[Book] = []
        self.max_books = 3  # Business rule

class Library:
    def __init__(self):
        self.books: dict[str, Book] = {}  # isbn -> Book
        self.users: dict[int, User] = {}  # user_id -> User

Step 2: Implement Primary Use Case (Borrow Book)

class Library:
    def __init__(self):
        self.books: dict[str, Book] = {}
        self.users: dict[int, User] = {}
    
    def add_book(self, book: Book):
        self.books[book.isbn] = book
    
    def register_user(self, user: User):
        self.users[user.user_id] = user
    
    def borrow_book(self, user_id: int, isbn: str) -> bool:
        """Core operation: User borrows a book"""
        # Validation
        if user_id not in self.users:
            print(f"Error: User {user_id} not found")
            return False
        
        if isbn not in self.books:
            print(f"Error: Book {isbn} not found")
            return False
        
        user = self.users[user_id]
        book = self.books[isbn]
        
        # Business rules
        if len(user.borrowed_books) >= user.max_books:
            print(f"Error: User {user.name} has reached borrowing limit")
            return False
        
        if book.is_borrowed:
            print(f"Error: Book '{book.title}' is already borrowed")
            return False
        
        # Execute borrow
        book.is_borrowed = True
        book.borrower = user
        user.borrowed_books.append(book)
        return True

# Expected Output:
library = Library()

# Setup
book1 = Book("978-0134685991", "Effective Java", "Joshua Bloch")
book2 = Book("978-0132350884", "Clean Code", "Robert Martin")
library.add_book(book1)
library.add_book(book2)

user = User(1, "Alice")
library.register_user(user)

# Borrow book
success = library.borrow_book(1, "978-0134685991")
print(f"Borrow successful: {success}")
# Output: Borrow successful: True

print(f"Alice's books: {[b.title for b in user.borrowed_books]}")
# Output: Alice's books: ['Effective Java']

# Try to borrow already borrowed book
success = library.borrow_book(1, "978-0134685991")
# Output: Error: Book 'Effective Java' is already borrowed
# Output: Borrow successful: False

Step 3: Add Supporting Operation (Return Book)

class Library:
    # ... previous methods ...
    
    def return_book(self, user_id: int, isbn: str) -> bool:
        """Supporting operation: User returns a book"""
        if user_id not in self.users or isbn not in self.books:
            return False
        
        user = self.users[user_id]
        book = self.books[isbn]
        
        # Check if user actually borrowed this book
        if book not in user.borrowed_books:
            print(f"Error: User {user.name} hasn't borrowed '{book.title}'")
            return False
        
        # Execute return
        book.is_borrowed = False
        book.borrower = None
        user.borrowed_books.remove(book)
        return True

# Expected Output:
success = library.return_book(1, "978-0134685991")
print(f"Return successful: {success}")
# Output: Return successful: True

print(f"Alice's books: {[b.title for b in user.borrowed_books]}")
# Output: Alice's books: []

Try it yourself: Add a method search_books(title_keyword: str) that returns all books whose titles contain the keyword.


Java Differences

In Java, you’d use:

  • ArrayList<Book> instead of List[Book]
  • HashMap<String, Book> instead of dict[str, Book]
  • Explicit getters/setters for encapsulation
  • null instead of None
public class Library {
    private Map<String, Book> books;
    private Map<Integer, User> users;
    
    public Library() {
        this.books = new HashMap<>();
        this.users = new HashMap<>();
    }
    
    public boolean borrowBook(int userId, String isbn) {
        // Implementation similar to Python
    }
}

C++ Differences

In C++, you’d manage:

  • Memory explicitly with pointers or smart pointers (std::shared_ptr<Book>)
  • std::unordered_map<std::string, Book*> for dictionaries
  • std::vector<Book*> for lists
  • Destructors for cleanup

Common Mistakes

1. Trying to Implement Everything

Mistake: Starting to code every class and method from your design diagram.

Why it’s wrong: You’ll run out of time and have nothing working to show. Interviewers value a working subset over incomplete everything.

Fix: Implement one complete vertical slice (end-to-end flow) first. For a parking lot, implement park and remove completely before adding payment processing.


2. Implementing in the Wrong Order

Mistake: Starting with edge cases, optimizations, or peripheral features.

# DON'T start here:
def calculate_parking_fee_with_discounts(ticket, is_weekend, has_membership, promo_code):
    # Complex pricing logic...

Why it’s wrong: You’re solving problems that don’t matter if the core doesn’t work.

Fix: Always implement the happy path first. Get park_vehicle() and remove_vehicle() working before worrying about pricing, discounts, or error messages.


3. Writing Pseudo-Code Instead of Real Code

Mistake: Using comments or pseudo-code for critical methods.

class ParkingLot:
    def park_vehicle(self, vehicle):
        # TODO: Find available spot
        # TODO: Assign vehicle to spot
        # TODO: Create ticket
        pass

Why it’s wrong: The interviewer can’t verify your logic works. You’re not demonstrating coding ability.

Fix: Write actual working code for key methods. It’s okay to stub out helper methods, but core operations must be real.

def park_vehicle(self, vehicle: Vehicle) -> Optional[Ticket]:
    for spot in self.spots:
        if spot.is_available() and spot.can_fit(vehicle):
            spot.park_vehicle(vehicle)
            return Ticket(self.next_ticket_id, vehicle, spot)
    return None

4. No Error Handling in Core Methods

Mistake: Assuming everything succeeds without checking.

def borrow_book(self, user_id, isbn):
    user = self.users[user_id]  # KeyError if user doesn't exist
    book = self.books[isbn]      # KeyError if book doesn't exist
    user.borrowed_books.append(book)

Why it’s wrong: Your code will crash on invalid input. Shows lack of defensive programming.

Fix: Add basic validation for the happy path. Return None, False, or raise exceptions for errors.

def borrow_book(self, user_id, isbn) -> bool:
    if user_id not in self.users or isbn not in self.books:
        return False
    # ... rest of logic

5. Ignoring the Interviewer’s Feedback

Mistake: Continuing to implement your original plan when the interviewer suggests changes.

Why it’s wrong: Interviewers test your ability to adapt and collaborate. Ignoring feedback signals poor teamwork.

Fix: When an interviewer says “What if we need to support multiple parking lots?” or “How would you handle concurrency?”, acknowledge it and adjust your implementation priority. Ask: “Should I refactor now or note it for later?”

Interview Tips

1. Announce Your Implementation Plan

Before writing code, tell the interviewer: “I’m going to implement the core classes first — ParkingLot, ParkingSpot, and Vehicle. Then I’ll implement the park_vehicle() method end-to-end. After that works, I’ll add remove_vehicle(). Does that sound good?”

Why this works: Sets expectations, shows you can prioritize, and gives the interviewer a chance to redirect you if needed.


2. Write Method Signatures First

Stub out all methods with signatures and docstrings before implementing:

class Library:
    def borrow_book(self, user_id: int, isbn: str) -> bool:
        """User borrows a book. Returns True if successful."""
        pass
    
    def return_book(self, user_id: int, isbn: str) -> bool:
        """User returns a book. Returns True if successful."""
        pass

Then implement one at a time. This shows you’re thinking about the complete interface.


3. Test As You Go

After implementing each key method, write a quick test:

# Implement park_vehicle()
# Immediately test it:
parking_lot = ParkingLot("Test Lot")
parking_lot.add_spot(ParkingSpot(1, SpotSize.MEDIUM))
car = Vehicle("ABC123", VehicleType.CAR)
ticket = parking_lot.park_vehicle(car)
print(f"Ticket: {ticket.ticket_id if ticket else 'Failed'}")

Why this works: Catches bugs immediately. Shows you write testable code. Gives you confidence to move forward.


4. Use Time Checks

At 20 minutes: You should have core classes defined and one method fully implemented.

At 35 minutes: You should have 2-3 key methods working and be ready to discuss trade-offs.

At 40 minutes: Stop adding features. Clean up code, add comments, prepare to explain.

Pro tip: If running behind, tell the interviewer: “I’m going to focus on finishing park_vehicle() completely rather than starting remove_vehicle() partially. Is that okay?” This shows time management awareness.


5. Narrate Your Decisions

As you code, explain your choices:

  • “I’m using a dictionary here for O(1) lookup by ticket ID.”
  • “I’m returning None to indicate failure rather than throwing an exception because…”
  • “I’m storing a reference to the user in the book so we can track who borrowed it.”

Why this works: Interviewers can’t read your mind. Narration shows your thought process and invites feedback.


6. Know When to Stub

It’s okay to say: “The calculate_fee() method would compute pricing based on duration, but for now I’ll stub it out and focus on the parking logic.”

def calculate_fee(self, ticket: Ticket) -> float:
    """Calculate parking fee. Stub for now."""
    return 10.0  # Placeholder

This shows you understand scope management.


7. Prepare for Follow-Up Questions

After implementing core components, interviewers often ask:

  • “How would you handle concurrency?” (Answer: Add locks, use thread-safe data structures)
  • “How would you persist this data?” (Answer: Add a database layer, serialize to JSON)
  • “How would you scale this?” (Answer: Distribute spots across servers, use message queues)

Have high-level answers ready. You don’t need to implement these, but show you’ve thought about them.

Key Takeaways

  • Prioritize ruthlessly: Implement core domain classes and critical operations first. Everything else is secondary.
  • One complete flow beats many incomplete pieces: Get park_vehicle() working end-to-end before starting remove_vehicle().
  • Write real code for key methods: Pseudo-code is acceptable for helpers, but core operations must be actual, working code.
  • Test incrementally: After each method, write a quick test to verify it works. Catch bugs early.
  • Communicate your plan: Tell the interviewer what you’re implementing and why. Adjust based on their feedback.