Catalog / Data-Oriented Patterns / DOP: Immutable Data Modeling
DOP

DOP: Immutable Data Modeling

Treat data as immutable values that can never change once created. Transformations produce new data.

Intent & Objective

Eliminate all shared mutable state bugs, race conditions, and accidental side effects by ensuring that all data structures are strictly read-only values.

πŸ‘₯ Real-World Human Analogies & Social Roles
1 Intuitive Scenarios
Accounting Bank Ledger Financial Ledgers

"When you buy coffee, the bank does not erase your balance; it adds an immutable transaction record, calculating current balance by summing records."

The Problem

Action at a distance: method A passes an object to method B, and method B silently modifies a field. Method A crashes later because its assumptions were invalidated without its knowledge.

The Solution

Model all data entities with immutable primitives: `const` structs in C++, `frozen=True` dataclasses in Python, and `record` types in Java. Provide non-mutating "wither" functions for incremental updates.

Key Participants & Architectural Roles

Immutable Value
Read-only data entity whose fields cannot be changed after creation
Wither / Transform Function
Returns a brand new copy of the value with specific fields altered
Structural Sharing
Reuses unchanged nested sub-trees to keep memory and CPU overhead near zero

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, objects are mutable entities with identities and internal state machines. In DOP, data structures are pure values (like the number 42 or the string "hello"): you cannot "mutate" the number 42 into 43; you calculate a new number (42 + 1).

Advantages

  • βœ“ Completely thread-safe: immutable objects can be shared across any number of threads with zero locks
  • βœ“ Effortless undo/redo and time-travel debugging: previous states are preserved as values
  • βœ“ Eliminates defensive copying across API boundaries

Trade-offs

  • βœ— Frequent copies in hot loops can cause GC pressure if not using structural sharing or compiler optimizations

When to Apply

  • β†’ Multi-threaded and concurrent applications
  • β†’ Financial ledgers, event sourcing, auditing, and reactive frontend state stores

When to Avoid

  • ! Low-level graphics framebuffers or real-time physics engines where mutating a single pre-allocated 4K pixel array in-place is necessary