Catalog / Data-Oriented Patterns / DOP: Separate Code from Data
DOP

DOP: Separate Code from Data

Code lives in pure functions; data lives in passive, transparent data structures without encapsulated methods.

Intent & Objective

Decouple data representation completely from behavior. Instead of locking data inside objects with private fields and member methods, treat data as plain, transparent records or maps, and place all business logic in pure, stateless functions.

πŸ‘₯ Real-World Human Analogies & Social Roles
1 Intuitive Scenarios
Restaurant Order Tickets & Kitchen Chefs Food Service

"The order ticket is a plain sheet of data with no methods. The chefs (code) read the data, prepare dishes, and print receipts without mutating the ticket structure."

The Problem

In traditional OOP, adding a new method to a domain entity (e.g. `User.exportTaxReport()`, `User.serializeXml()`) pollutes the class with foreign dependencies and forces recompilation of the entire object hierarchy. When two systems need to exchange data, OOP forces heavy object-relational mapping (ORM) and DTO conversions.

The Solution

Define data as plain transparent records (C++ structs, Python dataclasses/dicts, Java records). Write standalone functions in modules or namespaces that take data as input and return transformed data as output.

Key Participants & Architectural Roles

Data Entity / Record
Transparent, immutable holder of raw data with no behavior
Pure Functions / Calculations
Stateless logic operating on data structures: `(Data) -> Data`
I/O Boundary / Actions
Functions interacting with external systems (DB, API) to load/save plain data

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, data and logic are welded together inside class instances (`object.method()`). In Data-Oriented Programming (DOP), data and code are strictly separated (`function(data)`). This eliminates anemic domain model debates and allows business logic to evolve without altering data representations.

Advantages

  • βœ“ Infinite composability: any function can process any compatible data structure
  • βœ“ Effortless serialization to JSON, XML, or binary formats without reflection or custom mappers
  • βœ“ Trivial unit testing: pure functions only require passing input data and asserting output data

Trade-offs

  • βœ— Lack of class-level encapsulation means any code can read all data fields if not bounded by modules

When to Apply

  • β†’ Modern web services, microservices, and event-driven data pipelines
  • β†’ When the same data entity needs to be processed by dozens of different subsystems (billing, analytics, notifications)

When to Avoid

  • ! Stateful GUI widget toolkits where UI elements naturally encapsulate internal widget state and OS window handles