A common association to the term "Architectural Patterns" is to think about some of the patterns discussed in Buschmann et al.’s Pattern-Oriented Software Architecture [POSA 1]. In that book there are a couple patterns gathered under the category called Architectural Patterns. Examples of the patterns are Pipes and Filters and Reflection.
Pipes and Filters are about channeling data through Pipes and processing the stream in Filters. Pipes and Filters have been picked up by the SOA community as a useful pattern for message-based systems.
Reflection is built into both Java and .NET, making it possible to write programs that read from and write to objects in a generic way by only using the metadata of the objects (not knowing anything about the type of the object beforehand).
If Design Patterns is about refining subsystems or components, Architectural Patterns is about the structuring into subsystems. To make it more concrete, let’s take a common example, Layers [POSA 1].
An Example: Layers
Layers or layering is a basic principle when it comes to architecture, which means to factor out responsibilities into separate cohesive units (clusters of classes) and define the dependencies between those units. Most developers are reasonably familiar with this.
Because it’s such a commonly used and well-understood pattern, we will just give a quick example of it here to give us a feeling of the pattern category.
Assume we have built a set of classes for a SalesOrder application, such as -Customer, Order, Product, and so on. Those classes encapsulate the meaning they have for the Domain, and also how they are persisted/depersisted and presented. The current implementation is to persist to the file system and to present the objects as HTML snippets.
Unfortunately, we now find out that we need to be able to consume the objects as XML as well and to use a relational database for persistence.
Solution Proposal One: Apply Layers
The most common solution to this problem is probably to factor out some of the responsibilities of the classes. The new requirements made it obvious to us that the classes were clearly breaking the SRP.
We try to split the classes so that the responsibilities are cohesively dealt with from a technological point of view.
Therefore, the old classes will now only focus on the domain meaning (let’s call the layer Domain layer). The presentation (or rather consumption) responsibilities are dealt with by another set of classes (another layer called the Consumer layer), and the persistence responsibilities are dealt with by yet another set of classes (the Persistence layer).
Three layers spontaneously felt like a typical solution here, one per responsibility category. The two new layers have two implementations each for dealing with both the old requirements and the new.
The dependencies between the layers are also defined, and in this case we decided that the consumption layer will depend on the domain layer, and the domain layer will depend on the persistence layer. That way, the Consumer layer is totally unaware of the Persistence layer, which was something we decided was good in this particular project.
We will get back to the subject of layering again in Chapter 4, "A New Default Architecture," and then approach it a bit differently.
Another Example: Domain Model Pattern
We have already discussed the Domain Model pattern [Fowler PoEAA] in Chapter 1 (and will do so much more throughout the book). I think about the Domain Model pattern as an example of an Architectural Pattern.
We’re not going to discuss an example about the Domain Model pattern here and now because the whole book is about just that. Instead, we’ll continue by focusing on another dimension of the patterns, regarding domain-dependence or not. Next up are Design Patterns for specific types of applications.