Back to LLD explorer
Concurrency / Realtime• Patterns: Command, Observer, Strategy

Google Docs

Hard

Problem Summary

Design a real-time Collaborative Rich-Text Document Editor supporting concurrent multi-user editing, Operational Transformation (OT) conflict resolution, and version history snapshots.

Functional Scope

  • Concurrent document modifications by multiple remote collaborators.
  • Operational Transformation (OT) or CRDT strategy to guarantee eventual consistency.
  • Command pattern encapsulating document mutations (Insert, Delete, Format).
  • Observer pattern broadcasting transformed operations to connected WebSocket peers.
  • Monotonically increasing document revisions and snapshot recovery.

Entity-Relationship (ER) Schema

Document [1] --> [*] Operation
Document [1] --> [1] ConflictResolverStrategy
Document [1] --> [*] CollaboratorObserver

Design Approach

Apply the Command pattern for editing operations and Strategy for Operational Transformation (OT) transformation matrices, ensuring all collaborators converge on identical document contents.

Core Classes & Models

Document (DocId, revision, text buffer)Operation (Type: INSERT, DELETE, position, text content, authorId, clientRevision)ConflictResolverStrategy (OperationalTransformationStrategy, CRDTStrategy)CollaboratorObserver (Broadcasts transformed operations to connected peers)HistoryManager (Snapshot creation and revision rollback)
Code Blueprint
89 lines
/**
 * Low-Level Design: Google Docs Collaborative Text Editor
 * Design Patterns Applied:
 *  - Command Pattern: Encapsulating keystrokes, inserts, deletes with Undo / Redo support
 *  - Observer Pattern: Real-time broadcast of document edits to active collaborators
 *  - Strategy Pattern: Operational Transformation (OT) conflict resolution strategies
 */

import java.util.*;

// --- [DESIGN PATTERN: Observer] Real-time collaborator sync ---
interface DocumentObserver {
    void onDocumentModified(int version, String fullText);
}

class CollaboratorView implements DocumentObserver {
    private final String userId;
    public CollaboratorView(String userId) { this.userId = userId; }
    @Override
    public void onDocumentModified(int version, String fullText) {
        System.out.printf("💻 [Collaborator %s] Sync v%d: \"%s\"%n", userId, version, fullText);
    }
}

// --- [DESIGN PATTERN: Command] Text editing command with undo ---
interface EditorCommand {
    void execute();
    void undo();
}

class InsertTextCommand implements EditorCommand {
    private final StringBuilder doc;
    private final int index;
    private final String text;

    public InsertTextCommand(StringBuilder doc, int index, String text) {
        this.doc = doc; this.index = index; this.text = text;
    }

    @Override
    public void execute() {
        doc.insert(index, text);
    }

    @Override
    public void undo() {
        doc.delete(index, index + text.length());
    }
}

class CollaborativeDocument {
    private final StringBuilder content = new StringBuilder();
    private int version = 0;
    private final Stack<EditorCommand> history = new Stack<>();
    private final List<DocumentObserver> observers = new ArrayList<>();

    public void addObserver(DocumentObserver o) { observers.add(o); }

    public synchronized void applyCommand(EditorCommand cmd) {
        cmd.execute();
        history.push(cmd);
        version++;
        for (DocumentObserver o : observers) o.onDocumentModified(version, content.toString());
    }

    public synchronized void undo() {
        if (!history.isEmpty()) {
            EditorCommand cmd = history.pop();
            cmd.undo();
            version++;
            for (DocumentObserver o : observers) o.onDocumentModified(version, content.toString());
        }
    }

    public StringBuilder getContent() { return content; }
}

public class Main {
    public static void main(String[] args) {
        CollaborativeDocument doc = new CollaborativeDocument();
        doc.addObserver(new CollaboratorView("Alice"));
        doc.addObserver(new CollaboratorView("Bob"));

        System.out.println("--- Collaborative Editing ---");
        doc.applyCommand(new InsertTextCommand(doc.getContent(), 0, "Hello "));
        doc.applyCommand(new InsertTextCommand(doc.getContent(), 6, "World!"));
        doc.undo();
    }
}