An Inter-Service
Coupling Index for Lossless Exchanges
By Jeff Schneider
Copyright, Momentum Software Inc.
November 2003
Warning
This paper is not an
academic, proof-oriented paper. Rather it is a practioners view on the state of
coupling in a distributed computing world. The formulas in this paper are
designed to convey potential impacts and should be viewed as conceptual
guidelines only.
Introduction
Coupling is a term
that is used to describe the breadth and depth of dependencies between two
entities. A significant amount of effort has been applied to determining the
attributes that couple software entities. The computer software community has
been striving to create packages of highly cohesive modules that communicate
between themselves in a loosely coupled fashion. Much of the recent work has
focused on coupling within object-oriented systems, usually relating to a
single application written in a homogenous environment. Thus measurements
related to 'class coupling', 'inheritance coupling' and the like were
prominent. Web Services and the contract-based programming model have pushed
the level of abstraction and offer one potential answer to the ongoing coupling
dilemma.
This index has been
created with web services and service oriented architectures in mind and thus
will likely have biases towards measuring those types of systems. The creation
of a quantitative index for capturing what most scientists believe is a
qualitative attribute may likely be an academic exercise. However, my goal is
to call out that certain variables will affect the coupling of systems and
should be given attention during the design phase. In addition, a fundamental
belief that I hold is that 'intermediaries', if introduce-able at runtime, have
the potential of bringing a coupling index to an unprecedented low level. This
concept is conveyed via 'Intermediary Decoupling’; where-by, other coupling
concerns are mitigated by the use of one or more 'intermediaries'.
All formulas mention
hereafter are introduced only to convey one potential way of capturing a
coupling factor and by no means should be considered a firm rule for the
quantitative measurement of coupling. Rather, they should serve as a new
starting point for others to consider, revise and extend upon.
The Service
Coupling Index
Coupling can be viewed
from many angles. This paper pays extra attention along three dimensions: 1. Design-Time Issues vs. Run-Time 2. Code-base Issues vs. Use Case Based and
3. Consumer Side vs. Producer Side
To date, coupling
metrics have largely focused on 'design time' issues. That is, the measurement
of dependency is observed by statically analyzing the code. In this instance,
the code 'states' what it can and does communicate with. However, this type of
metric becomes less important in a service and message based architecture.
Services have the ability to send out messages, which can be altered,
translated or re-routed. This switches the focus from 'what the code says it
does' to 'what the network can make it do'. Thus, the level of coupling in
software componentry is directly affected by the intelligence of the service
network in which it resides. In an intelligent service network, a consumer and
producer can dynamically resolve their differences by introducing new services
that act as intermediaries to resolve disputes.
The second issue of
coupling deals with the scope in which we care to measure the coupling. To
date, most of the efforts have taken a static analysis of all dependencies (or calls)
between two software entities (taking into account the entire code base).
Although this is a fair scope, I believe that an equally insightful measurement
can be taken by reducing the scope from 'all the code' interactions to 'only
the code utilized to fulfill a use-case'. With a use-case approach, we can more
accurately look at coupling based on fulfilling some intent.
The third issue
focuses on 'where' the coupling takes place. Can a service be designed in a way
where it invites tight coupling? Can a consumer be written in such a manner as
to increase the coupling on a specific service? My belief is, "yes"
on both accounts. Although coupling usually occurs as an instance of a
collaboration path between systems, it is possible to identify some of the
design time problems that invite tight coupling without ever looking at the
producer/consumer relationship or at the runtime message instances.
In order to determine the coupling level
between two entities, consider the following formula. Where, 'User Weight' is a
value defined by the user of the system to weight the influence of that piece
of the architectural concern.
For a given use case
(or intent), determine:
((Intermediary Decoupling *
Standards Coupling * User Weight1) +
(Intermediary Decoupling *
Granularity Coupling * User Weight2) +
(Intermediary Decoupling *
Contract Coupling * User Weight3) +
(Intermediary Decoupling *
Abusive Coupling * User Weight4))
where a lower score =
more loosely coupled
Granularity
Coupling
Granularity Coupling
is concerned with the ability for a service to have an efficient conversation
in both local and distributed mode. Historically, modules were optimized to
either be a local call with a fine-grained interface or a remote call with a
coarse grained interface. With the introduction of services and their potential
to be relocated closer to each other, it becomes important for a service not to
be designed with a single granularity design. By offering both coarse and
fine-grained interfaces, the service can become more tolerant to the latency
issue. The assumption is that the
granularity design of the service is made with no knowledge of latency between
itself and other dependent services. The producer-consumer relationship has the
responsibility of performing run-time negotiation on which granularity level to
use. It can be successfully argued that
some services will only have one 'correct' coupling level and in such cases,
only the appropriate offering should be provided and from an index perspective
no points should be deducted.
For Each Potentially Bi-Granular
Operation, calculate:
(2 - (a coarse grained
interface? Yes =1, No = 0) -
(a fine grained interface? Yes = 1, No = 0))
Note: Agreeing on what
is fine grained and what is coarse grain is yet another issue. One rule of
thumb is to only consider calls with primitive data types as examples of
fine-grained calls.
Standards Coupling
Web Services, as well
as most modern distributed computing techniques, have become significantly
dependant on the use of protocols or standards to enable the communications
between heterogeneous participants. As the number of required protocols or
standards increases, so does the coupling. However, the increase in coupling is
also related to the ubiquity of the protocol implementations or the ease in
which a substitute can be located. As an example, communication via the WS-I
basic profile may require a handful of protocols or standards (e.g., tcp/ip,
dns, http, url, soap 1.1, wsdl 1.1., uddi 2.0, XML Schema 1.0, etc.) Many of
these protocols / standards are very ubiquitous (tcp, dns, etc.) Conversely, an
implementation may require more advanced protocols (ws-reliableMessaging,
ws-atomicTransaction, ws-PolicyAttachment, ws-PolicyAssertion, etc.) In these
cases, the installed implementations between communicating partners may be less
ubiquitous. In addition to base
transmission protocols, one must consider the other standards that may be used
in the communications. This will include potential parameter values (passing in SQL, XQuery, XPath, etc.)
Another form of standards coupling deals with language or platform assumptions
(e.g., two systems are coupled if they demand using the same language or the
same platform).
For Each Standard, find the
lesser value:
(1- (the ubiquity of the
standard within a community, percent of participants (0 : 1) *
(How standardized is the
standard?, percent of standardization (0 : 1))) OR
(Repeat: Standards Coupling (a
valid substitution)))
Note: At first it may
appear difficult to determine the ubiquity of a given standard or protocol.
However, the tools and techniques to create an inventory of the capabilities of
the services (standards, protocols, versions, etc.) will be required to make
loose coupling in service networks plausible. During the incline of the web
era, programmers built crawlers to scan capabilities of web servers; the same
concept will likely be applied to the web services world. The only difference
is that the results of the 'ubiquity crawlers' will likely be provided as a service
and feed intermediaries information on how to provide dynamic resolutions.
Contract Coupling
Contract Coupling is
concerned with the interface encapsulation of the service. The interface
between the service and the consumer of the service is a contract - and not all
contracts are created equally. Services
that require information to be passed in which is difficult to obtain increases
the coupling level. Conversely, a service that can be called without internal
knowledge of the system enables looser coupling. If a service were to require
some piece of unknown information (e.g., a foreign key) and no means to obtain
the information (e.g., a foriegn key lookup), then the coupling is increased.
If a service were to provide 'helper operations' to retrieve the hidden
information, then the coupling is decreased.
The essence of Contract Coupling deals with the constraints related to
the parameters of the call. If a parameter has an enumerated set of valid
options, they should be communicated. If the acceptable parameter values are
based on other parameter values, than that should be conveyed. Failure to
convey information related to a successful invocation leads to increase
coupling. Currently, a significant amount of information about a web service
contract is published in the WSDL, the message schema or extensions like a
policy. However, these facilities do
not ensure loose coupling, rather they just provide the means to do so; the
responsibility of correct utilization falls on the service designer.
For Each Required
Operation, sum (Ability to ascertain parameter call information), where:
(Fully reflective or
interrogate-able through contract = 0,
human ascertainable = .5,
unobtainable without knowledge
of internal system = 1)
Note: Change weights as
appropriate (0-1)
Abusive Coupling
In addition to the
regular coupling issues that deal with contract (both functional and
non-functional), there are a number of issues that directly affect system
performance. Even though the interface between consumer and producer are clean
(or loose), it is still possible to misuse the contract. There are five
well-known abuses in contract-oriented programming that should be considered:
1. Chatty Conversations - Chattiness is a
measurement of the breadth of the message exchanges. It can be viewed as the number of calls between XY, from X to Y,
or Y to X to fulfill some intent. In lossless exchanges, it is possible to
define message exchange patterns that are so verbose that they increase the
coupling between the entities. Previous work defined this measurement by
counting inbound or outbound function calls.
2. Fatty Messages - Fatty messages are those messages with too much information
being passed between participants. Prior work referred to this concept as
‘Stamp Coupling’ and places it as a primary concern. Today, I believe less
emphasis is placed on fatty messages for two reasons: 1. The introduction and
ubiquitous spread of grammars like XML enable systems to pass fatty schemas
without the other party having to be fully informed on those portions of the
schema in which they may not be interested. 2. System (network, cpu, disk)
performance appears to be increasing at a rate greater than the increase in the
fat of the messages. The issue that remains is that of increasing complexity
and programmer error. Thus, fatty messages often reveal too much information,
making the consumer of the message confused on which information they should be
working with and which information should be ignored.
3. Time Bound Conversations (synchronous) -
Time Bound Conversations are those that demand a specific synchronization
scheme. That is, they demand for the messaging to be either synchronous, or
asynchronous. In many cases, a service could be designed to have both synch and
asynch capability (a bi-synchronous service), however, most designers will
choose one or the other - thus limiting the flexibility of the system. I've
fought on many occasions to throw out the issue of time bound conversations as
an issue of coupling. However, the fact is that the issue remains just that, a
real issue. My belief is that time-bound conversations have the potential to be
remedied via an intermediary (and often are). However, the vast majority of
system communication architectures do not deploy this as part of their base
patterns. Thus, I am including it as part of 'abusive coupling'.
4. Interface Fragility
- Inteface Fragility deals with the impact of extending or modifying the
interface so that the consumers of the interface will have minimal impact. In modern programming models, a software
consumer is coupled to the interface of the producer. The impact of the
coupling changes based on the ability to absorb interface changes. Thus, if
even a small change in an interface (like an extension) causes the entire
interface to break, the interface would be considered very fragile.
5. Fixed Invocation
Models - The Fixed Invocation Model issue is a consumer-side problem. By
programming to a specific and perhaps limited invocation model, the coupling is
increased. For instance, if a program were to specify the use of JMS to send
messages, certain assumptions about the synchronicity or platform may be
implied. These implications may limit the flexibility of the calling structure
and increase the dependence on specific API's. As an alternative, an
invocation-meta-model is a preferred method of overcoming fixed call
structures. Here, the invocation model is described as runtime metadata and the
invocation is assembled at runtime.
For Each Operation,
calculate:
((Chattiness * Weight1) + (Fatty
* Weight2) +
(Time Bound * Weight3) +
(Fragility * Weight4)
(Fixed Invocation Model * Weight
5) / 5)
Where: Chattiness is, 1 call = 0, 2 calls = .33, 3 calls = .66, 4 or more calls = 1
Fatty is, (1 - percent of (0 : 1) of the message
document that is actually needed in the communication)
Time Bound: Bi-synchronous services with both asynch and
synch implementations available = 0
Bi-synchronous
services with only 1 implementation available = 1
Uni- synchronous
services with the correct implementation = 1
Uni- synchronous
services with the incorrect implementation = 0
Fragility is the percent of the
consumers that will be adversely effected by a random, yet valid change in the
interface (0 : 1)
Fixed Invocation Model: (1 –
(#
of the permutations in the community covered by the invocation model) /
(#
of permutations of standards found in the community) )
Intermediary
Decoupling
A significant number
of tools and techniques are used and often standardized in modern distributed
computing. A non-exhaustive list to consider includes, encryption, hashing,
signing, windowing, addressing, reliability, transactional capability, message
encoding, enveloping, negotiation capability, self-morph-ability, inspect-ability,
compression, streaming, caching, etc.
As previously mentioned, Standards Coupling relates to the aggressive
use of standards to create an effective communication path. It doesn't concern
itself with the 'failed scenario'. Intermediary Decoupling deals with the
ability to swap out a protocol or standard on the fly (at run-time, not design
time). Thus, if two parties wish to communicate and their predetermined
protocol matching fails, they have the ability to introduce an intermediary
(translator, fail over service, proxy, etc.) to fulfill the original
communication requirements.
For
Each Call, sum(ability to dynamically resolve the communication
conflict)
Note: Intermediary
Decoupling will likely rely on the use of a dynamic addressing scheme to route
information at runtime. This includes return paths or callbacks.
Conclusions
This paper looks at
coupling as it relates to web services and service oriented architectures. It
acknowledges the concepts of modern architectures like common grammars for schemas,
network protocols, services, interface definition languages, dynamic policies
and the like as potential decoupling devices. It also promotes the use of
'intermediaries' to remedy many of the coupling issues related to the growing
number of protocols and standards that are now required to communicate in a
'loose' fashion.
On a personal note, it
is my belief that just as educated software intermediaries can help reduce
Standards Coupling, additional automated intermediaries will be able to
mitigate the effects of Abusive Coupling, Granularity Coupling and Contract
Coupling. And through 'educated networks', software modules will be able to
automatically refactor themselves across the network to loosen or tighten their
relationship as needed. It is my opinion that the software community should
place increasing attention on methods to enable the dynamic structuring of
software across a network, with the structure of that software controlled by
the network, not the programmer.
This paper has limited
the focus on ‘recipe based’ programming. That is to say that additional
decoupling can likely be found by reducing the amount of ‘recipe information’
(the ‘how’ aspect), rather than the intent or goal of the communications. Modern programming languages tend to focus
more on the set of calls necessary to fulfill some use case. Advances in
intentional and generative programming make offer a new level of decoupling.
In addition, this
paper was limited to ‘lossless exchanges’. These are message exchanges where
both parties agree to only communicate as long as the syntax of the
conversation is fully agreed upon in advance. The belief is that this type of
‘all or nothing’ contract will reduce the potential for miscommunications.
However, most biological exchanges are not ‘lossless’ rather they are ‘lossy’.
In this manner, if two parties fail to understand a conversation, they ask for
clarification or bring in a third party to resolve misunderstandings. In addition, the guarantee of syntactic
agreement does not imply the guarantee of semantic agreement. Which, could be
argued is actually more important.
Advances in ‘lossy exchanges’ will likely take decoupling to a whole new
level.
Acknowledgments
I'd like to thank the
following people for providing valuable feedback: James Iry, Sean McCullough,
Doug Kaye and David Orchard. In addition, much of this work was influenced by
the book, "The Practical Guide to Structured Systems Design" by
Meilir Page-Jones which built upon many of the concepts of "Structured Design"
(Yourdan and Constantine).