Bird
Raised Fist0

Design LinkedIn in OOP - Profile, Connection, Feed, Job, Recommendation

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
๐ŸŽฏ
Design LinkedIn in OOP - Profile, Connection, Feed, Job, Recommendation
40 min ยท hard
hard

Design a LinkedIn-like professional networking system supporting user profiles, connections, personalized feeds, job postings, and recommendation engine with concurrency and extensibility in mind.

  • Profiles have mutable state (experience, skills) and immutable identity (userId).
  • Connections are bidirectional and must be consistent under concurrent requests.
  • Feed aggregates posts from connections and job recommendations personalized per user.
  • Job postings have lifecycle states (OPEN, CLOSED) and require thread-safe updates.
  • Recommendation engine suggests connections and jobs based on profile data and network.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Design Profile and User Identity
Define the Profile class capturing user identity and mutable attributes. How to ensure identity immutability and safe concurrent updates to mutable fields?
๐Ÿ’ก Hint
Use final fields for immutable identity. Use synchronized methods or volatile for mutable fields to ensure visibility and atomicity.
Profile class with final String userId (immutable identity) and synchronized setters for mutable fields like experience; use volatile for fields read without synchronization.
Mid: Uses encapsulation and synchronized setters. Senior: Explains why userId is final (immutable identity) and why volatile or synchronized is needed for mutable fields to prevent stale reads or race conditions.
โš ๏ธCommon Wrong Answer
Using String userId without final allows identity mutation causing inconsistent hashCode/equals behavior leading to bugs in collections.
Step 2
Model Connections with Bidirectional Consistency
Design Connection management ensuring bidirectional consistency under concurrent add/remove connection requests.
๐Ÿ’ก Hint
Use synchronized methods or locks to atomically update both users' connection sets. Consider deadlock prevention by ordering locks.
Use synchronized boolean addConnection(Profile p) that locks both profiles in consistent order (e.g., userId lex order) to atomically update connections sets, preventing race conditions and deadlocks.
Mid: Implements bidirectional add/remove with synchronization. Senior: Explains thread interleaving causing inconsistent connections if locks not ordered, and how ordering locks by userId prevents deadlock.
โš ๏ธCommon Wrong Answer
Synchronizing on each Profile independently without lock ordering causes deadlock when two threads add connections in opposite order.
Step 3
Design Feed Aggregation and Thread Safety
How to design Feed aggregation that merges posts from connections and job recommendations, ensuring thread-safe updates and reads?
๐Ÿ’ก Hint
Use CopyOnWriteArrayList or synchronized blocks for feed posts list. Use volatile reference for feed snapshot to ensure visibility.
Feed class holds volatile List<Post> feedPosts; synchronized methods update feedPosts atomically; volatile ensures readers see latest feed snapshot without locking.
Mid: Uses synchronized add/remove for feedPosts. Senior: Explains how volatile reference prevents stale reads and how CopyOnWriteArrayList trades off write cost for lock-free reads.
โš ๏ธCommon Wrong Answer
Using non-volatile List without synchronization causes readers to see stale or partially updated feed leading to inconsistent UI.
Step 4
Implement Job Posting Lifecycle with Concurrency
Design Job class with lifecycle states (OPEN, CLOSED). How to safely update and read job status concurrently?
๐Ÿ’ก Hint
Use enum JobStatus and volatile JobStatus status field. Use synchronized methods for state transitions to ensure atomicity.
Job class has volatile JobStatus status; synchronized boolean closeJob() atomically checks and updates status from OPEN to CLOSED preventing lost updates.
Mid: Uses enum for status and synchronized methods. Senior: Explains volatile ensures visibility of status changes and synchronized prevents race conditions in state transitions.
โš ๏ธCommon Wrong Answer
Using String for status without synchronization causes race conditions where multiple threads close job simultaneously leading to inconsistent state.
Step 5
Design Recommendation Engine Extensibility
How to design Recommendation engine to allow adding new recommendation strategies without modifying existing code?
๐Ÿ’ก Hint
Use interface RecommendationStrategy with method List<Recommendation> recommend(Profile p). Use composition to inject strategies.
RecommendationStrategy interface defines recommend(Profile p); RecommendationEngine holds List<RecommendationStrategy> and delegates calls, enabling Open-Closed Principle via interface realization.
Mid: Uses interface for strategy pattern. Senior: Explains interface cannot hold state, so stateful strategies use composition; how this design supports adding new strategies without modifying RecommendationEngine.
โš ๏ธCommon Wrong Answer
Hardcoding recommendation logic inside RecommendationEngine violates Open-Closed Principle and requires modifying existing code for new strategies.
๐Ÿ”Œ
API Design Challenge
Design APIs for managing profiles, connections, feeds, jobs, and recommendations that support concurrency, consistency, and extensibility.
  • Use RESTful endpoints with idempotent methods for connection management to handle retries safely.
  • Design feed APIs to support pagination and real-time updates using thread-safe data structures.
  • Implement recommendation APIs that allow plugging in multiple strategies without changing existing endpoints.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Profile identity immutable with final userId
  • Synchronized bidirectional connection updates with lock ordering
  • Volatile and synchronized usage in Feed for thread-safe aggregation
  • Job lifecycle state with enum and volatile status field
  • RecommendationStrategy interface enabling Open-Closed Principle
