liveBook · Manning

Separation of data and behavior

As explained in F# in Action: A Revised Edition of Get Programming with F#

Separation of data and behavior is a design pattern in which data structures hold state while separate functions or modules implement operations on that state.

Separation of data and behavior models state with simple data types and puts operations in separate functions or modules. Rather than combining mutable fields and methods in a class, represent the current value directly and pass it to functions that return an updated value. This style favors composable, declarative code and keeps behavior independent of a type’s definition. section 2.1.3 section 2.8

A shopping basket without a stateful class

Model a basket as an immutable record containing its items. Place AddItem, Clear, and Checkout in a Basket module. Each operation accepts a basket, performs its work, and returns an updated basket instead of changing hidden internal state. The data remains a visible description of the basket; the module supplies the behaviors that use it. section 2.1.3

Use records, tuples, and unions to describe data shapes, then add simple functions only where a behavior is needed. This is especially useful when data changes shape over time: new behaviors can be created or removed without changing the source type. With immutability and expression-oriented code, attention can move from encapsulating mutable state to mapping data between shapes and handling boundaries such as databases and web APIs. section 10.1.2 section 10.7

A practical starting heuristic is:

  • Treat incoming and domain data as data, not as classes that must own behavior. section 10.1.2
  • Define records, tuples, or unions for the shape you need; use modules for operations over those values. section 10.1.2
  • Prefer immutable values and functions that return replacements when an operation changes state. section 2.1.3 section 5.7
  • Add members when OO features such as dot notation or overloading genuinely help, but begin with a clean split. section 10.1.2

The split does not require abandoning existing applications. In mixed F# and C# systems, keep F# expression-oriented, immutable, and organized around separate functions and data rather than imitating class-centered C# design. Introduce it through a horizontal tier such as data access, or implement a complete vertical slice in F# when avoiding cross-language compromise matters more. section 11.2.3

Figure 11.3 A horizontal tiers approach to introducing F# into a mixed-language application. Here, F# is used for all data access operations but is called from a C# layer on top.

A horizontal-tier layout illustrates one incremental adoption path: implement a shared data-access layer in F# while a C# layer calls it. section 11.2.3

How F# in Action: A Revised Edition of Get Programming with F# covers it

How deep it goes
Explains the pattern through an immutable basket example, modeling types, modules, and limited cases for members.
Examples
Uses a retail basket with AddItem, Clear, and Checkout, plus horizontal and vertical mixed-language application layouts.
What it assumes
Contrasts the approach with object-oriented classes while introducing the F# organization from that familiar starting point.
What you can do after
Apply it by modeling state with F# data types and placing change-producing operations in modules.
How it connects
Connects immutability, records, tuples, unions, modules, expressions, encapsulation, databases, and web APIs.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of F# in Action: A Revised Edition of Get Programming with F#. The section links point to the parts of the book it draws on.