Skip to content

Designing Robust Ops

The examples in the Building an App Level 3 guide use index-based ops: { op: "toggleDone", index: 2 }. This works for single-session undo but breaks when ops need to survive reordering — undo after other edits, concurrent users, or offline sync. If someone inserts at index 1, your index: 2 now points to the wrong item.

Prefer identity-based ops: { op: "toggleDone", id: "abc123" }. This is the same principle behind CRDTs[^crdt] — operations that commute (produce the same result regardless of order) are safe for concurrent use.

typescript
// Fragile — depends on ordering
type FragileOp = { op: "toggleDone"; index: number }

// Robust — works regardless of order
type RobustOp = { op: "toggleDone"; id: string }

// Gold standard — idempotent (applying twice = applying once)
type IdempotentOp = { op: "setDone"; id: string; done: boolean }
Op styleUndoConcurrentOffline sync
index: 2FragileBreaksBreaks
id: "abc" + toggleWorksWorksDouble-toggle risk
id: "abc" + done: trueWorksWorksIdempotent

You don't need to start here. Index-based is fine for simple undo. But when you add collaboration, offline sync, or AI automation — design identity-based, ideally idempotent.

See Also


[^crdt]: CRDTs (Conflict-free Replicated Data Types) — data structures designed for distributed systems that can be edited independently on multiple replicas and merged without conflicts.

Released under the MIT License.