Good to Have - 30%
  • Use of CopyOnWriteArrayList for feed posts
  • Explanation of deadlock scenarios and prevention
  • Use of synchronized boolean methods for atomic state changes
  • Use of enum for type safety and exhaustive switches
  • Composition over inheritance in recommendation strategies
Bonus - 10%
  • Detailed thread interleaving scenarios for race conditions
  • Use of volatile for visibility without synchronization overhead
  • Discussion of lifecycle ownership in composition vs aggregation
  • Use of final keyword for immutable fields
  • Clear separation of interface realization vs abstract
โœ…
Model Answer
โ–ผ Reveal

This design models LinkedIn's core modules with Java concurrency and OOP best practices. Profiles have immutable userId and thread-safe mutable fields. Connections are managed bidirectionally with lock ordering to prevent deadlocks. Feed aggregation uses volatile references and synchronized updates for thread safety. Job postings use enum status with volatile and synchronized methods for safe lifecycle transitions. The recommendation engine uses the Strategy pattern via interfaces and composition to enable extensibility without modifying existing code.

  • Use final String userId in Profile to ensure immutable identity
  • Synchronize add/remove connection methods locking Profiles in lex order to avoid deadlocks
  • Use volatile reference for feedPosts list to ensure visibility and synchronized methods for atomic updates
  • Define JobStatus as enum and use volatile status field with synchronized methods for state changes
  • Implement RecommendationStrategy interface and inject strategies into RecommendationEngine to follow Open-Closed Principle
  • Profile class uses final userId field for immutable identity; synchronized setters for mutable fields ensure thread safety.
  • Connection management uses synchronized methods locking both Profile objects in lexicographical order of userId to prevent deadlocks and ensure bidirectional consistency.
  • Feed aggregation uses volatile reference to List<Post> for visibility; synchronized methods or CopyOnWriteArrayList for thread-safe updates.
  • Job class uses enum JobStatus with volatile status field; synchronized methods for atomic state transitions prevent race conditions.
  • Recommendation engine uses interface RecommendationStrategy and composition to enable extensibility following Open-Closed Principle.
  • Use of enum types (JobStatus) prevents runtime bugs from string typos and enables exhaustive switch statements.
  • Volatile keyword ensures visibility of shared mutable state across threads without full synchronization overhead.
  • Synchronized methods provide atomicity for compound operations involving multiple fields or objects.
  • Lock ordering strategy prevents deadlocks in concurrent connection updates.
  • Interface realization used for recommendation strategies since interfaces cannot hold instance state in Java.

Practice

