A mutable shell handles state changes, side effects, and communication with external systems around a functional core. It gathers inputs, passes them to the core, and turns the core’s decisions into visible effects. section 6.3 section 6.6
Keep the shell deliberately small:
- Gather external data without making additional business decisions. section 6.3
- Give the functional core enough information to make complete decisions. section 6.3
- Represent decisions explicitly as outputs such as file updates, commands, or messages. section 6.3 section 6.4
- Apply those outputs through databases, filesystems, buses, or other external dependencies. section 6.3
Refactoring an audit system
A filesystem-bound AuditManager reads files, decides where a visitor record belongs, and writes the result itself. Refactoring moves the decision into a pure AuditManager that accepts FileContent values and returns a FileUpdate. Persister reads the directory and applies that update, while ApplicationService coordinates the read-decide-act sequence. The resulting test compares the returned FileUpdate directly instead of configuring a filesystem mock. section 6.4
The pattern improves testability and maintainability by concentrating complexity in output-driven business logic and leaving fewer integration tests around effects. It adds code and may reduce performance, so apply it when system complexity and importance justify the investment; do not pursue architectural purity at any cost. section 6.5 section 6.6
