Bird
Raised Fist0

How to Approach Any LLD Problem in 45 Minutes - Step-by-Step Framework

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
๐ŸŽฏ
How to Approach Any LLD Problem in 45 Minutes - Step-by-Step Framework
40 min ยท medium
medium

Design a reusable Java framework that guides software engineers through a structured 5-level, 4-gate LLD problem-solving process within 45 minutes. The system must support timed steps, enforce progression through gates, and allow extensible step definitions with concurrency-safe state tracking.

  • The framework has exactly 5 levels, each containing multiple steps.
  • Each level has 4 gates that must be passed sequentially before moving to the next level.
  • Each step has a time limit and must track start and end times with thread-safe state updates.
  • The system must allow adding new steps or gates without modifying existing classes (Open-Closed Principle).
  • Concurrency: multiple engineers may use the framework simultaneously; shared resources must be thread-safe.
  • Steps and gates have statuses (PENDING, IN_PROGRESS, COMPLETED) that must be updated atomically.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Core Domain Entities and Their Relationships
Design the main classes representing Levels, Gates, and Steps. Decide how they relate and how to represent their statuses.
๐Ÿ’ก Hint
Use enums for statuses to leverage Java's type safety and exhaustive switch checks. Use composition to model Levels containing Gates and Gates containing Steps.
Use enum Status {PENDING, IN_PROGRESS, COMPLETED} for step/gate status - enums provide compile-time safety and prevent string typos; Levels, Gates, Steps use composition with lifecycle ownership (Steps cannot exist without Gates).
Mid: Names composition relationships clearly. Senior: Explains why enum is preferred over String for statuses due to Java's exhaustive switch and IDE support.
โš ๏ธCommon Wrong Answer
Using String for statuses leads to runtime bugs from typos like 'INPROGRESS' not caught at compile time.
Step 2
Model Step Behavior with Abstract Classes and Interfaces
Decide how to represent Steps with shared state and behavior, and how to allow extensibility for different step types.
๐Ÿ’ก Hint
Abstract class Step with fields like startTime, endTime, and status; interfaces cannot hold instance state in Java, so abstract class is needed for shared fields.
abstract class Step with volatile long startTime, endTime and synchronized methods to update status - abstract class needed because interfaces cannot hold instance state in Java.
Mid: Identifies abstract class for shared state. Senior: Explains why volatile is needed for startTime/endTime to ensure visibility across threads.
โš ๏ธCommon Wrong Answer
Using interface Step with default methods but no fields causes duplication and inconsistent state management.
Step 3
Implement Thread-Safe Status Updates and Timing
Ensure that status transitions and timing updates on Steps and Gates are atomic and visible across threads.
๐Ÿ’ก Hint
Use synchronized methods for atomic check-and-set of status; volatile for timing fields to guarantee visibility; avoid race conditions where two threads set status simultaneously.
public synchronized boolean updateStatus(Status newStatus) to atomically check current status and set newStatus; volatile long startTime/endTime for visibility; prevents race conditions where two threads could set conflicting statuses.
Mid: Names synchronized for atomicity. Senior: Traces thread interleaving where Thread 1 reads PENDING, context switch, Thread 2 reads PENDING, both set IN_PROGRESS causing inconsistent state.
โš ๏ธCommon Wrong Answer
Using non-synchronized setters leads to race conditions and inconsistent status updates visible to other threads.
Step 4
Design Gate and Level Progression Logic Enforcing Sequential Flow
Implement logic to enforce that Gates and Levels progress sequentially only after previous gates/levels are completed.
๐Ÿ’ก Hint
Use synchronized methods in Gate and Level classes to check previous gate/level completion before allowing progression; encapsulate progression logic to follow Single Responsibility Principle.
synchronized boolean proceedToNextGate() checks previous gate status atomically before advancing; prevents concurrent threads from skipping gates; encapsulates progression logic enforcing Single Responsibility Principle.
Mid: Describes synchronized method usage. Senior: Explains how without synchronization, two threads could both advance gate index causing out-of-order progression.
โš ๏ธCommon Wrong Answer
Allowing unsynchronized gate progression causes out-of-order gate completion and breaks framework correctness.
Step 5
Enable Extensibility Without Modifying Existing Classes
Design the system so new step types or gates can be added without changing existing code, adhering to the Open-Closed Principle.
๐Ÿ’ก Hint
Use abstract classes and interfaces for extensibility; factory pattern or dependency injection to create steps; avoid modifying core classes when adding new step implementations.
Use abstract class Step and interface StepExecutor; new step types extend Step and implement StepExecutor; factory pattern with synchronized creation methods to instantiate steps; Open-Closed Principle enforced by avoiding modifications to existing classes.
Mid: Identifies abstract class and interface usage. Senior: Explains how factory pattern with synchronized creation avoids race conditions in step instantiation.
โš ๏ธCommon Wrong Answer
Hardcoding step types in core classes forces modification on every new step addition, violating Open-Closed Principle.
๐Ÿ”Œ
API Design Challenge
Design the API interfaces and classes to support timed steps, sequential gate progression, and extensible step types with thread-safe state management.
  • Define interfaces and abstract classes to separate step behavior and execution logic.
  • Use synchronized methods and volatile fields to ensure thread safety in status and timing updates.
  • Implement factory pattern or dependency injection to create new step types without modifying core classes.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Use of enum for statuses to prevent runtime bugs
  • abstract class Step with volatile fields and synchronized methods
  • Composition relationships with clear lifecycle ownership
  • Synchronized methods for atomic status updates
  • Sequential progression logic with synchronized methods
