Exploring creative ways of chaining patterns together into pattern application sequences.
After the SOA Design Patterns book was released last month, someone sent me a message congratulating me on producing the largest published design pattern catalog on record. It was an interesting revelation (albeit one I haven't confirmed) that made me think about why this, of all the design patterns books, turned out to be so voluminous. My conclusion was simply that it is a reflection of what service-oriented computing has become in mainstream IT. SOA adoption initiatives are larger, more ambitious and therefore also more complex than those based on past distributed computing models. As a result, there is a wider range of issues to tackle, for which (fortunately) we now have a wider range of proven design solutions.
That bit of praise was soon followed by a message with a different tone from someone overwhelmed by the patterns because there were too many. This reminded me of a reviewer comment I received during one of the final manuscript draft stages, where the feedback notes simply ended with the statement: "This book is just screaming for a methodology!" A catalog of this size does warrant extra guidance to help determine how and when patterns should be applied, especially when a particular problem state requires the application of multiple patterns.
Applying design patterns in combination is a relatively established practice that has been well documented in past books (such as those that are part of the Pattern-Oriented Software Architecture series from Addison Wesley). It is what constitutes a collection of patterns as a pattern language and allows us to explore creative ways of chaining patterns together into pattern application sequences.
In the SOA design patterns catalog there are pattern relationship diagrams that hint at a variety of application sequences for a given pattern. In this modest article series we cherry pick some of the more unique combinations to highlight the individual patterns involved and to document the benefits of their combined application. Let's begin by focusing on a pair of patterns that, on the surface, may appear to have very different purposes, but can, in fact, be successfully applied together to achieve a common goal.
Perhaps one of the most flexible and fundamental service design patterns is Service Fašade. It introduces the traditional notion of fašade logic into a service architecture, resulting in opportunities to establish different types of intra-service intermediary processing layers. There are many use cases for this pattern; however, the one we are interested in for this application sequence is that of runtime behavior compensation.
A service fašade component can be positioned between the underlying service implementation and the service contract as a decoupled buffer designed to preserve established behavior patterns that may be subject to change due to augmentation or refactoring of underlying service resources or logic. The service fašade's job in this case is to retain predictable behavior for the benefit of consumer programs that have formed dependencies on the service.
UI Mediator is also focused on behavior, but from a human's perspective. This innovative pattern (contributed by Clemens Utschig-Utschig, Berthold Maier, Bernd Trops, Hajo Normann, and Torsten Winterberg) aims to provide feedback and other forms of interactive logic to the presentation layer of a given solution, independently of what underlying services may be doing. To accomplish this, the mediator service is typically positioned between the user-interface and the controller service responsible for carrying out the majority of the service composition logic. When that service is unresponsive or provides insufficient interaction to make for a quality front-end experience, the mediator logic compensates for the benefit of the human user.
So, to recap, Service Fašade can protect consumer programs from behavioral service changes and UI Mediator can shield humans from inconsistent or non-communicative UI-to-service interaction. What then is the net result of applying these patterns together? The primary benefit is that you are establishing behavioral regulators at both ends (back and front). This can lead to a highly stable solution, capable of dynamically adapting to various runtime conditions that are not necessarily exceptions or errors, but simply unforeseen circumstances that provoke the solution to respond in unforeseen ways.
You have options as to how these patterns can be applied together. For example, fašade logic can be placed into the controller service at the top of a service composition hierarchy. The UI mediator service would then act as the consumer of this service (though it would technically be considered part of the overall composition) in order to liaise between the composition and various user-interfaces. Given the fact that one service composition can be comprised of agnostic services shared by other compositions, you may want to further require that any of these shared services also be outfitted with behavioral compensation fašades. This can add stability to any consumer that may have formed a dependency on the shared service, which ultimately increases its reuse and ROI potential.
But what if you don?t have a complex service composition, but instead you just have one service that needs to act as a UI mediator and needs to be positioned as a consumable and reusable resource? You can certainly apply both patterns to the same service. The only recommendation is that the respective processing layers (back- and front-end) be physically decoupled into separate components.
We've been exploring a simple example of a pattern application sequence where the outcome of applying two specific patterns together is a specific target state that we could refer to as Two-Way Behavioral Stability. Incidentally, this could also be the name of a compound pattern comprised of the joint application of Service Fašade and UI Mediator. But that's a topic for another day...