Loose Coupling and High Cohesion
Posted on August 20, 2016
How is it possible to design systems that can withstand the test of time by being able to accommodate developments in technology, and remain maintainable (meaning that changes, whether defect corrections or new features, can be made at a reasonable cost? Of course, there is no panacea here, and the second law of thermodynamics applies as much to software as it does physical and biological systems.
This is no mere metaphor. Entropy is a key concept in information theory, and not only is its definition analogous to entropy in physical systems, but there are genuine limits on the capabilities of computer systems that can be reduced to basic physics. But I digress, the principles of good software engineering are generally much more prosaic than the underlying physics of information systems.
Two basic principles that we will consider here are loose coupling and high cohesion. They may be briefly defined as follows:
- Loose coupling means that system components (for example, classes in object oriented systems) are as orthogonal as possible (meaning they can vary independently), interacting only through well defined interfaces.
- High cohesion means that system components are designed to focus on one activity or problem, and do not play multiple unrelated roles. In other words, the key idea behind high cohesion is: “Do one thing and do it well.”
If only the human body could follow these principles! Organs and body systems generally play many roles, and often interact in surprising ways. This is hardly surprising, given that humans evolved over approximately one million years, and life itself is about 3.6 billion years. That’s a long time, and in emergent systems, we generally expect complexity and clean separation of function is hardly to be expected.
But software systems are artificial creations, and it is not unreasonable that human designers can try to maintain an architecture consisting of loosely coupled components. Of course, it is true that software tends to grow organically, and over time, coupling will tend to become stronger, and system components will tend to become less cohesive. But that does not mean that we shouldn’t try to hold to the principles of loose coupling and high cohesion insofar as is possible.
Now, let’s try to look at how these principles apply to HIT, and for concreteness, let’s look at HL7 version 2. Much of the discussion will also apply to version 3. Both versions use the same “extension by restriction” model, and both are event driven. The chief difference is that much which is implicit in version 2 (e.g., modeling) is made explicit in version 3, and version 3 attempts to resolve ambiguities in version 2. A good example of how this is done is through the introduction of nullFlavor, which is designed to control how null values are interpreted in a systematic way; in version 2, null handling is mostly addressed in ad hoc fashion.
The event driven model of HL7 is a useful design pattern for building loosely coupled systems. The events themselves can be cleanly separated from the event handlers, or pieces of code that provide the actual implementation logic. This makes it relatively easy to add new events without the rest of the system being aware of the change.It is also possible to change the underlying implementation that handles the event (or in the case of HL7, processes the message). This is one thing that HL7 does particularly well. Incidentally, events are very explicit in HL7, but less so in other programming environments. Think of the use of callbacks in Java. They, too, are triggered by events (method calls), and the handlers are decoupled from the event source through explicit registration of callbacks. It’s interesting to note that in some object oriented languages (e.g., Smalltak), invoking a method is even called sending a message.
Of course, trigger events are only part of the picture in HL7. There are also the messages themselves, and this is where HL7 falls short in tems of loose e. Messages and segments represent certain information, such as provider information, and provider role (attending, performing,…) but it is not at all clear what is to be done with that information in the context of a given information system. Worse, the same messages and segments are used in multiple contexts, and what they mean depends, to a certain extent on that context. Conformance profiles, which are where we restrict the generic message definitions and specify how they should be used and interpreted in a particular context (use case).
Finally, this is really a cohesion issue. The messages, events, and segments in the HL7 specification are meant to be somewhat generic. So, from a modeling perspective, they lack cohesion in the sense that their use must be further restricted for use in a particular context. This is what is meant by extension by restriction.