Good to Have - 30%
  • Factory pattern for extensible step creation
  • Open-Closed Principle adherence via abstract classes and interfaces
  • Volatile usage for timing fields
  • Clear separation of
Bonus - 10%
    โœ…
    Model Answer
    โ–ผ Reveal

    This framework uses Java enums for status management, abstract classes for shared step state, and synchronized methods to ensure thread-safe updates and sequential progression. Composition models the hierarchy of Levels, Gates, and Steps, enforcing lifecycle ownership. Extensibility is achieved via abstract classes, interfaces, and a factory pattern to add new step types without modifying existing code, adhering to the Open-Closed Principle.

    • Use enum Status for compile-time safety and exhaustive switch support
    • Use volatile for startTime and endTime to ensure visibility across threads
    • Use synchronized methods to atomically update status and prevent race conditions
    • Enforce sequential gate and level progression with synchronized methods to avoid out-of-order advancement
    • Implement factory pattern with synchronized creation methods to support extensibility and thread safety
    • Use abstract class Step for shared state since interfaces cannot hold instance fields in Java
    • Model composition with Levels containing Gates and Gates containing Steps to enforce lifecycle ownership
    • Use enum Status for step and gate statuses to leverage Java's compile-time safety and exhaustive switch support.
    • abstract class Step holds shared instance state (startTime, endTime, status) with volatile fields for visibility and synchronized methods for atomic updates.
    • Composition models lifecycle ownership: Levels contain Gates, Gates contain Steps; Steps cannot exist independently.
    • Synchronized methods on status updates prevent race conditions where multiple threads update status concurrently.
    • Volatile keyword on timing fields ensures visibility of start and end times across threads without locking overhead.
    • Gate and Level progression logic encapsulated in synchronized methods to enforce sequential flow and prevent out-of-order advancement.
    • Factory pattern with synchronized creation methods supports thread-safe extensible step instantiation.
    • Open-Closed Principle enforced by abstract classes and interfaces allowing new step types without modifying existing code.
    • Avoid String for types and statuses to prevent runtime bugs from typos; enums provide compile-time guarantees.
    • Use of abstract class over interface for Step because interfaces cannot hold instance state in Java.

    Practice

    (1/5)
    1. In the Library Management System, the ReservationManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct use case?
    easy
    A. Prototype pattern, to clone ReservationManager instances efficiently.
    B. Factory pattern, because it controls object creation centrally.
    C. Builder pattern, to construct ReservationManager with complex parameters.
    D. Singleton pattern, to ensure only one ReservationManager instance manages all reservations.

    Solution

    1. Step 1: Identify the pattern from constructor and method

      The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single instance is created and accessed globally.
    2. Step 2: Why Singleton fits ReservationManager

      ReservationManager must coordinate all reservations centrally to avoid conflicts; multiple instances would cause inconsistent state.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Private constructor + static synchronized getInstance() -> Singleton pattern [check]
    Hint: Private constructor + static getInstance() -> Singleton [check]
    Common Mistakes:
    2. In the Movie Ticket Booking System, the SeatManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is it the correct choice?
    easy
    A. Prototype pattern, to clone seat states efficiently.
    B. Factory pattern, because it controls object creation centrally.
    C. Builder pattern, to construct complex seat objects step-by-step.
    D. Singleton pattern, to ensure only one instance manages seat states globally.

    Solution

    1. Step 1: Identify the pattern from constructor and method signatures

      A private constructor prevents external instantiation, and a static synchronized getInstance() method ensures controlled single instance creation.
    2. Step 2: Reason why Singleton fits seat management

      SeatManager must coordinate seat availability globally to avoid conflicting bookings, so a single shared instance is necessary.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Private constructor + static synchronized getInstance() -> Singleton pattern [check]
    Hint: Private constructor + static getInstance() = Singleton [check]
    Common Mistakes:
    3. In the auction system, should the Bid entity be designed as an abstract class or an interface? Consider that bids have state (amount, bidder) and behavior (validate, notify). Which is the best choice and why?
    easy
    A. Interface, because it allows multiple inheritance and enforces method signatures without state.
    B. Interface, because bids only define behavior and state is stored externally in a database.
    C. Abstract class, because it can hold common bid state and provide default behavior implementations.
    D. Abstract class, because it forces all subclasses to implement all methods explicitly without defaults.

    Solution

    1. Step 1: Analyze state and behavior needs

      Bids have shared state (amount, bidder) and common behavior (validation, notification), which benefit from code reuse and encapsulation.
    2. Step 2: Compare abstract class vs interface

      Abstract classes can hold state and provide default method implementations; interfaces cannot hold state and only define method signatures.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      Stateful entity with shared behavior -> abstract class [check]
    Hint: State + behavior reuse -> abstract class, not interface [check]
    Common Mistakes:
    4. In a UML class diagram, should Vehicle be modeled as an abstract class or an interface if it has state like speed and behavior like accelerate()? Why?
    easy
    A. Interface, because it allows multiple inheritance and defines behavior without state.
    B. Abstract class, because it can hold shared state and provide default behavior implementations.
    C. Interface, because state can be stored externally and behavior defined via default methods.
    D. Abstract class, because interfaces cannot declare methods with parameters.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Vehicle has state (speed) and behavior (accelerate()), so it needs a construct that supports instance variables and method implementations.
    2. Step 2: Evaluate abstract class vs interface

      Abstract classes can hold state and provide default behavior; interfaces cannot hold instance state (only constants) and default methods can't maintain state.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      State + behavior with shared code -> abstract class [check]
    Hint: Stateful base class -> abstract class, not interface [check]
    Common Mistakes:
    5. You need to add support for ElectricCar that requires ChargingSpot compatibility in the current parking system. What is the minimum change to the design to support this without modifying existing classes?
    hard
    A. Modify Vehicle class to add a boolean needsCharging and update parking logic to check this flag.
    B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
    C. Create a new ElectricParkingLot subclass that handles electric cars and charging spots separately.
    D. Add a ChargingSpot field to Vehicle and modify all parking methods to handle it.

    Solution

    1. Step 1: Identify extensibility requirements

      ElectricCar and ChargingSpot are new types requiring compatibility mapping without changing existing classes.
    2. Step 2: Apply minimal invasive change

      Adding new enum values and subclass plus updating compatibility map extends functionality without modifying existing class code, preserving OCP.
    3. Step 3: Avoid violating OCP

      Options B, C, and D modify existing classes or create parallel hierarchies, increasing complexity and violating OCP.
    4. Final Answer:

      Option B -> Option B
    5. Quick Check:

      Extend enums and map, subclass ElectricCar -> minimal change [check]
    Hint: Extend enums and map, subclass new type -> minimal change [check]
    Common Mistakes:
    Recommended

    Ready to prove it?

    Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

    10 questions~5 mineasy hard