3. Isolate Mutations
Contain and isolate mutable state using bulkheads
When you have to use mutable state, don’t share it. Instead contain it together with the associated behavior, using isolated and partitioned compartments, separated by “bulkheads” and thus adopting a shared-nothing architecture. This contains failure, prevents it from propagating outside the failed component, limits its scope, and localizes it to make it easier to pinpoint and manage. It also avoids minor issues leading to “cascading failures” and taking down an entire system. For example, recall that validation errors are not failures but are part of the normal interaction protocol of your stateful component.
Bulkheads are most easily installed by having the compartments communicate using asynchronous messaging, which introduces a protocol boundary between the components, isolating them in both time and space. Asynchronous messaging also enables observing the fluctuating demands, avoiding flooding a bulkhead, and providing a unit of replication if needed.
Only use mutable state for local computations, within the consistency boundary of the bulkheaded component—a unit of consistency that provides a safe haven for mutations, completely unobservable by the rest of the world. When the component is done with the local processing and ready to tell the world about its results, then it creates an immutable value representing the result—a fact— and publishes it to the world.
The bulkheaded components should ideally use single-threaded execution to simplify the programming model and avoid concurrency-related problems such as deadlocks, race conditions, and corrupt data. For example, Node.js, Akka, Disruptor, or implementation of the Reactor Pattern and its variants offer this functionality.
In this model, others can rely on stable and immutable values for their reasoning, whereas each component can internally still safely benefit from the advantages of mutability (like the simplicity of coding and algorithmic efficiency), strong consistency (providing ACID semantics), and reduced coordination and contention (through the Single Writer Principle ).