Bird
Raised Fist0

Requirements Gathering for LLD - What Questions to Ask the Interviewer

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
🏗️
Requirements Gathering for LLD - What Questions to Ask the Interviewer
Structured 40-minute LLD interview walkthrough focusing on requirements gathering, entities, relationships, concurrency, and code design in Java.
mediumOOP Foundations for InterviewsFreq: high
Prerequisites:OOP Fundamentals
⚙️
Functional Requirements
  • System must support multiple concurrent users interacting with shared resources
  • System must handle pricing strategies with configurable rules
  • System must validate input data and handle edge cases gracefully
  • System must provide clear error messages for invalid operations
  • System must allow extensibility for future features without modifying existing code
  • System must ensure thread-safe operations on shared mutable state
  • System must log all critical operations for audit purposes
👤
Use Cases
  • Candidate asks clarifying questions about system requirements
  • Interviewer provides detailed functional and non-functional requirements
  • Candidate identifies concurrency and edge case scenarios
  • Candidate confirms out-of-scope features
  • Candidate documents requirements for design
🧑‍💻
Actors
  • Interviewer
  • Candidate
  • System User
  • System Administrator
❓
Clarifying Questions to Ask
  • How many concurrent threads or users will interact with the system?
  • Are there any specific concurrency constraints or expected contention points?
  • What pricing strategies should the system support (fixed, dynamic, tiered)?
  • How should the system behave under edge cases such as invalid input or resource exhaustion?
  • Are there any features explicitly out of scope for this design?
  • What are the expected performance and latency requirements?
  • Should the system support rollback or compensation in case of failures?
Out of Scope
✗ UI/UX design details
✗ Database schema design
✗ Third-party integrations
✗ Deployment and scaling strategies
🔢
Enumerations
enum UserRole
ADMIN | USER | GUEST
Defines user roles to prevent typo bugs and enable exhaustive switch-case handling for authorization logic.
enum RequestStatus
PENDING | APPROVED | REJECTED | CANCELLED
Represents lifecycle states of a request, enabling clear state transitions and preventing invalid states.
enum PricingStrategy
FIXED | DYNAMIC | TIERED
Encapsulates pricing types to enforce strategy pattern implementation and avoid string-based errors.
📦
User
4 fields
private final String userIdprivate volatile UserRole roleprivate String nameprivate String email
Represents a system user with identity and role; manages user-specific data and permissions.
public String getUserId()Returns the unique identifier of the user.
public UserRole getRole()Returns the current role of the user.
public synchronized void setRole(UserRole role)Atomically updates the user's role to ensure visibility across threads.
📦
Request
4 fields
private final String requestIdprivate volatile RequestStatus statusprivate final User requesterprivate final long timestamp
Models a user request with immutable identity and mutable status; tracks requester and creation time.
public RequestStatus getStatus()Returns the current status of the request.
public synchronized boolean updateStatus(RequestStatus newStatus)Atomically updates the request status ensuring valid state transitions.
📦
PricingPolicy
2 fields
private final PricingStrategy strategyprivate Map<String, Double> parameters
Encapsulates pricing rules and parameters based on strategy; calculates price accordingly.
public double calculatePrice(Request request)Computes price for a given request based on the pricing strategy and parameters.
public synchronized void updateParameters(Map<String, Double> newParams)Atomically updates pricing parameters to ensure thread-safe configuration changes.
📦
AuditLog
1 fields
private final List<String> logs
Records system events and operations for audit and debugging purposes.
public synchronized void logEvent(String event)Appends a new event to the audit log ensuring thread-safe writes.
public synchronized List<String> getLogs()Returns a copy of the current logs to prevent concurrent modification.
📦
SystemConfig
2 fields
private volatile int maxConcurrentUsersprivate volatile boolean enableLogging
Holds global configuration parameters with thread-safe visibility guarantees.
public int getMaxConcurrentUsers()Returns the maximum allowed concurrent users.
public synchronized void setMaxConcurrentUsers(int maxUsers)Atomically updates the maximum concurrent users setting.
public boolean isLoggingEnabled()Returns whether logging is enabled.
public synchronized void setLoggingEnabled(boolean enabled)Atomically updates the logging enabled flag.
🔗
Relationships
Request──►User[many-to-one]
associationRequest depends on User but User can exist independently
PricingPolicy◇──►PricingStrategy[one-to-one]
aggregationPricingStrategy can exist independently of PricingPolicy
AuditLog◆──►String[one-to-many]
compositionAuditLog owns log entries; entries do not exist independently
SystemConfig──►User[one-to-many]
associationSystemConfig references Users for configuration but does not own them

Practice

