Bird
Raised Fist0

Design Stack Overflow in OOP - Question, Answer, Vote, Tag, Reputation, Bounty

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
🏗️
Design Stack Overflow in OOP - Question, Answer, Vote, Tag, Reputation, Bounty
Model Stack Overflow's core entities and interactions with Java OOP principles emphasizing concurrency and extensibility.
mediumSocial and Professional PlatformsFreq: high
Prerequisites:OOP FundamentalsJava Concurrency BasicsDesign Patterns (Factory, Observer, Strategy)
⚙️
Functional Requirements
  • Users can create, edit, and delete Questions and Answers
  • Users can upvote or downvote Questions and Answers with vote count updates
  • Users can add multiple Tags to Questions
  • Users can offer Bounties on Questions to attract better answers
  • Reputation points update atomically and reflect vote changes and bounty awards
  • Only one accepted Answer per Question
  • Votes are idempotent per User per post (Question/Answer)
👤
Use Cases
  • User posts a Question
  • User posts an Answer to a Question
  • User votes (upvote/downvote) on Question or Answer
  • User adds Tags to a Question
  • User offers a Bounty on a Question
  • System updates User Reputation based on votes and accepted answers
🧑‍💻
Actors
  • User
  • Moderator
  • System (for automated reputation and bounty management)
❓
Clarifying Questions to Ask
  • How many concurrent users/votes do we expect? (Concurrency gates and thread count)
  • Is there a pricing or cost model for bounties? How is bounty currency managed?
  • What happens if a User tries to vote multiple times on the same post?
  • Are votes anonymous or visible to others?
  • How to handle vote retractions or changes?
  • Is reputation updated synchronously or asynchronously?
  • What is the lifecycle of a Tag? Can it exist without Questions?
Out of Scope
✗ Full text search and indexing
✗ Comment system
✗ Notification system
✗ User authentication and authorization
✗ UI/UX design
⚡
QPS Calculation
read qps10000
write qps2000
🖥️
Server Estimate
app servers20
db servers5
cache servers3
🔢
Enumerations
enum PostType
QUESTION | ANSWER
Defines the type of post to distinguish behavior and attributes; prevents typo bugs and enables exhaustive switch statements.
enum VoteType
UPVOTE | DOWNVOTE
Encapsulates vote direction explicitly; avoids magic strings and supports type-safe vote handling.
enum ReputationChangeReason
UPVOTE_RECEIVED | DOWNVOTE_RECEIVED | ANSWER_ACCEPTED | BOUNTY_AWARDED
Enumerates reasons for reputation changes to maintain clear, extensible reputation logic.
enum BountyStatus
OPEN | AWARDED | EXPIRED
Tracks bounty lifecycle states to enforce business rules and prevent invalid operations.
📦
User
4 fields
private final long userIdprivate String usernameprivate volatile int reputationprivate final Map<Long, Vote> votesCast
Represents a platform user, manages reputation and votes cast, enforces voting rules per user.
public synchronized void incrementReputation(int points, ReputationChangeReason reason)Atomically increments reputation points with reason tracking.
public synchronized boolean castVote(Post post, VoteType voteType)Casts a vote on a post if not already voted; ensures idempotency.
public synchronized boolean hasVotedOnPost(long postId)Checks if user has already voted on the given post.
📦
Post
6 fields
protected final long postIdprotected final long authorUserIdprotected String contentprotected final PostType postTypeprotected volatile int voteCountprotected final Map<Long, Vote> votes
Abstract base for Question and Answer, manages content, votes, and vote counts with concurrency safety.
public synchronized boolean addVote(Vote vote)Adds a vote if not already present; updates voteCount atomically.
public synchronized boolean removeVote(long userId)Removes a user's vote and updates voteCount atomically.
public int getVoteCount()Returns current vote count with volatile visibility guarantees.
📦
Question
4 fields
private final List<Answer> answersprivate final Set<Tag> tagsprivate volatile Long acceptedAnswerIdprivate Bounty bounty
Extends Post to represent questions, manages answers, tags, accepted answer, and bounty.
public synchronized void addAnswer(Answer answer)Adds an answer to the question atomically.
public synchronized boolean acceptAnswer(long answerId)Marks an answer as accepted; only one accepted answer allowed.
public synchronized void addTag(Tag tag)Adds a tag to the question.
public synchronized void setBounty(Bounty bounty)Associates a bounty with the question.
📦
Answer
1 fields
private final long questionId
Extends Post to represent answers linked to a question.
public long getQuestionId()Returns the associated question's ID.
📦
Vote
3 fields
private final long userIdprivate final VoteType voteTypeprivate final long postId
Represents a vote cast by a user on a post.
public VoteType getVoteType()Returns the type of vote (UPVOTE or DOWNVOTE).
📦
Tag
1 fields
private final String name
Represents a tag label; can exist independently and be associated with multiple questions.
public String getName()Returns the tag name.
📦
Bounty
5 fields
private final long bountyIdprivate final long questionIdprivate final int amountprivate volatile BountyStatus statusprivate volatile Long awardedToUserId
Manages bounty lifecycle, amount, and award status for a question.
public synchronized boolean awardBounty(long userId)Awards bounty to a user if open; updates status atomically.
public synchronized void expireBounty()Marks bounty as expired.
🔗
Relationships
🗄️
Users
PK: userId
userId BIGINT PRIMARY KEYusername VARCHARreputation INT
🗄️
Posts
PK: postId
postId BIGINT PRIMARY KEYauthorUserId BIGINTcontent TEXTpostType VARCHARvoteCount INT
🔌
POST
/posts
Request
{
  "authorUserId": "long",
  "content": "string",
  "postType": "QUESTION or ANSWER",
  "questionId": "long (if postType is ANSWER)"
}
Response
{
  "postId": "long",
  "status": "success or failure"
}
Creates a new question or answer.
🔌
POST
/posts/{postId}/vote
Request
{
  "userId": "long",
  "voteType": "UPVOTE or DOWNVOTE"
}
Response
{
  "voteCount": "int",
  "status": "success or failure"
}
Casts a vote on a post; idempotent per user.
🔌
POST
/questions/{questionId}/bounty
Request
{
  "userId": "long",
  "amount": "int"
}
Response
{
  "bountyId": "long",
  "status": "OPEN or failure"
}
Offers a bounty on a question.

