FSD Frontend System Design

Part VI β€” The Blueprint Β· Lesson 11.11

HLD – Google Docs

In one lineTwo people typing in the same paragraph is the entire problem β€” OT or CRDT is the answer.

Where you've seen itTwo colleagues typing into one sentence, and the result reading correctly for both of them.

  • Time21 min
  • DiagramConcurrent edit conflict + OT vs CRDT resolution
  • Chapter11 Β· High Level Design

Diagram

diagram
1–2 Β· SCOPE AND SCALE

  in scope   rich text editing Β· multi-user cursors Β· comments Β·
             offline editing Β· version history
  out        export pipeline Β· sharing permissions UI Β· print
  scale      docs up to ~100k words Β· 2–20 concurrent editors
             sub-100ms local echo is non-negotiable
diagram
3 Β· THE CORE PROBLEM β€” naive sync loses data

  both start with:  "Hello"

  Alice inserts "!" at 5        Bob inserts " world" at 5
       "Hello!"                      "Hello world"
           β”‚                              β”‚
           └──────────► server β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
              last-write-wins β‡’ ONE EDIT IS LOST βœ—

  Text needs index transformation. This is why 11.9's
  last-write-wins was fine for shapes and is fatal here.
diagram
6a Β· DEEP DIVE β€” OT vs CRDT

  OPERATIONAL TRANSFORM (OT)
    ops carry positions; the server transforms each incoming op
    against ops it has already applied

    Bob's insert@5  ──transform against Alice's insert@5──► insert@6
    result: "Hello! world"   both edits survive

    βœ“ compact ops Β· βœ— needs a central server Β· βœ— hard to prove correct

  CRDT (Yjs, Automerge)
    every character gets a unique, ordered id; merges are
    commutative β€” order of arrival doesn't matter

    βœ“ works peer-to-peer and offline Β· βœ“ provably convergent
    βœ— metadata overhead per character Β· βœ— heavier payloads

  Choose OT if you already have an authoritative server.
  Choose CRDT if offline and P2P matter. Say WHY, either way.
diagram
6b Β· DEEP DIVE β€” LATENCY AND PRESENCE

  local echo    apply the keystroke to the local model IMMEDIATELY
                (never wait for the server β€” typing must feel free)
                     β”‚
                     β”œβ”€β–Ί render
                     └─► queue op β†’ server β†’ broadcast β†’ peers

  presence      cursors + selections, ~20Hz, throttled,
                sent on a SEPARATE ephemeral channel β€” never
                persisted, never part of the document history

How it works

  1. The document is a data model, not the DOM β€” a tree of blocks with marks. Rendering derives from it.
  2. Local echo first: apply, render, then send. Any perceptible delay makes typing feel broken.
  3. Sync via OT or CRDT over WebSocket (2.4), with an explicit reconnect-and-catch-up path.
  4. Presence is ephemeral and travels separately from document operations.
  5. Offline buffers ops locally (9.1) and merges on reconnect β€” CRDTs make this trivial, OT makes it work with server help.

Trade-offs

ChoiceCost
OTCompact, mature, server-dependent, tricky to implement
CRDTOffline-friendly, convergent, larger payloads
contentEditableNative input/IME; famously inconsistent across browsers
Custom-rendered editorFull control; you rebuild IME, selection, and a11y

Accessibility (8.3): rich-text editors are one of the hardest a11y surfaces β€” announce collaborator changes politely without spamming, keep keyboard shortcuts discoverable, and never move the user's cursor because of a remote edit.

Interview angle

"Two users type in the same sentence. How does it not break?"

  • Position indices shift under concurrent edits, so raw last-write-wins loses one of them.
  • OT transforms incoming operations against already-applied ones; CRDTs give every character a unique id so merges commute.
  • I'd pick based on constraints β€” OT with an authoritative server, CRDT if offline or peer-to-peer editing is required β€” and I'd apply locally first so typing never waits on the network.

Recap

  • Concurrent text editing is the problem; OT and CRDT are the two real answers.
  • Local echo immediately; sync in the background.
  • Presence is ephemeral and separate from document history.