Design Stack Overflow
OOP design for a Q&A platform covering question and answer posting, voting system, reputation tracking, tag-based search, comment threads, and answer acceptance with privilege escalation.
The Problem
Your developer community platform handles 20,000 questions per day across 500 technology tags. The current system stores everything in a single posts table with a type column, and recalculates user reputation from scratch on every page load. At peak hours, loading a user's profile takes 12 seconds because the query scans every vote ever cast. Last month, a bug in the voting logic allowed the same user to upvote a question 47 times, catapulting a spam post to the front page before anyone noticed.
Q&A platforms are deceptively complex because they blend content management with a game-like reputation economy. Votes must be idempotent (one per user per post), reputation changes cascade through multiple actions (upvotes, accepted answers, bounties), and privilege levels gate which features a user can access. A system that gets voting wrong undermines trust. A system that gets reputation wrong either locks out legitimate users or hands moderation power to spammers.
Design the core classes for a Stack Overflow-style Q&A platform that handles question and answer posting, a voting system with reputation tracking, tag-based search, comment threads, answer acceptance, and privilege escalation based on cumulative reputation.
Requirements
Clarifying Questions
Before jumping into class design, ask questions to nail down the scope. Cover four areas: core actions, error handling, boundaries, and future extensions.
You: "What are the main actions a user can take? Post questions, post answers, vote, comment, and accept answers?"
Interviewer: "Yes. Users post questions with a title, body, and tags. Other users post answers. Both questions and answers can receive upvotes and downvotes. The question author can mark one answer as accepted. Users can also comment on both questions and answers."
Five core actions: post question, post answer, vote, comment, accept answer. Each action has different permission requirements and reputation effects. That immediately tells us we need a User entity that tracks reputation and a privilege system that gates actions.
You: "How does the reputation system work? What are the exact point values?"
Interviewer: "When your question gets upvoted you earn +10. When your answer gets upvoted you earn +15. Getting downvoted costs you -2. When your answer is accepted you earn +15, and the question author who accepts it earns +2. Casting a downvote costs the voter -1."
Six distinct reputation events, each with a different point value. We need a way to track these events and derive the total reputation. The asymmetry between question upvotes (+10) and answer upvotes (+15) is intentional: answers are more valuable.
You: "What privileges do reputation thresholds unlock?"
Interviewer: "At 15 reputation you can upvote. At 50 you can comment. At 125 you can downvote. At 2000 you can edit other people's posts. At 3000 you can cast close votes. New users start at 1 reputation."
Privilege escalation based on thresholds. The system must check reputation before allowing an action. This is a natural fit for a privilege registry: a mapping from action to required reputation.
You: "Can a user change their vote? What about voting on their own posts?"
Interviewer: "Users cannot vote on their own posts. A user can change their vote (switch from upvote to downvote or vice versa) or retract it entirely. Each user gets exactly one vote per post."
Vote idempotency is critical. We need to track who voted on what, and handle three operations: cast, change, and retract. Storing votes as a map from user ID to vote type makes lookups O(1).
You: "How does search work? Can users search by tags, title, or content?"
Interviewer: "Users can search by title keywords and filter by tags. Full-text content search can be a follow-up. Tags are a fixed set that moderators manage. Each question must have at least one tag, maximum five."
Tag-based filtering plus keyword search. The search ranking strategy could vary: relevance, votes, recency. That difference in ranking suggests a Strategy pattern.
You: "Should we support marking questions as duplicates?"
Interviewer: "Yes. A user with sufficient reputation can link a question to an existing one as a duplicate and close it. The closed question redirects viewers to the original."
Duplicate detection adds a relationship between questions. A closed question holds a reference to its duplicate target. We can model this as a nullable field on Question.
You: "What about bounties, edit history, and moderation queues?"
Interviewer: "Those are extensions. For the core design, focus on posting, voting, reputation, tags, comments, answers, and duplicate closure. We can discuss bounties and edit history as follow-ups."
Good. You have ruled out bounties, edit history, and moderation queues from the core scope. This keeps the initial design focused.
Final Requirements
Functional Requirements:
- Users post questions with a title, body, and 1-5 tags
- Users post answers to questions
- Users upvote or downvote questions and answers (one vote per user per post, changeable)
- Reputation updates: question upvote +10, answer upvote +15, downvote received -2, answer accepted +15 to answerer and +2 to asker, downvote cast -1 to voter
- Privilege escalation: upvote at 15, comment at 50, downvote at 125, edit at 2000, close at 3000
- Question author accepts one answer per question
- Users comment on questions and answers
- Search by title keywords with tag filtering, configurable ranking strategy
- Close questions as duplicates (links to original)
Non-Functional Requirements:
- Thread safety for concurrent voting on the same post
- Extensibility for new reputation events (bounties, suggested edits)
- O(1) vote lookup per user per post
Out of Scope:
- UI rendering and markdown parsing
- Persistence and database layer
- Bounty system, edit history, moderation queues (discussed as extensions)
- Real-time notifications (event hooks only)
Example Inputs and Outputs
Scenario 1: Post, Answer, and Accept
- User Alice (reputation 1) posts a question "How do I reverse a linked list?" tagged
[java, data-structures] - User Bob (reputation 200) posts an answer with a recursive solution
- Alice accepts Bob's answer
- Expected: Bob's reputation increases by +15 (accepted answer). Alice's reputation increases by +2 (accepted an answer). The question shows Bob's answer as accepted.
Scenario 2: Voting with Reputation Effects
- User Charlie (reputation 100) upvotes Alice's question
- User Dave (reputation 150) downvotes Bob's answer
- Expected: Alice gains +10 (question upvote, now at 13). Bob loses -2 (downvote received, now at 213). Dave loses -1 (cost of downvoting, now at 149).
Scenario 3: Privilege Check Failure
- User Eve (reputation 10) tries to upvote a question
- Expected: rejected because upvoting requires 15 reputation. Eve cannot upvote yet.
Try It Yourself
Try it yourself
Before reading the solution, spend 15-20 minutes sketching your own class diagram. Focus on how you would track votes (one per user per post) and how reputation changes propagate. Compare your approach with the walkthrough below.
Step 1: Identify Core Entities
Start by scanning the requirements for nouns: user, question, answer, comment, vote, tag, reputation, search result. Each noun is a candidate entity. The next question: does each one deserve its own class, or can some be merged?
A common mistake here is lumping Question and Answer together because "they're both posts." They do share traits (body, votes, comments), but they have different behaviors: only Questions have tags, only Questions can be closed as duplicates, and only Answers can be accepted. We use a shared Votable abstraction to capture commonality while keeping them as distinct types.
| Entity | Responsibility | Key attributes |
|---|---|---|
| Platform | Top-level orchestrator. Manages users, questions, and search. | users, questions, tags |
| User | Tracks identity, reputation, and privilege level. | id, name, reputation, questions, answers |
| Question | A posted question with tags, answers, and optional duplicate link. | id, title, body, tags, answers, acceptedAnswer, closedAsDuplicate |
| Answer | A response to a question. Can be accepted by the question author. | id, body, question, accepted |
| Comment | A short remark attached to a question or answer. | id, body, author, timestamp |
| Vote | A single upvote or downvote from one user on one post. | voter, targetPost, voteType |
| Tag | A topic label for categorizing questions. | name, description |
| Votable | Abstract base for Question and Answer. Holds votes and comments. | votes, comments, score, author |
| ReputationEvent | A record of a single reputation change with reason. | userId, points, reason, timestamp |
| SearchResult | A ranked result from a search query. | question, relevanceScore |
Notice that Vote is its own entity, not just a counter on the post. We need to enforce "one vote per user per post" and support vote changes. A simple integer counter cannot do that. Each Vote records who voted and what type, and the Votable class indexes votes by user ID for O(1) lookups.
Step 2: Define Relationships and Class Design
User
The User is more than a data holder. It owns the reputation log and answers privilege queries.
Deriving state from requirements:
| Requirement | What User must track |
|---|---|
| "Reputation updates: +10, +15, -2, etc." | Running reputation total and event log |
| "Privilege escalation at thresholds" | Current reputation for threshold checks |
| "Users post questions and answers" | References to authored content (optional) |
Deriving methods from needs:
| Need | Method |
|---|---|
| Check if user can perform action | hasPrivilege(Privilege) |
| Update reputation on events | addReputationEvent(ReputationEvent) |
| Get current score | getReputation() |
Votable (Abstract Base)
Votable captures the shared voting and commenting behavior of Question and Answer. The key decision: votes are stored in a Map<String, Vote> keyed by user ID, giving O(1) lookup for duplicate vote checks.
Deriving state from requirements:
| Requirement | What Votable must track |
|---|---|
| "One vote per user per post" | Map from user ID to Vote |
| "Both questions and answers have comments" | List of comments |
| "Score derived from votes" | Computed from vote map (no separate counter) |
The score is computed on demand: count UPVOTE entries minus DOWNVOTE entries. No separate counter means no risk of the score drifting out of sync with the actual votes.
Platform (Orchestrator)
The Platform orchestrates all actions. It validates privileges, delegates to entities, and fires reputation events. I always tell candidates: your orchestrator should be the single entry point for all mutations. If voting logic is scattered across User, Question, and Answer, bugs will follow.
Deriving methods from needs:
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with NotesFromSDE Premium.