Practice

(1/5)
1. The Meeting Scheduler currently calculates fees using a FeeCalculator class. To add a new WeekendFeeStrategy without modifying existing code, which SOLID principle applies and what is the minimum change required?
medium
A. Dependency Inversion Principle: inject WeekendFeeStrategy into FeeCalculator by modifying its constructor.
B. Open/Closed Principle: create a new WeekendFeeStrategy class implementing FeeStrategy interface; FeeCalculator uses it polymorphically.
C. Single Responsibility Principle: modify FeeCalculator to handle weekend fees directly.
D. Liskov Substitution Principle: subclass FeeCalculator and override fee calculation for weekends.

Solution

  1. Step 1: Identify SOLID principle for extensibility

    Open/Closed Principle (OCP) requires adding new behavior without modifying existing classes.
  2. Step 2: Apply Dependency Inversion Principle (DIP)

    Injecting the new WeekendFeeStrategy via constructor or setter allows FeeCalculator to depend on abstractions, enabling extension without modification.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Inject new strategy -> respects OCP and DIP [check]
Hint: Inject new strategy -> OCP + DIP respected [check]
Common Mistakes:
2. In the in-memory file system, the createFile() method checks if a filename is available and then adds the file to the directory without synchronization. Which exact thread interleaving causes two threads to create files with the same name (double creation)?
medium
A. Thread 1 checks filename availability -> true, context switch; Thread 2 checks availability -> true; both add file with same name.
B. Thread 1 and Thread 2 both call createFile() simultaneously and both fail due to race condition.
C. Thread 1 adds file, then Thread 2 checks availability and finds it unavailable, so no conflict occurs.
D. Thread 1 deletes a file while Thread 2 creates a file with the same name, causing inconsistency.

