Stack Overflow (LLD)#
Problem statement (interviewer prompt)
Design the OO class model for Stack Overflow: users, questions, answers, comments, votes, tags, reputation, and badges. Cover voting effect on reputation, accepting an answer, and tag-based search.
classDiagram
class User {
+id, name, email
+reputation : int
+badges : List~Badge~
+vote(post, type)
}
class Post {
<<abstract>>
+id, author : User
+body, createdAt
+votes : Map~User, VoteType~
+comments : List~Comment~
+score() int
}
class Question {
+title, tags : Set~Tag~
+answers : List~Answer~
+acceptedAnswer : Answer
}
class Answer {
+question : Question
+accepted : boolean
}
class Comment { +author, body, post }
class Tag { +name, description }
class Badge { +name, kind }
Post <|-- Question
Post <|-- Answer
Question *-- "many" Answer
Question *-- "many" Tag
Post *-- "many" Comment
User --> Post : authors
Reputation deltas: +10 upvote on Question, +10 upvote on Answer, +15 accepted answer, -2 downvote, -1 to downvoter on Answer.
A common interview problem because it exercises inheritance, observer/event patterns, validation rules, and a clear data model.
Class diagram#
classDiagram
class User {
+id, name, email
+reputation : int
-badges : List~Badge~
+ask(title, body, tags) Question
+answer(q, body) Answer
+comment(post, body)
+vote(post, type)
}
class Post {
<<abstract>>
+id, author : User
+body, createdAt
-votes : Map~User, VoteType~
-comments : List~Comment~
+addVote(user, type)
+score() int
}
class Question {
+title, tags : Set~Tag~
-answers : List~Answer~
+acceptedAnswer : Answer
+accept(answer)
}
class Answer {
+question : Question
+accepted : boolean
}
class Comment { +author, body, postId }
class Tag { +name, description }
class Badge { +name, kind }
class VoteType {
<<enumeration>>
UP
DOWN
}
Post <|-- Question
Post <|-- Answer
Question *-- "many" Answer
Question *-- "many" Tag
Post *-- "many" Comment
User --> Post : authors
Voting flow#
class Post:
def add_vote(self, user, t: VoteType):
if user == self.author: raise ValueError("cannot vote own post")
prev = self.votes.get(user)
self.votes[user] = t
delta = vote_delta(self, prev, t) # bumps author rep
self.author.reputation += delta
Reputation deltas (SO defaults):
| Action | Author Δ | Voter Δ |
|---|---|---|
| Upvote question | +5 | 0 |
| Upvote answer | +10 | 0 |
| Downvote answer | -2 | -1 |
| Accepted answer | +15 | +2 |
Accept answer#
class Question:
def accept(self, answer, by):
if by != self.author: raise PermissionError
if answer.question != self: raise ValueError
if self.accepted_answer:
self.accepted_answer.accepted = False
self.accepted_answer.author.reputation -= 15
answer.accepted = True
answer.author.reputation += 15
Tag-based search#
In LLD, model an in-memory tag→questions inverted index; in HLD this is Elasticsearch.
class Repo:
def __init__(self):
self.tag_index: dict[Tag, set[Question]] = defaultdict(set)
def index(self, q: Question):
for tag in q.tags:
self.tag_index[tag].add(q)
def search(self, tags: list[Tag]) -> list[Question]:
return sorted(set.intersection(*(self.tag_index[t] for t in tags)),
key=lambda q: q.score(), reverse=True)
Badge engine (Observer / event-driven)#
flowchart LR
Event[VoteCast / AnswerAccepted] --> Bus[(event bus)]
Bus --> BadgeRule1[Rule: 10 upvotes -> Popular Question]
Bus --> BadgeRule2[Rule: accepted answer -> Enlightened]
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class Event,BadgeRule1,BadgeRule2 service;
class Bus queue;
Each domain event publishes to an event bus; badge-awarding rules subscribe.
Moderation#
- Posts can be flagged.
- A
ModerationQueueholds flagged posts pending review. - Moderator actions: hide, edit, delete, restore.
- Threshold reputation to gain moderation privileges.
Concurrency#
- Vote counts: use atomic increments or row-level locks.
- Reputation: same.
- Posting: optimistic locking by version.
Extensions#
- Bounty system (offered reputation locked until awarded).
- Edit history (immutable revisions).
- Markdown rendering layer.
- Notifications (your post received an answer).
Where Stack Overflow LLD fits#
flowchart TB
SO((Stack Overflow<br/>LLD))
OOP[OOP pillars<br/>Post inheritance]
BPL[Behavioral patterns<br/>Observer / badges]
RQ["Reddit Q&A (HLD)<br/>system-design sibling"]
POL[Pessimistic / optimistic locking<br/>concurrent voting]
OOP --> SO
BPL --> SO
SO -. complement .- RQ
POL --> SO
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class SO service;
class OOP,BPL,RQ,POL datastore;
Glossary & fundamentals#
| Tag | Concept | What it is | Page |
|---|---|---|---|
LLD |
OOP pillars | Post inheritance | oop-pillars |
LLD |
Behavioral patterns | Observer for badge events | behavioral-patterns |
HLD |
Reddit Q&A (HLD) | the system-design sibling | reddit-qa |
LLD |
Pessimistic vs optimistic locking | concurrent voting | pessimistic-optimistic-locking |
Quick reference#
Classes#
- User (reputation, badges)
- Post (abstract: votes, comments)
- Question (title, tags, answers, acceptedAnswer)
- Answer (question, accepted)
- Comment, Tag, Badge
Reputation deltas#
| Action | Author Δ |
|---|---|
| Upvote Q | +5 |
| Upvote A | +10 |
| Downvote A | -2 (voter -1) |
| Accepted A | +15 |
Accept rules#
- Only Q's author can accept
- Switching: previous accepted loses +15
- Question's acceptedAnswer updated atomically
Tag search#
In-memory inverted index: tag → set
Badge engine#
Domain events → bus → rule evaluators. Decouples awarding from posting.
Moderation#
Flag → ModerationQueue → moderator actions (hide/edit/delete/restore).
Concurrency#
- Atomic vote counters / row locks
- Optimistic version per post for edits
Extensions#
- Bounties
- Edit history (immutable revisions)
- Notifications
- Markdown rendering
Refs#
- Stack Exchange API docs
- Nick Craver - SO architecture posts
FAQ#
How is reputation calculated?#
Each vote on a user's post applies a fixed delta: question upvote plus 5, answer upvote plus 10, downvote minus 2, accepted answer plus 15. The sum is the user's reputation.
How do you model questions and answers?#
A common Post superclass with subclasses Question and Answer. Comments attach to any Post. Question owns an optional accepted_answer_id and a list of Answer references.
How is tag-based search implemented?#
Tags are a many-to-many relation with Question. A secondary index from tag to question id list lets queries fetch posts by tag in O(1) per tag.
How is voting kept idempotent?#
Each Vote row is keyed (user_id, post_id) so a user can vote at most once per post. Re-voting updates the existing row, recomputing the reputation delta atomically.
How are badges awarded?#
Define BadgeRule objects with predicates that check post or user events; an event bus fires changes and a worker evaluates the rules, granting badges idempotently.
Related Topics#
- Reddit Q&A (HLD): the system-design counterpart
- Behavioral Patterns: Observer for badge engine
- Pessimistic vs Optimistic Locking: concurrent vote/reputation updates
Further reading#
- Site - Stack Exchange API docs
- Blog - Stack Overflow architecture posts