(1/5)
1. In a vending machine design, a State interface defines methods like selectProduct(), insertMoney(), and dispense(). Concrete classes like IdleState, HasMoneyState, and SoldState implement this interface. Which design pattern is applied here and why is it the correct choice?
easy
A. Observer pattern, because states notify the vending machine when transitions occur.
B. Strategy pattern, because it allows changing algorithms at runtime for product selection.
C. Decorator pattern, because it adds responsibilities to states dynamically without altering their interface.
D. State pattern, because it encapsulates state-specific behavior and transitions within state classes.

Solution

  1. Step 1: Identify the role of State interface and concrete states

    The State interface defines behavior that varies depending on the vending machine's current state. Concrete classes implement these behaviors and handle transitions.
  2. Step 2: Match pattern intent to scenario

    The State pattern encapsulates state-specific behavior and transitions, allowing the vending machine to change behavior dynamically without complex conditionals.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    State pattern encapsulates state behavior and transitions [check]
Hint: State pattern encapsulates behavior per state [check]
Common Mistakes:
2. In the Elevator System, should the Elevator class implement an interface or extend an abstract class to represent different elevator types (e.g., passenger, freight)? Consider that elevators share common state and behavior but also have type-specific logic.
easy
A. Use an abstract class, because elevators share common state and partial behavior implementations.
B. Use an interface, because elevators only share behavior signatures, not state.
C. Use a concrete class, because inheritance is unnecessary for elevator types.
D. Use multiple interfaces, one per behavior, to avoid state duplication.

Solution

  1. Step 1: Analyze shared state and behavior

    Elevators share common fields like currentFloor, direction, and doorStatus, plus some implemented methods.
  2. Step 2: Abstract class fits shared state and partial behavior

    Abstract class allows code reuse and enforces common state, while subclasses override type-specific logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports shared state and behavior [check]
Hint: Abstract class for shared state; interface for pure behavior [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? Why?
easy
A. Interface, because it enforces method signatures without implementation or state, which is ideal for all vehicles.
B. Abstract class, because it forces all subclasses to implement all methods explicitly.
C. Interface, because Java 8+ allows default methods that can hold state variables safely.
D. Abstract class, because it can hold shared state like licensePlate and provide common behavior implementations.

Solution

  1. Step 1: Identify state holding needs

    licensePlate is shared state, which interfaces cannot hold as fields.
  2. Step 2: Evaluate options

    Abstract classes can hold state and provide default behavior; interfaces cannot hold instance fields, only constants.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Abstract class holds shared state like licensePlate [check]
Hint: State needs abstract class, interfaces only declare behavior [check]
Common Mistakes:
4. To add a new WeekendFeeStrategy pricing rule in the Workflow Engine's fee calculation, which minimal change respects SOLID principles?
medium
A. Modify the existing FeeCalculator class to add weekend logic inside its calculate() method.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy interface and inject it without changing FeeCalculator.
C. Add a boolean flag isWeekend to FeeCalculator and branch logic accordingly.
D. Combine all fee strategies into one large class with if-else for each pricing rule.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires classes to be open for extension but closed for modification.
  2. Step 2: Apply OCP to fee strategy

    Adding a new WeekendFeeStrategy class extends behavior without modifying existing FeeCalculator, respecting OCP and Dependency Inversion Principle.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New strategy class + no FeeCalculator change -> OCP respected [check]
Hint: OCP: extend with new class, don't modify existing [check]
Common Mistakes:
5. ElectricCar requires ChargingSpots in the parking system. What is the minimum change to support this without modifying existing classes, ensuring extensibility and avoiding class explosion?
hard
A. Modify Vehicle class to include a boolean isElectric field and add charging logic inside existing methods.
B. Add charging spot logic inside ParkingLot class and modify parkVehicle() to check for electric cars.
C. Create a new ElectricCarChargingFacade class that extends ParkingLot and handles charging spots separately.
D. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclass ElectricCar extends Vehicle allows new types without changing existing code.
  2. Step 2: Update SpotCompatibility.COMPATIBILITY_MAP to include new compatibility rules for charging spots.

  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    New enums and subclass added, existing classes unchanged -> extensible design [check]
Hint: Add enums and subclass; update compatibility map, no existing class changes [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