Solution

  1. Step 1: Trace the check-then-act sequence without synchronization

    Thread 1 calls isNameAvailable() -> true, but before adding the file, context switches to Thread 2.
  2. Step 2: Thread 2 also calls isNameAvailable() -> true and proceeds to add the file, then Thread 1 resumes and adds its file too.

    This causes double creation due to the race condition on the availability check and add operation.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act gap without sync -> double creation [check]
Hint: Check availability -> context switch -> both add same file [check]
Common Mistakes:
3. You want to add a WeekendFeeStrategy to calculate parking fees differently on weekends using the current Iterator-based design. Which minimal change respects the Open-Closed Principle (OCP)?
medium
A. Add a boolean flag isWeekend to the FeeStrategy interface and implement conditional logic in all subclasses.
B. Modify the existing FeeStrategy class to add weekend logic with an if-else condition.
C. Create a new WeekendFeeStrategy class implementing FeeStrategy and update the client code to use it when appropriate.
D. Combine all fee strategies into a single class with multiple methods and switch logic inside the iterator.

Solution

  1. Step 1: Understand OCP requirements

    OCP requires software entities to be open for extension but closed for modification.
  2. Step 2: Evaluate options

    Modify the existing FeeStrategy class to add weekend logic with an if-else condition. modifies existing class, violating OCP. Create a new WeekendFeeStrategy class implementing FeeStrategy and update the client code to use it when appropriate. adds a new class but requires client code modification, which may violate DIP. Add a boolean flag isWeekend to the FeeStrategy interface and implement conditional logic in all subclasses. extends interface with a flag, allowing existing implementations to adapt without changing their core logic. Combine all fee strategies into a single class with multiple methods and switch logic inside the iterator. centralizes logic, violating SRP and OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Extending interface with flag allows extension without modifying existing classes [check]
Hint: OCP: extend behavior without modifying existing classes [check]
Common Mistakes:
4. The system needs to support ElectricCar and ChargingSpot without modifying existing classes. What is the minimum change to the current Java design to add these features while preserving extensibility?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
B. Modify Vehicle class to include a boolean isElectric field and add charging logic inside existing ParkingSpot class.
C. Create a new ElectricCarChargingManager class that extends BookingManager and handles charging spots separately.
D. Add a new interface Chargeable and modify all Vehicle subclasses to implement it, including ElectricCar.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enums or modifying compatibility maps changes existing classes, violating OCP.
  2. Step 2: Use composition by adding an isElectric field and charging logic in ParkingSpot to handle charging without class explosion.

    This approach extends functionality with minimal changes and avoids class explosion or god classes.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Use fields and composition, avoid modifying enums or compatibility maps [check]
Hint: Add fields and logic, avoid modifying enums or compatibility maps [check]
Common Mistakes:
5. To add ElectricCar needing ChargingSpot without modifying existing classes, what is the minimum change to the current design using enums VehicleType and SpotType and a compatibility map?
hard
A. Modify Vehicle base class to include charging capability and add logic in existing spot classes
B. Create a new ElectricVehicleFactory that overrides existing factory methods and modifies compatibility map
C. Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar subclass, and update compatibility map; no existing classes modified
D. Add ElectricCar as a flag inside Vehicle and modify parkVehicle() to check for charging spots

Solution

  1. Step 1: Understand current enum and compatibility map design

    VehicleType and SpotType enums define types; compatibility map links them. Adding new types requires updating enums and map.
  2. Step 2: Analyze minimal change without modifying existing classes

    Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar subclass, and update compatibility map; no existing classes modified adds new enum values and classes without modifying existing classes, respecting OCP. Modify Vehicle base class to include charging capability and add logic in existing spot classes modifies base Vehicle class, violating OCP but minimal code change.
  3. Step 3: Choose minimal change that avoids modifying existing classes

    Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar subclass, and update compatibility map; no existing classes modified is minimal and respects OCP; Modify Vehicle base class to include charging capability and add logic in existing spot classes modifies existing classes, violating requirement.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    New enums + subclass + compatibility map update -> minimal change without existing class modification [check]
Hint: Add enums + subclass + map update; no existing class edits [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