ADR 0013: Async Classes For Orchestration, Pure Functions For Analysis¶
Status¶
Accepted
Date¶
2025-02-05
Context¶
Two different kinds of code coexist in IRIS:
- orchestration code that coordinates repositories, units of work, adapters and side effects;
- analytical code that transforms already-loaded inputs into deterministic decisions or metrics.
Trying to force one object model onto both layers caused confusion:
- orchestration code became under-structured when written as free functions;
- analytical code became over-engineered when wrapped in async service objects only to perform pure math.
Decision¶
IRIS uses async-class-first orchestration and pure-function-first analytical engines.
The practical rule is:
- orchestration services may be async classes with injected repositories/adapters and explicit lifecycle boundaries;
- analytical engines should default to pure functions and typed contracts;
- stateful or async engines require an explicit justification, not convenience;
- service modules should not absorb analytical helpers that belong in an engine package.
Consequences¶
This preserves the right abstraction at each layer:
- orchestration stays explicit about dependencies and write boundaries;
- analytical behavior stays easy to test and reason about;
- the codebase avoids “everything is a service class” and “everything is a loose helper” extremes;
- the canonical
signalssplit remains the reference pattern for later domains.
See also¶
- ADR 0009: Signals Service/Engine Split — canonical example
- ADR 0011: Analytical Engines Never Fetch — pure function constraint