IV. Assert Autonomy

Design components that act independently and interact collaboratively

The components of a larger system can only stay responsive to the degree of autonomy they have from the rest of the system. In Reactive applications, autonomy is achieved by clearly defining the component boundaries, who owns what data and how the owners make it available, and by designing them such that each party is afforded the necessary degree of freedom to make its own decisions.
When a service calls upon another component, that component must have the ability to communicate back momentary degradations, for example, caused by overload or faulty dependencies. And it must have the freedom to not respond when that is appropriate, most notably when shedding heavy load. This requires the protocol between these components to be asynchronous and event-based, even when the used API looks synchronous — after all, we can only contain component-level failure when the protocol foresees the possibility of unsuccessful or late responses.

Another aspect of autonomy is that the boundary between the two components is crossed only via the documented protocols; there cannot be other side-channels. Only with this discipline is it possible to reason about the collaboration and potentially verify it formally (for example using Session Types new tab). Many times the protocol will be trivial, like the request-response new tab message pairs, but in other cases, it may involve back-pressure (as in Reactive Streams new tab) or even complex consensus protocols between multiple parties. The important part is that the protocol is fully specified, respecting the autonomy of the participants within the communication design.

Valuable patterns that foster autonomy include: domain-driven design new tab, event-sourcing new tab, and CQRS new tab. Communicating fully self-contained facts — modeled closely after the underlying business domain — gives the recipient the power to make their own decisions without having to ask again for more information. CQRS separates concerns by making decisions about one part of the system in one location (one component), which can then readily be disseminated and acted upon elsewhere—possibly at a much later time.