Bird
Raised Fist0

Design a Social Media Profile System - User, Follow, Post, Like, Feed OOP

LLDhardInterview freq: high
Choose your preparation mode4 modes available
๐ŸŽฏ
Design a Social Media Profile System
40 min ยท medium
medium

Design a social media profile system where users can follow each other, create posts, like posts, and view a feed of posts from followed users.

  • Users can follow/unfollow other users.
  • Users can create posts with text content and timestamps.
  • Users can like posts; each like is unique per user-post pair.
  • Feed shows posts from followed users sorted by timestamp descending.
  • Concurrency: multiple users can follow/unfollow, post, and like concurrently.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Design User and Follow Relationship
Define the User class and model the follow/unfollow relationship between users.
๐Ÿ’ก Hint
Use a thread-safe Set to store followers and followings. Consider lifecycle ownership of User objects.
User class holds instance state followers and followings as ConcurrentHashMap.newKeySet() to ensure thread-safe concurrent modifications; composition relationship with Follow is avoided since Follow is implicit in User's sets.
Mid: Uses Set<User> for followers/followings. Senior: Explains why ConcurrentHashMap.newKeySet() is used over HashSet to avoid ConcurrentModificationException and race conditions during concurrent follow/unfollow.
โš ๏ธCommon Wrong Answer
Using HashSet for followers without synchronization leads to ConcurrentModificationException or lost updates when multiple threads modify followers concurrently.
Step 2
Design Post Entity and Creation
Design the Post class and how users create posts.
๐Ÿ’ก Hint
Post needs immutable fields for content and timestamp; use final fields. Posts belong to a User (aggregation).
Post class has final fields for content and timestamp to ensure immutability; User aggregates Posts but Posts can exist independently for feed retrieval.
Mid: Defines Post with content and timestamp. Senior: Explains why immutability via final fields prevents visibility issues without synchronization and supports safe publication.
โš ๏ธCommon Wrong Answer
Mutable Post fields without synchronization cause visibility issues where other threads see stale or partially constructed Post objects.
Step 3
Implement Like Functionality with Concurrency
Design how users like posts ensuring each user can like a post only once, handling concurrent likes.
๐Ÿ’ก Hint
Use ConcurrentHashMap or ConcurrentHashSet to store likes per post; atomic check-and-set needed to prevent duplicate likes.
Post class uses ConcurrentHashMap<User, Boolean> as a concurrent set of likers; likePost(User u) is synchronized or uses putIfAbsent to atomically check-and-set like existence.
Mid: Uses a Set to store likers. Senior: Explains how putIfAbsent prevents race conditions where two threads simultaneously like the same post causing duplicate likes.
โš ๏ธCommon Wrong Answer
Using a non-thread-safe Set for likes causes race conditions where multiple likes from the same user can be recorded concurrently.
Step 4
Design Feed Generation
Design how to generate a user's feed showing posts from followed users sorted by timestamp descending.
๐Ÿ’ก Hint
Feed generation should be efficient; consider snapshot consistency and thread-safe iteration over followed users' posts.
FeedService uses snapshot copies of followed users' posts using synchronized or concurrent collections; posts are merged and sorted by timestamp using PriorityQueue; volatile or final used for references to ensure visibility.
Mid: Merges posts from followed users. Senior: Explains how snapshotting followed users' posts avoids ConcurrentModificationException and ensures consistent feed view despite concurrent post additions.
โš ๏ธCommon Wrong Answer
Iterating directly over mutable posts collections without synchronization causes ConcurrentModificationException or inconsistent feed data.
Step 5
Ensure Thread-Safe Follow/Unfollow Operations
Implement follow and unfollow methods ensuring atomicity and visibility in concurrent environment.
๐Ÿ’ก Hint
Use synchronized methods or atomic operations on followers/followings sets; consider deadlock avoidance.
User.follow(User other) and unfollow(User other) are synchronized methods to atomically update both users' followers and followings sets; avoids partial updates violating consistency.
Mid: Uses synchronized methods for follow/unfollow. Senior: Explains how synchronized ensures atomic check-and-set preventing inconsistent follower/following states and how deadlock is avoided by ordering locks or using concurrent sets.
โš ๏ธCommon Wrong Answer
Updating followers and followings sets separately without synchronization leads to inconsistent state where one user follows another but not vice versa.
๐Ÿ”Œ
API Design Challenge
Design APIs for user follow/unfollow, post creation, liking posts, and feed retrieval ensuring thread safety and consistency.
  • Use RESTful endpoints with appropriate HTTP methods (POST for follow, unfollow, create post, like; GET for feed).
  • Consider idempotency and concurrency control in API design to prevent inconsistent states.
  • Use pagination and filtering parameters in feed retrieval API to handle large data efficiently.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • User followers and followings stored in thread-safe concurrent sets (ConcurrentHashMap.newKeySet())
  • Post class immutable with final fields for safe publication
  • Atomic like operation using ConcurrentHashMap.putIfAbsent to prevent duplicate likes
  • Synchronized follow/unfollow methods to maintain follower-following consistency
  • Feed generation uses snapshot copies to avoid concurrent modification exceptions
