Chapter 13 · Denormalization, Caching, and Derived Data
Duplicated Attributes and Consistency Ownership
Design duplicated attributes safely by naming the authoritative source, defining synchronization rules, and separating historical snapshots from accidental redundancy.
Learning outcomes
Duplicating an attribute is safe only when the system can answer one question clearly: which copy is authoritative? Without that rule, denormalized fields drift and different consumers see different truths.
Assign authoritative ownership to every duplicated fact.
Separate mutable copies from historical snapshots.
Choose synchronous or asynchronous synchronization deliberately.
Design reconciliation rules for duplicated attributes.
One fact, one owner
Customer.legal_name -- authoritativeWorkOrderProjection.customer_name -- derivedInvoice.customer_name_snapshot -- historical factThe projection copy should not become independently editable. The invoice snapshot may intentionally remain unchanged forever.
Current copy versus historical snapshot
| Copy | Meaning | Refresh? |
|---|---|---|
| Projection.customer_name | Current Customer name | Yes |
| Invoice.customer_name_snapshot | Name at invoice issuance | No |
| PartUsage.charged_unit_price | Price charged at usage time | No |
Equal-looking values can have different owners because their time semantics differ.
Synchronous duplication
BEGIN;UPDATE customer ...;UPDATE customer_read_projection ...;COMMIT;Strong consistency, but greater transaction cost and coupling.
Asynchronous duplication
Lower source-write coupling, but temporary staleness must be accepted and monitored.
Versioned synchronization
customer_id = 17source_version = 42If version 44 has already been applied, a late version-43 event must not overwrite the newer projection state.
Idempotent projection updates
Duplicate event delivery should be harmless. Store processed event IDs, source versions, or design the update as a deterministic overwrite rather than an unconditional increment.
Ownership across services
Prefer:
Customer Service owns legal_nameOther services consume CustomerUpdatedAvoid two services both “owning” and independently editing the same field.
Derived totals
WorkOrder.parts_totalIf PartUsage rows are authoritative, the total is derived and requires maintenance for every relevant insert, update, delete, reversal, or correction.
Counter drift
- lost event;
- duplicate event;
- manual database update;
- migration that bypasses normal logic;
- failed consumer;
- out-of-order event.
Reconciliation query
SELECT wo.work_order_idFROM work_order woWHERE wo.parts_total <> ( SELECT COALESCE(SUM(quantity * charged_unit_price), 0) FROM part_usage pu WHERE pu.work_order_id = wo.work_order_id);A reconciliation path turns hidden drift into detectable drift.
Copying identifiers
Stable identifiers such as tenant_id or customer_id are frequently copied into projections for efficient filtering. Their ownership still needs to be documented, especially if the identifier can be reassigned or scoped.
Copying reference labels
Status display names may change. Decide whether a projection should show the latest label or preserve the label as it appeared historically.
All write paths matter
Synchronization must account for API commands, admin tools, imports, migrations, support scripts, and repair jobs. A denormalized design is only as reliable as its least-governed write path.
WorkshopHub duplication registry
| Value | Owner | Refresh |
|---|---|---|
| Projection.customer_name | Customer | CustomerUpdated |
| Invoice customer snapshot | Invoice event | Never |
| WorkOrder.parts_total | PartUsage set | Transactional or async aggregate |
| Search status label | Status reference | Reindex/update |
Practice: define ownership
Asset display name
Asset has a calculated display name copied into a search index. What should be documented?
Review answer
Authoritative source fields, calculation rule, update trigger/event, freshness target, idempotency/version behavior, reconciliation method, rebuild procedure, and the rule that the search copy is not independently editable.
Summary and next lesson
Safe duplication requires one authoritative owner, explicit temporal meaning, and deterministic synchronization. Current copies refresh; historical snapshots often do not. The next lesson applies these principles to aggregated structures such as summary tables and materialized views.
References
- Martin Kleppmann, Designing Data-Intensive Applications.
- Pat Helland, writings on data ownership and distributed systems.
- Martin Fowler, material on CQRS and event-driven projections.