When Functional Pipelines Meet Domain Objects - Part 6: An Example

To test that a domain-first OO approach sustains development speed and simplifies complex systems, I asked an AI to provide a scenario where functional programming would outperform OO. Its choice: real-time fraud detection for an online payment platform.
At first glance, this looks like a natural fit for functional programming. The system ingests high-volume event streams (user ID, amount, timestamp, merchant, location) and transforms them to detect suspicious patterns. Functional languages shine here: immutability, stateless transformations, and concurrency align with the idea of streaming data through a pipeline of pure functions.
In this functional design, events are immutable facts passed through filters and mappers:
- filterRecentEvents narrows events to a timeframe
- computeFeatures calculates distances, counts, or aggregates
- scoreRisk assigns probabilities
- flagSuspicious takes an action
These functions compose neatly:
detectFraud = compose(filterRecentEvents, computeFeatures, scoreRisk, flagSuspicious)
It’s elegant, predictable, and highly concurrent. But notice the paradigm: new data is always pulled through the pipeline. Detection only happens as long as data is being streamed and transformed.
Reframing with OO: Fraud as Domain Knowledge
The OO perspective shifts focus from pipelines to the domain itself. Fraud isn’t just a flow of transactions—it’s a set of scenarios that criminals play out. Transactions remain immutable facts, but the “what” is fraud patterns.
So the domain model would be:
A 'Pattern' object - e.g., “distance > 1000km AND count > 5”
A 'Scenario' object (e.g., HighDistanceScenario) that link multiple Patterns
A 'Cursor' object to retrieve and group relevant data (time windows, user accounts, merchants)
But here’s the turning point: once Scenarios and Patterns exist as objects, they stop being passive code.
Patterns persist* as standing definitions, continuously evaluating incoming data.
Scenarios become stateful detectors* that accumulate evidence and trigger alerts.
* Knowledge is reusable: as new Patterns evolve, historic data can be re-evaluated without loss.
What began as a “pull pipeline” becomes an active domain model that operates continuously, interactively, and historically—all without changing the core logic.
Why OO offers more benefits
Functional programming offers composability and concurrency, but it distributes fraud logic across stateless functions. As the number of scenarios grows, oversight and adaptability suffer.
OO, by contrast, centralizes logic in domain objects:
* Fraud knowledge is legible and traceable (Scenarios encapsulate their meaning).
* Reuse accelerates development (Patterns can be shared across Scenarios).
* Adaptation is easy (add a new Pattern, swap out a Cursor backend).
* Domain experts could even assemble Scenarios themselves from existing Patterns.
Most importantly - the domain model changes how the system can run.
- Functional: always pull new data through a stream.
- OO: the same logic also supports continuous monitoring, re-checking historic data, or interactive exploration.
That’s the effect of OO: the search for the ‘what,’ and the ‘how’ expands beyond what you initially wanted to achieve in ways that improve the system..