Good to Have - 30%
  • Use of volatile or final for collection references to ensure visibility
  • Separation of concerns following Single Responsibility Principle
  • Use of enums for fixed types to improve type safety
  • Avoidance of composition for Follow to respect lifecycle independence
  • Efficient feed merging using PriorityQueue or similar data structure
Bonus - 10%
  • Explanation of deadlock avoidance strategies in follow/unfollow synchronization
  • Use of immutable Post objects to enable safe caching or sharing
  • Design extensibility for future features like comments or reactions
  • Use of Java 8+ Stream API for feed generation
  • Consideration of memory consistency effects of final and volatile keywords
Using HashSet for followers/followings without synchronization leads to ConcurrentModificationException and lost updates when multiple threads modify the sets concurrently.
Mutable Post fields without synchronization cause visibility issues where other threads may see stale or partially constructed Post objects, leading to inconsistent behavior.
Using a non-thread-safe Set for likes causes race conditions where multiple likes from the same user can be recorded concurrently, violating uniqueness constraints.
Iterating directly over mutable posts collections without synchronization causes ConcurrentModificationException or inconsistent feed data due to concurrent modifications.
Updating followers and followings sets separately without synchronization leads to inconsistent state where one user follows another but not vice versa, breaking data consistency.
โœ…
Model Answer
โ–ผ Reveal

    • User class uses ConcurrentHashMap.newKeySet() for followers and followings to allow concurrent modifications without explicit synchronization.
    • Post class is immutable with final fields for content and timestamp to ensure safe publication across threads.
    • Likes stored in Post as ConcurrentHashMap<User, Boolean> to atomically check-and-set likes using putIfAbsent preventing duplicate likes.
    • Feed generation uses snapshot copies of followed users' posts to avoid ConcurrentModificationException and ensure consistent feed views.
    • Follow and unfollow methods are synchronized to atomically update both users' followers and followings sets, maintaining consistency.
    • Avoid composition for Follow entity; follow relationship is modeled as association via sets in User to respect lifecycle independence.
    • Use volatile or final references for collections to guarantee visibility of updates across threads.
    • Avoid mutable shared state without synchronization to prevent visibility and race condition bugs.
    • Use enums for PostType or UserStatus if extended to avoid string-based errors and improve type safety.
    • Design respects Single Responsibility Principle by separating User, Post, Like, and Feed concerns into distinct classes.

    Practice

    (1/5)
    1. In designing the Player abstraction for the Tic-Tac-Toe game, should Player be an abstract class or an interface, and why?
    easy
    A. Abstract class, because Java interfaces cannot have default methods for shared logic.
    B. Interface, because players only define behavior like making moves, allowing multiple inheritance of behavior.
    C. Abstract class, because players share common state like name and score that should be inherited.
    D. Interface, because it allows storing player state directly in the interface.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Players have common state (e.g., name, symbol, score) and some shared behavior (e.g., basic validation). Abstract classes allow state fields and shared method implementations.
    2. Step 2: Why abstract class is better than interface here

      Interfaces define behavior contracts but cannot hold instance state. Although Java 8+ interfaces support default methods, they cannot hold mutable state. Thus, abstract class suits better for shared state and behavior.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      Shared state + behavior -> abstract class, not interface [check]
    Hint: State needs abstract class; behavior-only fits interface [check]
    Common Mistakes:
    2. In the Food Ordering System, the KitchenQueue class has a parkOrder() method that checks if a slot is available before assigning an order. Without synchronization on parkOrder(), which exact thread interleaving causes double-booking of the same slot?
    medium
    A. Thread 1 and Thread 2 both call parkOrder() simultaneously and the JVM throws an exception.
    B. Thread 1 checks slot availability -> true, context switch before assignment; Thread 2 checks availability -> true, both assign same slot.
    C. Thread 1 assigns slot, then Thread 2 waits for Thread 1 to finish before assigning next slot.
    D. Thread 1 and Thread 2 both wait on a lock, causing deadlock and no assignment.

    Solution

    1. Step 1: Identify the check-then-act race condition

      Without synchronization, Thread 1 reads slot as available but is preempted before assignment; Thread 2 also reads available and proceeds.
    2. Step 2: Both threads assign the same slot leading to double-booking

      Because the availability check and assignment are not atomic, both threads assign the same slot concurrently.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      Check-then-act gap without sync -> double assignment [check]
    Hint: Check availability -> context switch -> both assign same slot [check]
    Common Mistakes:
    3. In the Elevator System, the assignElevatorToFloorRequest() method checks if an elevator is available before assigning it. Without synchronizing this method, what exact sequence of thread interleaving can cause two threads to assign the same elevator simultaneously?
    medium
    A. Thread 1 assigns elevator, then Thread 2 assigns a different elevator without conflict.
    B. Thread 1 and Thread 2 both call assignElevatorToFloorRequest() but one waits until the other finishes.
    C. Thread 1 checks elevator availability -> true, context switch; Thread 2 checks availability -> true; both assign the same elevator concurrently.
    D. Thread 1 and Thread 2 both fail to find an available elevator and return null.

    Solution

    1. Step 1: Identify check-then-act race condition

      Without synchronization, Thread 1 reads elevator as available, then context switches before assignment.
    2. Step 2: Thread 2 also reads elevator as available and proceeds to assign it, causing double-booking.

      Both threads assign the same elevator because the availability check and assignment are not atomic.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      Unsynchronized check-then-act causes double assignment [check]
    Hint: Check-then-act without sync allows double assignment race [check]
    Common Mistakes:
    4. The system must support ElectricCar vehicles needing ChargingSpot parking. What is the minimum change to the current design to support this without modifying existing classes?
    hard
    A. Add a boolean isElectric flag to Vehicle and ParkingSpot classes and update all compatibility checks.
    B. Modify existing Vehicle and ParkingSpot classes to add electric-specific fields and logic.
    C. Create a new ElectricVehicleManager class that handles electric cars separately, duplicating some logic.
    D. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.

    Solution

    1. Step 1: Identify extensibility without modifying existing classes

      Adding new enum values and subclassing allows extension without changing existing class code, respecting OCP.
    2. Step 2: Update compatibility externally

      Updating SpotCompatibility map outside existing classes avoids modifying their code, enabling new vehicle-spot matching.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Extend enums + subclass + external map update -> no existing class changes [check]
    Hint: Extend enums + subclass + external map -> no existing class changes [check]
    Common Mistakes:
    5. To support ElectricCar orders requiring ChargingSpots in the existing Order Management System, what is the minimum change that respects extensibility without modifying existing classes?
    hard
    A. Modify VehicleType enum to include ElectricCar and add charging logic inside existing Vehicle class.
    B. Create a new ElectricCar class and modify Order class to handle charging spots explicitly.
    C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
    D. Add charging spot logic inside existing Spot class and modify OrderState to handle ElectricCar states.

    Solution

    1. Step 1: Identify extensibility requirements

      New vehicle and spot types must be added without modifying existing classes to respect OCP.
    2. Step 2: Evaluate options

      Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally. adds new enum values and classes externally, updating compatibility map without changing existing code; Options B, C, D modify existing classes violating OCP.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      Adding new enums and classes externally respects OCP [check]
    Hint: Add new enums and classes externally, 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