User:DKinzler (WMF)/Coupling

Types of Coupling in Software Systems, as seen by Daniel.

Static (Interface) Coupling
X is statically coupled to Y if X relies on the interface and contract of Y. When the interface or contract of Y changes, X has to change as well.

In an object oriented language, this would be the case when X calls methods on a variable with the declared type Y, relying on the behavior specified by its contract. Similarly, In a service oriented architecture, this would be the case if X sends requests or messages to a service with contract Y.

This kind of coupling can easily be discovered by static analysis. It is transitive only to the extent that additional types are used in the interface definition of Y, so they are needed in order to communicate with Y.

If X is statically coupled to Y, this implies a behavioral (and often dynamic) coupling to some concrete implementation Z of Y.

Dynamic (Causal) Coupling
X is dynamically coupled to Z if a defect in Z will cause a defect in X. When the implementation of Z changes, tests for X have to be run to assert that all expectations are still met.

In an object oriented language, this would be the case when X calls methods on an object of concrete type Z. Similarly, in a service oriented architecture, this would be the case if X sends requests or messages to the concrete service implementation Z.

This kind of coupling can be discovered by static analysis if all implementations of an interface Y are known: if X is statically coupled to Y, then it is coupled to the behavior of all implementations of Y.

Behavioral coupling is fully transitive: if X uses Z, and Z uses W, a defect in W may also cause a defect in X.

Note that behavioral coupling typically, but not necessarily, implies a dynamic coupling as well. A counter-example is a distributed system that uses message queues for communication: while the recipient of a message is known and a certain behavior is expected (behavioral coupling), the performance of the recipient does not affect the sender (no dynamic coupling).

Runtime (Performance) Coupling
X is runtime-coupled to Z if the performance of Z impacts the performance of X. In particular, this is the case if X has to wait for Z to complete a task before it can continue its own operation. This also implies behavioral coupling: when Z is down, X cannot function.

Function calls within a process always constitute dynamic coupling. Communication with another service constitutes dynamic coupling if that communication is synchronous. Not that asynchronous communication may still constitute behavioral coupling, if the sender relies on some behavior of the recipient of a message.

In an event driven architecture, the coupling is reversed: the event source is not coupled to any of the listeners, but the listeners rely on the functioning of the event source, and have to wait for it to generate events. So the event listener is coupled to the sources contract (static), behavior (causal), and performance (dynamic).

Dynamic coupling between services can easily be discovered based on a topology specification that identifies the type of all communication channels between services.

Operational (Deployment) Coupling
X is operationally coupled with Y if a new version of X is deployed or released together with Y. Units of operational coupling are typically things like source code repositories, container images, or library packages. They can also be understood as units of versioning.

Operational coupling is generally applied intentionally, by bundling together components that are statically, behaviorally or dynamically coupled. Releasing and deploying them together ensures that they are used in a known and tested configuration.

Operational decoupling requires careful management of stable interfaces between the components, so updates do not cause defects due to incompatibility.

Data (Schema) Coupling
X is data-coupled to Y if it consumes the persisted output of Y. For example, X reads a file generated by Y.

Schema coupling is common and not problematic if done intentionally and properly. However, it is extremely brittle if the data format is not designed and maintained as a stable interface by the producer. For instance, if X queries a database that is defined by Y, it is quiter possible that Y changes the schema of the database without notice, breaking X.