Causality: Why Unique Isn't Enough
Why this matters: the range handler gave us unique IDs and nothing else. If the ID cannot tell you what happened first, you need a second mechanism for ordering — or an ID that carries it.
Key takeaway
Beyond uniqueness, systems need to reason about event ordering and causality. In many designs it is preferable to use an identifier that both guarantees uniqueness and preserves event ordering.
Causal versus concurrent
Consider two users on a social media platform. One posts a comment (Event A), another replies (Event B). Event B depends on Event A and must occur after it — they are causally related.
Conversely, concurrent events occur independently. If Peter and John comment on two different tweets simultaneously, there is no causal relationship between them.
The goal is to identify dependencies where they exist — and, just as importantly, to not invent ordering between events that have none.
Where ordering is actually required
| Use case | Why ordering matters |
|---|---|
| Last-write-wins conflict resolution | A key-value store uses time-ordered identifiers to decide which of two concurrent writes survives |
| Distributed tracing | Reconstructing a request means knowing which span preceded which, across services |
| Financial regulation | MiFID requires wall-clock synchronization within 100 microseconds of UTC to detect anomalies in high-speed trading |
| Replicated logs | Replaying events in the wrong order produces a different final state |
Why physical clocks fail
Timestamps are commonly used to determine event ordering. If one event occurs at 6:00 a.m. and another at 7:00 a.m., their timestamps establish the order.
However, relying on physical clocks in distributed systems is challenging due to clock drift, skew, and synchronization limits.
This is the same problem the Databases chapter raised about last-write-wins and the Key-Value Store chapter raised about vector clocks — arriving here as a design constraint on the ID format itself.
The scorecard grows
From here on, every approach is also scored on causality maintained:
| Unique | Scalable | Available | 64-bit numeric ID | Causality maintained | |
|---|---|---|---|---|---|
| Using UUID | |||||
| Using a database | |||||
| Using a range handler |
Our best approach so far scores four out of five — and the missing column is the one the rest of the chapter is about.
Key takeaway
Uniqueness is a property of one ID. Causality is a property of the relationship between two. Getting the second requires either logical time or extraordinarily good physical time — and the next four lessons are those two paths.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "We'd add a timestamp so we know the order." |
| L5 | Knows clocks are unreliable: "physical timestamps drift between machines, so they can't reliably order events across servers." |
| Staff+ | Separates the two properties: "uniqueness is per-ID, causality is between IDs. And embedding physical time threatens both — a drifting clock corrected by NTP can reissue a timestamp, so you get duplicates and broken ordering from the same cause." |
Next: the simplest attempt at time-based IDs.