Design a question-and-answer site
People ask questions, others answer, everyone votes, and the best answer should rise to the top, for the person who asked and for the millions who arrive from a search engine years later. Most traffic is anonymous reading; the hard parts are ranking answers fairly, spotting duplicate questions, and keeping a community of writers motivated.
1. The prompt
"Design a Q&A site: users post questions, write answers, vote, and follow topics. Show the best answers first, and help people find existing answers before they ask again."
What makes it hard:
- Ranking with little data. An answer with 3 upvotes and 0 downvotes isn't obviously better than one with 90 and 10.
- Duplicates. The same question is asked in a hundred wordings; answers get spread thin.
- Reads dwarf writes, and most readers arrive from search engines, not the home page.
2. Frame the problem
How big?
300 M monthly visitors, most of them signed out; 50 M questions with 150 M answers stored.
Signed-out readers of old questions mean pages can be cached at the CDN.
How many writes?
~100 K new questions, ~300 K answers and ~5 M votes a day.
Votes are the only frequent write; they need cheap counters, not row locks on hot answers.
Is there a personalised home feed?
Yes: questions from followed topics and people, ranked.
A feed pipeline (Design D06), but questions are long-lived, so ranking matters more than recency.
Rich content?
Markdown text with images and code blocks.
Images go to blob storage; text is small and stored in the database.
Should we stop duplicate questions?
Suggest similar questions while typing, and let the community merge duplicates.
A similarity search at question time, plus a merge workflow.
Reputation and moderation?
Points from votes unlock abilities (editing, closing); spam and abuse must be handled.
Votes feed reputation, so vote fraud matters; moderation needs queues and tools.
Search?
Full-text search across questions and answers.
A search index fed from the database (Design D26, Module 12).
3. What it must do
- A user can ask a question and is shown similar existing questions before posting.
- A user can answer and vote; each question shows its answers best first.
- A user sees a feed of questions from topics and people they follow, and can search everything.
Not now: private messaging, paid answers, live sessions, AI-written answers (a follow-up in section 10).
4. How well it must do it
| Target | Why this number |
|---|---|
| Question pages: p95 under 300 ms, even for signed-out visitors worldwide speed · where it runs | Most visitors arrive from search; slow pages lose them and their search ranking. |
| Fair ranking: a good answer with few votes isn't buried under an older one; vote counts update within seconds data quality | Writers stay only if good work is seen. |
| Duplicate suggestions appear as the asker types (under 300 ms) speed | Every duplicate prevented is one more question with a complete answer. |
| Votes are counted once per user per post, and fraud doesn't move reputation consistency · security | Reputation unlocks moderation powers. |
| Reads keep working if writes are degraded surviving failures | Reading is 99% of the value. |
5. Numbers that change the design
| Quantity | Working | → so we… |
|---|---|---|
| Page views | ~1 B a month ≈ 400 a second on average, a few thousand at peak | Modest for cached pages → so signed-out question pages come from the CDN and a page cache |
| Votes | 5 M a day ≈ 60 a second, bursts on viral answers | → so one row per (user, post) for uniqueness, plus a counter updated asynchronously |
| Stored text | 200 M posts × ~2 KB ≈ 400 GB | Fits one database cluster → so we start with one relational primary and read replicas; no sharding on day one |
| Reality check | Stack Overflow served ~66 M page loads a day in 2016 from 9 web servers and 4 SQL servers in 2 clusters | → so caching and a well-indexed database go a very long way |
6. The nouns
- User (with reputation), Question, Answer, Comment.
- Vote: one per user per post.
- Topic and Follow.
- Duplicate link: question A is a duplicate of question B.
questions question_id, author_id, title, body, topic_ids[], score, answer_count, accepted_answer_id, duplicate_of, created_at answers answer_id, question_id (index), author_id, body, up, down, rank_score, created_at votes user_id, post_id, value (+1 | -1), created_at PRIMARY KEY (user_id, post_id) follows user_id, target_type (topic | user), target_id reputation user_id, points (derived from votes, recomputable)
7. The contract
POST /v1/questions {title, body, topics} Idempotency-Key: … → {question_id, url}
GET /v1/questions/similar?title=… → [{question_id, title, answer_count}] (while typing)
GET /v1/questions/{id}?answers_sort=best&cursor=… → {question, answers: [...], next_cursor}
POST /v1/questions/{id}/answers {body} → {answer_id}
PUT /v1/posts/{id}/vote {value: 1 | -1 | 0} → {up, down} (PUT: repeating it is harmless)
GET /v1/feed?cursor=… → [{question summary}]
GET /v1/search?q=…&cursor=… → [{question summary, matched answer snippet}]
8. First working version
Stateless web servers, one relational database with replicas, Redis for caching, a CDN, and blob storage for images.
8.1 Asking (with duplicate suggestions)
As the title is typed, the client asks for similar questions (first version: full-text search on titles). On submit, one insert, then an event so search, feeds and notifications update asynchronously.
8.2 Reading a question
A signed-out visitor gets the whole rendered page from the CDN or the page cache. Signed-in users get the same cached page plus a small personal layer (their votes, follow state) fetched separately.
8.3 Voting
Upsert the vote row keyed by (user, post): repeating a vote changes nothing, and switching from up to down is a single update. Counts on the answer are updated from that change.
9. Make it hold up
9.1 Ranking answers fairly fair ranking
| Approach | Why | |
|---|---|---|
| ✗ Bad | Net votes (up − down) | The oldest answer has had the most time to collect votes; a better new one never catches up. |
| ~ Good | Share of upvotes (up ÷ total) | Fixes age, but one upvote out of one beats 95 out of 100. |
| ✓ Great | The lower bound of a confidence interval on the share of upvotes (the Wilson score), plus a quality model (length, code, author's track record) and a small boost for the accepted answer | Answers with few votes are ranked cautiously, not punished or over-promoted. Try it in section 13. |
Compute rank_score when votes change (asynchronously) and store it, so reading a question is a simple indexed sort.
9.2 Finding duplicate questions suggestions under 300 ms
- Keyword search on titles catches same-word duplicates but misses "How do I reverse a list?" vs "Flip the order of an array".
- Embeddings (Module 29): turn each question title into a vector; nearby vectors mean similar meaning. A nearest-neighbour index returns candidates as the user types.
- Combine both (hybrid search), re-rank with a classifier trained on questions the community already merged (Quora published such a dataset), and show the top five.
- When the community closes a question as a duplicate, redirect it to the original and fold its answers in, so search engines and links lead to one complete page.
9.3 Votes on a hot answer votes counted once
- The
votestable, with its primary key on (user, post), is the truth: uniqueness comes from the database. - Counters are derived: a vote event goes on a queue; a worker batches increments per post every second or two (Module 18) and recomputes
rank_score. A viral answer's thousand votes a minute become a few dozen writes. - Reputation is derived the same way, and can be recomputed from the votes table after fraud is removed.
9.4 The personalised feed reads keep working
Unlike a social feed, questions stay relevant for years and topics have millions of followers, so fan-out on write is wasteful. Build the feed on read: take recent and top questions from the user's followed topics (each topic's list precomputed and cached), merge, rank by a model (topic affinity, answer quality, freshness), and cache the result for a few minutes. Design D06 explains the push vs pull trade-off.
9.5 Caching pages that change question pages under 300 ms
| Approach | Why | |
|---|---|---|
| ✗ Bad | No page cache: render every view from the database | Works, but every read becomes several queries; spikes from search engines hit the database. |
| ~ Good | Cache rendered pages with a long TTL | Fast, but a new answer or edit stays invisible for the TTL. |
| ✓ Great | Cache signed-out pages at the CDN with a short TTL (a minute) plus stale-while-revalidate, purge or bump a version on edits and new answers, and keep vote counts slightly stale on purpose | Almost every read is a cache hit; content changes show within a minute; counts don't need to be exact. |
9.6 Spam, abuse and vote fraud security
New posts from new accounts go through a spam classifier and rate limits; low-confidence posts wait in a review queue. Vote fraud (sock-puppet accounts, voting rings) is detected offline by looking for accounts that vote mostly for one person, then those votes are reversed and reputation recomputed. Users unlock moderation abilities as reputation grows, which spreads the review work.
9.7 The whole design after the deep dives
10. Interviewer follow-ups
Show an AI-generated answer at the top.
Generate it with retrieval over the site's own answers (Module 29), label it clearly, cite the answers it used, and rank human answers by their own scores. Cache it per question; regenerate when answers change. Watch quality and the incentive for humans to keep writing.
A question goes viral from a news story.
The CDN absorbs the reads. Votes and answers burst on one question: batching keeps counter writes small, and rate limits slow sudden waves of new accounts.
The database outgrows one primary.
Move votes and counters to their own store first (they're the hottest writes), then shard questions and answers by question ID so a page is always one shard. Search and feeds already read from derived stores.
Support many languages.
Separate sites or language partitions, a language-aware search analyser and embeddings per language, and duplicate detection within each language.
Notify people when their question gets an answer.
The answer event feeds a notification service (Design D05) with batching, so a question receiving 20 answers sends one digest.
Delete a user's account and content.
Remove personal data; keep or anonymise their posts according to policy, since others' answers and votes depend on them. Purge caches and the search index, and recompute affected reputation.
Search engines crawl aggressively.
Serve them the cached pages, publish sitemaps, and rate-limit unknown crawlers at the edge.
11. When things break
| Failure | What users see | How we detect it | What limits the damage |
|---|---|---|---|
| Primary database down | Can't post or vote; reading works | Write errors | Failover to a standby; pages served from caches and replicas |
| Counter worker lagging | Vote counts a little behind | Queue lag | Counts are derived; catch up from the queue |
| Search index stale | New questions missing from search | Index lag | Re-feed from the change stream |
| Embedding service down | Fewer duplicate suggestions | Error rate | Fall back to keyword suggestions |
| Spam wave | Junk questions | Spam score spikes, new-account rate | Stricter rate limits and review queue for new accounts |
| Bad cache purge | Old answer shown | Edit-to-visible delay | Short TTLs as a backstop |
12. Wrap-up and the clock
Trade-offs we made:
- Slightly stale counts and pages for huge cache hit rates.
- A confidence-based ranking instead of simple vote sums.
- Feeds built on read, because questions live for years.
- One database first; derived stores for search, feeds and counters.
What we'd watch: CDN and page-cache hit rates · question page p95 · duplicate-suggestion click-through · vote queue lag · spam rate · answers per question.
At 10×: separate the vote store, shard questions by ID, more CDN capacity.
A 60-minute interview
| 0–5 | Frame: readers vs writers, votes, duplicates |
| 5–10 | Must do, how well, numbers |
| 10–15 | Nouns, contract |
| 15–25 | First version: ask, read, vote |
| 25–50 | Deep dives: ranking (9.1), duplicates (9.2), caching (9.5) |
| 50–60 | Votes or feed, follow-ups, wrap-up |
A 90-minute interview
| 0–8 | Frame, including moderation and SEO |
| 8–15 | Must do, how well, numbers |
| 15–22 | Nouns, contract |
| 22–35 | First working version |
| 35–75 | Deep dives 9.1–9.6 and the final picture |
| 75–85 | Follow-ups: AI answers, scaling the database |
| 85–90 | Trade-offs, metrics, 10× |
| Level | What a strong answer shows |
|---|---|
| Mid-level | A relational model with a unique vote key, CDN and Redis caching, full-text search, a simple ranking with its flaw explained. |
| Senior | Confidence-based ranking, embeddings for duplicates, asynchronous counters, feeds on read with reasons, cache freshness strategy. |
| Staff+ | Community incentives and abuse as design inputs, recomputable derived data (reputation, counts), SEO and duplicates merged into canonical pages, evaluation of ranking and suggestion quality. |
Common mistakes:
- Sorting answers by net votes.
- Updating a counter row in the request for every vote.
- Fan-out on write to millions of topic followers.
- Sharding a dataset that fits on one machine.
- Treating every page view as a personalised request.
13. Try it, check yourself, read more
Answer-ranking lab. Five answers to one question, with their upvotes and downvotes. Switch the ranking and watch the order change. Then give the newest answer a few more upvotes.
Wilson lower bound at 95% confidence: the lowest share of upvotes that's still consistent with the votes seen so far.
Which score ranks a 3-up/0-down answer fairly against a 90-up/10-down one?
What guarantees one vote per user per answer?
How do you catch duplicates worded differently?
Topics have millions of followers and questions stay relevant for years. How is the feed built?
| Resource | Why |
|---|---|
| How not to sort by average rating (Evan Miller) | Why the Wilson lower bound beats net votes and ratios. |
| Stack Overflow: the architecture, 2016 edition (Nick Craver) | A huge Q&A site on a handful of servers, thanks to caching. |
| Quora Question Pairs (Kaggle) | The duplicate-question problem as a public dataset. |
| MinHash | Fast near-duplicate detection on text, before or alongside embeddings. |
| Binomial proportion confidence interval | The maths behind the Wilson score. |