System Design Arena

Design Google Docs

Collaborative document editing: operational transformation vs CRDTs, presence, permissions, and version history for millions of concurrent documents.

Functional RequirementsNon-Functional RequirementsProtocol & API

Case Study

Google Docs

Same conversation, diagrams, and wrap-up you expectβ€”now framed with clearer scaffolding and iconography.

Prompt

Design a collaborative editor like Google Docs where multiple people edit the same document simultaneously and every participant converges to the same text.

Interview snapshot

  • β€’ Topic: Google Docs
  • β€’ Expected depth: 45 - 60 minutes
  • β€’ Focus areas: APIs, scale estimation, resilient architecture
  • β€’ Wrap-up: risk, monitoring, disaster recovery

Key takeaways

  • β€’ Multiple users edit the same document with live character-level updates.
  • β€’ Local edits render instantly (<16ms); remote edits <200ms.
  • β€’ WebSocket per open doc: submit {baseVersion, ops[]}, receive {version, ops[], authorId}.

πŸŽ™οΈ Interview mode

Practice this like a real interview

Don't read the answer first. Work the framework against the bare prompt, then compare against what the interviewer expected at each step.

🎯 Start guided practice (free)

Scorecard

What the interviewer is evaluating

Requirements7/10
Scale estimation6/10
API design7/10
Architecture9/10
Trade-offs10/10
Failure handling7/10

Staff-level signal

Can the candidate demonstrate the concurrent-edit conflict with a concrete example, then choose OT-with-a-sequencer or CRDT with an articulated trade-off?

🧠 Staff engineer judgment

Do not shard a single document β€” one doc’s edit rate is human-bounded. Centralize per doc (sequencer), shard across docs. Complexity budget goes to convergence, not to distributing 500 ops/sec.

Calibration

The common (bad) answer

Editor autosaves doc every 2s β†’ PUT /doc
Last write wins

❌ Why this scores poorly: Two concurrent editors overwrite each other’s paragraphs on every save. LWW on whole documents is data loss with a save button.

βœ“ What a strong answer adds

  • Character-level operations, not document blobs.
  • A per-doc sequencer totally orders ops; OT transforms concurrent ones.
  • Show convergence with a concrete two-user example.
  • Op log + snapshots: storage, history, and offline merge from one mechanism.
  • Presence as soft state over the same WebSocket.

Video walkthrough

Real-Time Collaboration Explained

Hello Interview Β· 15 min

OT vs CRDT explained clearly β€” the single decision this interview turns on.

Work the prompt yourself first β€” guided practice grades your own answer step by step. Watching someone else design it feels like progress and teaches you far less.

Interview flow

Dialogue timeline

Interviewer

What's the core challenge here?

Candidate

Concurrent edits to the same text. Two users insert at position 5 simultaneously β€” naive last-write-wins corrupts the document. We need every replica to converge to the same result while feeling instant locally.

Interviewer

What are the two standard approaches?

Candidate

Operational Transformation β€” transform incoming operations against concurrent ones, with a central server ordering them β€” and CRDTs, where characters carry identities so merges commute without a central authority. Docs-style products classically use OT with a server as sequencer; I'll design that and note the CRDT trade.

Interviewer

Walk me through OT with a concrete example.

Candidate

Doc is 'cat'. A inserts 'X' at 0; B deletes position 2 concurrently. Server orders A first; B's delete arrives referencing old positions, so it's transformed: shift by A's insert β†’ delete position 3. Both replicas apply operations in server order with transforms and converge to 'Xca'.

Interviewer

Why does a central server per document help so much?

Candidate

One sequencer per doc gives a total order of ops β€” the transform matrix stays simple (op vs op), versions are just sequence numbers, and history is the op log itself. The cost: that doc's edits all route to one place β€” fine, because a single doc's edit rate is human-scale.

Interviewer

How do sessions and presence work?

Candidate

Every open doc holds a WebSocket to the doc's session server (consistent-hash docId β†’ server). The server broadcasts ops, cursors, and selections. Presence is soft state β€” lost on reconnect, rebuilt instantly.

Interviewer

Offline edits for an hour, then reconnect.

Candidate

The client queued local ops against version V. On reconnect it pulls ops V..now, transforms its queue over them (same OT machinery), and submits. Convergence logic is identical to live editing β€” offline is just a long network delay.

Interviewer

Storage and history?

Candidate

Append-only op log per doc + periodic snapshots so loading is snapshot+tail, not a million-op replay. Named versions are pointers into the log; 'see edit history' falls out for free.

Interviewer

Scale check: millions of concurrent documents.

Candidate

Each doc is small and independent β€” shard by docId across session servers. The hard scaling is ops/doc (bounded by humans) not docs (unbounded but parallel). Hot doc with 100 editors: broadcast fan-out 100 β€” still trivial. The design scales because docs don't interact.

Scoping

Requirements & trade-offs

Functional Requirements

  • β€”Multiple users edit the same document with live character-level updates.
  • β€”Cursors/selections of collaborators visible in real time.
  • β€”Offline editing with safe merge on reconnect.
  • β€”Version history with restore. Out of scope: comments, suggestions.

Non-Functional Requirements

  • β€”Local edits render instantly (<16ms); remote edits <200ms.
  • β€”Strong eventual convergence β€” all replicas end identical, no lost edits.
  • β€”A document survives server crashes with zero committed-op loss.
  • β€”Millions of concurrent docs; hundreds of editors per doc worst-case.

Blueprint

Architecture modules

Module 1

Protocol & API

  • β€’WebSocket per open doc: submit {baseVersion, ops[]}, receive {version, ops[], authorId}.
  • β€’Ops: insert(pos, chars) / delete(pos, len) β€” transformed server-side.
  • β€’REST: snapshots, history list, permission grants.
  • β€’ACL check on session open + every op batch.

Module 2

Back-of-the-Envelope

  • β€’Typing β‰ˆ 5 ops/sec/user; 100 editors β†’ 500 ops/sec/doc max β€” tiny per doc.
  • β€’10M concurrent docs Γ— avg 2 sessions β†’ 20M WebSockets β†’ ~200 session servers.
  • β€’Op ~50 bytes; a heavily-edited doc's log ~10MB/year β†’ snapshot every ~1K ops.
  • β€’Doc-to-server mapping via consistent hashing; failover re-homes doc with log replay.

Module 3

System Diagram Notes

  • β€’Client ↔ Session server (per-doc sequencer, OT transform) ↔ Op log + snapshots.
  • β€’Presence broadcast in-memory on session server.
  • β€’Cold docs hydrate from snapshot+tail; LRU eviction of idle docs.
  • β€’Permissions service consulted at session open; cached with invalidation.

Module 4

Design Playbook

  • β€’Demonstrate the conflict with a two-user example before naming OT β€” show, then tell.
  • β€’OT vs CRDT in three sentences, then commit with a reason.
  • β€’Per-doc sequencer: centralize where cheap (one doc), shard where needed (all docs).
  • β€’Offline = long-latency online; same transform path β€” say it explicitly.
  • β€’Snapshot + op-log gives history free; interviewers reward noticing that.