Understanding Architectural Coupling
How we identify and view coupling at an architectural level, opposed to that of a single service, requires an abstraction at a higher level
Types of Coupling
Coupling comes in many variations and can sneak into a system if care is not taken. Within Software Engineering we can generally say that coupling is -
the degree of interdependence between software modules; a measure of how closely connected two routines or modules are [1]
To break things down in more detail we have -
Data Type Coupling
Content Coupling - Directly accessing and changing the data in another module
Common Coupling - Two modules sharing a global data structure
Data Coupling - A module passing data into another module through parameters or global data
Functional Type Coupling
Control Coupling - A module controlling the flow of execution in another module
Stamp/Temporal Coupling - Depending on the order of execution of other modules
Functional Coupling - A module's output becomes another module's input
Platform Type Coupling
Message Coupling - Communicating through a shared message-passing interface
Interop Coupling - Modules are dependent directly on a single platform's technology or protocols
But what does this look like as we take our level of abstraction higher?
Coupling Boundary
As we look at Distributed Software Systems we need a higher level of abstraction to examine the coupling between elements. This abstraction is known as the Architectural Quantum. An Architectural Quantum is defined from one perspective as an "independently deployable artifact, with high cohesion, high static coupling and synchronous dynamic coupling" [2]
The relationship to coupling is clear and we can define a Quantum as a bounded system exhibiting, high static coupling and synchronous dynamic coupling. These forms of coupling force the bounded system to be deployed as a unit that may eschew high cohesion.
Coupling, therefore, can cross even well-defined domain boundaries of microservices. Boundary crossing is what causes friction between teams and complex release strategies. Recognizing the underlying Quantum will enable us to eliminate unnecessary dependencies.
The Razor - Knowledge Discipline
Architecting a complex software system, specifically applying Continuous Architecture, is all about managing volatility and maximizing the Quality Attributes of the system. Minimizing and analyzing coupling comes down to Knowledge Discipline*.*
Knowledge Discipline - Knowledge, being both data & behavior, creates Architectural Quantum boundaries defined by singular ownership.
Singular ownership of Knowledge means that only one Quantum can be the source of truth for a domain's behavior or data. Let's look at a tightly coupled eCommerce example.
Knowledge Discipline - In Action
We'll look at the order placement system of, my favorite, Widgets Inc. Below it's clear the Order Service should not be orchestrating the downstream processes.
The Order Service has knowledge of the Inventory Domain/Service, also, it's aware of the Notification Service. Even worse, the Inventory Service is "validating" the Order for the Order Service based on its known inventory.
Due to the extraordinarily tight coupling among all three services, this system becomes a Distributed Monolith. Regardless of service breakdown, the tight coupling forms a single Quantum that must be deployed as a unit. Changes in one system ripple through others. If the individual services cannot be independently deployed, they're not "microservices" anymore. The monolith is simply further apart.
What a mess huh? Let's apply some Discipline between domains ๐ค
Here, both the Order & Inventory Services listen for an Order Placed event. Independant of one another they execute their Domain Responsibility. The Order Service records the Order and the Inventory Service updates the Inventory. Neither knows anything about the other. The Notification Service recognizes the two resultant downstream events: Order Recorded & Inventory Updated. Independently of any source of these events, the Notification Service executes its responsibility.
We have, however, traded the Data & Control Coupling for Platform Coupling in the form of a Message Broker. This is a tradeoff we can live with and the reason why comes down to volatility.
The Message Broker we've introduced offers a distinct and high 9s SLA. Also, as infrastructure, it's subject to very little change. New and evolving Business Requirements have none to little effect on the Broker. This provides us the tradeoff of depending on a Message Broker and in return, our domains become independent from one another.
Wrapping Up
Applying Knowledge Discipline gives us a technique to determine if there's an undesired coupling between modules. By identifying knowledge that has multiple owners we can identify hot spots of coupling. Slicing our system in terms of knowledge ownership keeps bounded data & behavior independently deployable and executable.
[1] Wikipedia contributors. (2022, May 6). Coupling (computer programming). Wikipedia. https://en.wikipedia.org/wiki/Coupling_(computer_programming)
[2] N. Ford, M. Richards, P. Sadalage, Z. Dehghani, Software Architecture: The Hard Parts. Sebastopol, CA: O'Reilly, 2022