Temporal and Behavioral Coupling
Coupling is "the degree to which each program module relies on each one of the other modules". Low coupling is typically a sign of a well-design implementation supporting the general goals of high readability and maintainability.
In his new post Ian Robinson explores how different distributed systems design approaches - Distributed 3-layer, Command-oriented, Event-oriented and Emergency services - impact two specific types of coupling: temporal and behavioral.
He starts by defining temporal coupling as:
... the degree to which the sending and handling of a message are connected in time. If a sender is dependent on a receiver being available when a message is sent, we have high temporal coupling... Processes whose activities are strictly ordered or whose results carry forward, leaving subsequent activities unable to start until a response to a prior request has been received, are similarly temporally coupled.
And behavioral coupling as:
...the degree to which parties share assumptions regarding behaviors, more specifically, to the implications of assigning the twin responsibilities for determining what action to execute and how to execute that action to the parties in a distributed interaction. In systems that exhibit an extremely high degree of behavioral coupling, the sender of a message determines what to do, and also knows something of how the receiver ought satisfy its request... High behavioral coupling requires a provider to evolve its service offerings in response to changed consumer requirements.
When a traditional 3-layer architecture is used for building of distributed systems (Distributed 3-layer), it is typically implemented using synchronous interactions (even when asynchronous messaging is used as a transport), typically leading to a high temporal and behavioral coupling. In this case:
Senders tell receivers what to do; receivers execute the sender’s orders. Sender and all intermediaries block until the call stack unwinds, effectively locking and/or consuming system resources further up the call chain. This blocking behavior undermines the autonomy of upstream components and at the same time increases the availability requirements of downstream components... in these circumstances the availability of the overall system can be no more than that of the least available participant, and the probability of failure is the joint probability of failure in any component or service.
Usage of the Command-oriented design typically allows to lower the degree of temporal coupling, especially when asynchronous interactions are used. Coupling can be lowered even further by implementing a "resumable" programming model common for orchestration engines implementations. In this design:
Senders typically determine what needs to be done, but rely on receivers to determine how to execute their instructions. This behavioral coupling can require providers to evolve (message formats, supported operations) in lockstep with changing consumer demands.
Lowest degree of both temporal and behavioral coupling can be achieved in the case of the Event-oriented design, especially when it is coupled with a "resumable" programming model:
Receivers determine both what needs to be done and how to do it based on the content of received messages. Can be difficult to trace the execution path of an end-to-end transaction or activity. Exposing an "ExtinguishFire" operation is a command-oriented way of executing a business process; acting on "FireStarted" notifications an event-oriented approach.
Finally Emergency services design is characterized by implementing a set of services, receiving information about what has happened and deciding what to do in any particular situations. This design is characterized by very low behavioral coupling, which allows for the independent evolution of emergency services implementations, but a higher degree of temporal coupling - someone has to be there to react at the given situation. Many RESTful solutions are based on this design.
URI-templated solutions have a higher degree of behavioral coupling than hypermedia-driven solutions (where servers constrain and guide what a client can do next, and determine how best to satisfy requests); client polling and caching can mitigate some of these temporal coupling issues.
The post provides an interesting analysis of impact of distributed systems design approaches on the coupling of the resulting systems. Unfortunately not all of Ian’s conclusions seem to be correct.
When it comes to temporal coupling the answer is quite straightforward - synchronous interactions (not communications) lead to strong temporal coupling, while asynchronous ones lead to low temporal coupling. Because any of the design approaches described in the post allow for use of both, it is not the design approach but rather the interaction used inside design that defines the temporal coupling characteristics of the resulting system.
When it comes to behavioral coupling, the issue becomes slightly more involved. First of all, there are several slightly different definitions of behavioral coupling, for example:
Behavioral coupling is a sub-form of Content Coupling but instead of accessing local data within the two pieces of code one module is restricted because of how another module is implemented (i.e. behaves).
If this definition is accepted, then the most common solutionfor the behavioral coupling is an intermediary that shields one of the participants from behavioral effects of the other.Again, such intermediary can be used regardless of the design approach.