(1/5)
1. In designing the Job Scheduler, should the RetryPolicy be an abstract class or an interface, and why?
easy
A. Interface, because RetryPolicy requires multiple inheritance of behavior.
B. Interface, because RetryPolicy defines behavior only and implementations may vary widely without shared state.
C. Abstract class, because interfaces cannot have method implementations in Java.
D. Abstract class, because RetryPolicy needs to hold state like retry count and share code.

Solution

  1. Step 1: Analyze RetryPolicy requirements

    RetryPolicy typically holds state such as retry count, max retries, and backoff strategy, which benefits from shared code and fields.
  2. Step 2: Abstract class vs interface in Java

    Abstract classes can hold state and provide default implementations, while interfaces (pre-Java 8) cannot hold state. Since RetryPolicy needs state, abstract class fits better.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    RetryPolicy holds state -> abstract class [check]
Hint: Stateful behavior -> abstract class; stateless -> interface [check]
Common Mistakes:
2. In an in-memory SQL database design, a Table class has a private constructor and a static synchronized getInstance() method returning the single instance. Which pattern is applied here and why is this the correct use case?
easy
A. Prototype pattern, because it clones an existing Table instance for reuse.
B. Factory Method pattern, because it controls object creation with a static method.
C. Builder pattern, because it incrementally constructs the Table instance.
D. Singleton pattern, because it ensures only one instance of Table exists in memory.

Solution

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

    A private constructor prevents external instantiation, and a static synchronized getInstance() method ensures controlled access to a single instance.
  2. Step 2: Match pattern intent to scenario

    The Singleton pattern guarantees a single instance per JVM, suitable for a Table class representing a unique in-memory table. Factory Method and Builder focus on object creation but don't enforce single instance. Prototype clones objects, which is unrelated here.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + static synchronized getInstance() -> Singleton [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
3. In designing a Vehicle abstraction for a parking system, should Vehicle be an abstract class or an interface if it needs to hold state like licensePlate and provide default behavior for getSize()? Why?
easy
A. Abstract class, because it can hold shared state and provide default method implementations.
B. Interface, because it allows multiple inheritance and enforces method contracts without state.
C. Interface, because Java 8+ interfaces can have default methods and fields for state.
D. Abstract class, because it forces all subclasses to implement all methods explicitly.

Solution

  1. Step 1: Analyze state and behavior requirements

    Vehicle needs to hold state (licensePlate) and provide default behavior (getSize), which interfaces cannot hold as fields.
  2. Step 2: Choose abstraction supporting state and default behavior

    Abstract classes support instance variables and method implementations; interfaces cannot hold instance state.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports state and default behavior -> correct choice [check]
Hint: State needs abstract class; interfaces can't hold instance fields [check]
Common Mistakes:
4. You want to add a WeekendFeeStrategy to the traffic light system's parking fee calculation. According to SOLID principles, what is the minimum change required?
medium
A. Add a boolean flag isWeekend in FeeCalculator and use conditional logic
B. Modify the existing FeeCalculator class to add weekend logic
C. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes
D. Create a subclass WeekendFeeCalculator extending FeeCalculator and override methods

Solution

  1. Step 1: Identify applicable SOLID principle

    Open-Closed Principle (OCP) requires classes to be open for extension but closed for modification.
  2. Step 2: Evaluate options for OCP compliance

    Adding a flag with conditional logic violates OCP by modifying existing class; creating a new strategy class and injecting it respects OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class + injection -> OCP compliant extension [check]
Hint: OCP: extend with new class, avoid modifying existing [check]
Common Mistakes:
5. To add a WeekendFeeStrategy for locker usage fees in the current Amazon Locker design, which minimal change respects SOLID principles?
medium
A. Modify the existing FeeCalculator class to add weekend fee logic inside the calculateFee() method.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes.
C. Add weekend fee logic directly inside the Locker class to calculate fees based on current day.
D. Add a boolean isWeekend flag to Package and modify LockerManager to apply extra fees conditionally.

Solution

  1. Step 1: Identify the SOLID principle involved

    Open-Closed Principle (OCP) requires adding new behavior without modifying existing code.
  2. Step 2: Evaluate options for minimal change respecting OCP

    Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes. suggests adding a new strategy class, but injecting it requires modifying existing FeeCalculator or client code, violating minimal change. Add a boolean isWeekend flag to Package and modify LockerManager to apply extra fees conditionally. adds a flag and conditional logic, which is a minimal change localized to Package and LockerManager, preserving OCP better than modifying FeeCalculator or Locker.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Minimal change with conditional flag -> respects OCP [check]
Hint: OCP: add new behavior without modifying existing classes [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