Building on patterns

The ever-increasing complexity of software has forced managers in many IT development organizations to start work on building a comprehensive software architecture. Driving the need are a steady escalation of component software use, an increase in enterprise-wide technology implementations, the rapid rate of technological change and the increasing importance of technology-to-business strategy.

Organizations that are including technology in the strategic planning process are discovering that the rapidly changing technology landscape makes it difficult to connect stable business strategies to unstable technology. Meanwhile, in the technical trenches of organizations, software engineers who embrace a component-based approach to software development have found that, along with its benefits, this approach presents the challenge of assembling the components into a solution that meets business requirements in a meaningful and maintainable form. In addition to all this is the difficulty of translating the requirements of today's complex enterprise-wide technology implementations into comprehensible and stable system designs. Each of these issues drives the need for a disciplined approach to structuring software systems. Software architecture aims to address this situation.

To business strategists, software architecture provides a conceptual view of technological solutions so that the solutions can be planned and understood independently from the specific and rapidly changing technologies that underlie them. To software engineers, it provides a structure within which components can be assembled meaningfully. To those responsible for system design it provides a reasoned way of stepping from requirements to design, eliminating the leap in logic that often occurs in that move. For all these players, software architecture provides a means to communicate the overall design of a system to others.

Software architecture yields these benefits because it provides a structured way of conceptualizing complex software systems. Early in the development of a software system comes the need to simply "get a handle" on the system. As business requirements are uncovered and the basic structure of a system is being considered, the first questions asked include: "What are the major identifiable parts or modules of the system?"; "What job does each of those parts handle?"; and "How does each part work together with other parts to solve the problem?" The answers to these questions are the primary issues with which software architecture is concerned.

Software architecture: Practice and theory
The literature regarding software architecture presents a multitude of approaches. For all their differences, nearly all modern approaches to software architecture address these three fundamental issues: the identification of the major structural elements of the system, the interrelationships of these elements and the rationale behind the definition of these elements and their interactions. This provides a working view of software architecture (see Fig. 1).

Figure 1
Hartman Figure 1
A working view of software architecture. Most approaches to software architecture address these three fundamental issues.

Like many other areas of software engineering, the practice of software architecture as it is commonly conducted has developed separately from the theory. The reality is that despite the variety of approaches provided, software architecture in the real world is typically an informal process performed by seasoned IT veterans who draw on a wealth of personal experience in what works and what does not. Unfortunately, this approach does not make for a repeatable process, because everyone's experience is slightly different, veteran engineers are not always available and those without the benefit of a veteran engineer often find very little practical documentation produced by experienced architects.

This situation has resulted in the widespread use of a default "how many tiers?" approach to architecture. Because of the recent popularity of a tiered view of systems, it is a widespread practice for many inexperienced architects to define their system's architecture by simply attempting to answer the question, "How many tiers does it have?" From this point of view, partitioning the system between presentation, business and data (and perhaps n other) tiers becomes the focus of architectural decision-making. What this approach fails to realize is that a tiered system is not the appropriate solution in every case. A tiered system is only one possible architectural form, and it may or may not meet the needs of the situation at hand.

Documenting experience with patterns
Pattern-Oriented Software Architecture (POSA) attempts to address both the need for well-documented real-world expertise in the architecting process and the need to recognize many possible architectural forms. In essence, POSA captures the proven experience of software architects and documents it in the form of various architectural patterns that each possess distinct properties. Architects working with these patterns can choose the pattern that has properties best suited to their specific solution requirements.

Although the use of architectural patterns is relatively new, nearly everyone in the software industry today is familiar with the concept of design patterns. Design patterns differ from architectural patterns because design patterns focus on subsystems while architectural patterns focus on entire systems. Despite this difference, the concept of capturing and documenting proven experience through patterns is the same. Patterns recognize that many engineers have repeatedly encountered the same problems in similar situations, and that similar solutions have repeatedly been applied to these situations with success. Patterns document the problem, its context and the tried-and-true solution.

An example of a commonly seen pattern is the Observer design pattern, sometimes referred to as the Publisher-Subscriber pattern. This pattern documents the fact that in many system designs there is a recurring need for components to use data provided by other components. In the language of patterns, this is referred to as the context. The common problem found in this context is what to do when a component changes its state and needs to inform other components that rely on its data. One possible solution to this problem has so repeatedly proven successful that it can be identified as a pattern. This pattern describes the implementation of a mechanism for components requiring the information (the observers) to register interest (subscribe) with the component supplying the information (the subject). The subject can then notify (publish to) all observers when its state changes. System designers can use this pattern as a model to solve the problem of inter-component notification in their own systems, and it can be implemented in whatever language or technology best suits the system at hand. Event mechanisms using callbacks are a familiar implementation of this pattern.

The benefit of a pattern-based approach to design is that any designer can consult a pattern reference, such as the classic text in the field of design patterns, Design Patterns: Elements of Reusable Object-Oriented Software by E. Gamma, et al. (Reading, Mass.: Addison Wesley, 1995), to find patterns that apply to the issues they face in designing a particular system. Because there is likely to be a design pattern developed for the most common design problems, designers using patterns do not need to waste time reinventing solutions to pattern-documented problems. There is a significant effort in the software industry to document and refine design patterns, so taking this approach allows a designer to draw on a wealth of real-world experience from across the software industry.

Pattern-Oriented Software Architecture
Pattern-Oriented Software Architecture attempts to accomplish at the level of entire systems what design patterns accomplish at the level of subsystems. A pattern-oriented approach to architecture recognizes that patterns can be developed to document the experience of successful system architectures and can make this knowledge available to the community of architects. In keeping with the definition of software architecture, architectural patterns describe the fundamental structural elements of an entire software system, how those elements work together and how they describe the reasoning process and guidelines behind the choice of architecture.

The Layers pattern is one example of an architectural pattern. This pattern is familiar to most developers even if they are not aware of POSA because many of today's tiered systems conform to the Layers pattern. This pattern was one of the first architectural patterns to be identified and is based on the work of software engineers exploring the challenges of decomposing complex software systems in the late 1960s (see Origins of Software Architecture Study, by Paul Clements of the Software Engineering Institute, for an excellent discussion of this subject). The decomposition of complex systems serves as the context of the Layers pattern. The problems identified as recurring in this context include how to isolate the effect of code changes, how to define stable and standardized interfaces, how to group functions into coherent modules and how to partition work among team members.

The Layers pattern documents this context and its problems and describes a repeatedly proven solution. The pattern describes an architecture in which the system is broken into groups of subtasks where the set of subtasks can be seen as a stack of layers. Each layer draws on services from the layer below it or provides services to the layer above it. In the case of a tiered system implementation, the presentation tier/layer is the set of subtasks that represent information to the user and draws on services provided by the business tier/layer, which contains processing logic to manipulate data. The business tier/layer in turn draws on the data tier, which provides data structures and data access services providing information to the logic of the business tier/layer (see Fig. 2).

Figure 2
Hartman Figure 2
Many of today's tiered systems conform to the Layers pattern. It was one of the first patterns to be identified, and its context is the decomposition of complex systems.

So if architects are intuitively using a Layers pattern when structuring tiered systems, then what is the advantage of explicitly identifying it as a pattern? In recognizing that these systems conform to a well-known pattern, we can now draw on the well-documented experiences of others who have used the same pattern. An architectural pattern reference such as Pattern-Oriented Software Architecture: A System of Patterns by Frank Buschmann, et al. (New York: Wiley, 1996) can provide a wealth of information on the situations best addressed by a layered architecture, guidelines for implementing this type of architecture, and examples and variations on the architecture. The result is a check on the suitability of the architecture for the particular system at hand, and a more solid implementation of the architecture for that system.

An example of a very different architectural form is the Pipes and Filters Pattern. The context for this pattern is a system that must process a stream of data. Examples of the problems found in this context include how to accommodate a variety of possible input and output sources, how to efficiently store data between steps in the process and how to maintain the integrity of the process in an interruptible environment. The Pipes and Filters pattern suggests addressing these problems by structuring the system as a series of processing steps with the data passing through "pipes" and "filters" on its way between endpoints in the system. In addition to being pathways for data transfer between filters, pipes can serve as buffers to assist in the synchronization issues presented by an interruptible environment. Filters perform specific processing on the input data and deliver the results as output data to the next step in the process (see Fig. 3).

Figure 3
Hartman Figure 3
The context for the Pipes and Filters pattern is a system that must process a stream of data. It suggests structuring the system as a series of processing steps.

Wireless applications are an excellent example of this type of context and problem set. They are fundamentally data stream-oriented applications that usually require transformation of the data as it moves between various business processes and devices. The Pipes and Filters pattern identifies many of the problems confronted by the architect of a wireless application. For example, in moving the data stream from point to point, the interruptible nature of wireless communications means that the data stream often requires buffering and synchronization to prevent data loss and to insure data integrity. In addition, wireless applications often require that the data be transformed for presentation on a wide array of mobile client device types and for processing by multiple back-end systems.

The applicability of the Pipes and Filters pattern to wireless applications demonstrates that today's wide range of technological choices requires us to be familiar with a wide range of architectural choices. Patterns provide this set of choices and failing to take advantage of them can have disastrous results. In our wireless example, an architect who is not familiar with a pattern-oriented approach is likely to default to a tiered approach. This would cause the issues of reliability, data integrity, connectionless store-and-forward buffering mechanisms, presentation on a multiplicity of client devices and back-office integration to be insufficiently addressed because these are not major emphases in the tiered approach.

Applying pattern-oriented architecture
At its most basic, applying patterns in the process of software architecture involves understanding the context and requirements of the system, identifying the problems presented by the context and then selecting the pattern (or patterns) proven to be most effective in addressing the context and its associated problems. The difficulty is that knowing which patterns apply requires a great deal of knowledge about a large number of patterns. To make the process easier, Buschmann, in Pattern-Oriented Software Architecture: A System of Patterns, has developed a classification of patterns by the problems they address (see the table, "A pattern classification"). Note that although the table shows only architectural patterns, Buschmann's original classification, from which the table is adapted, also includes design patterns, idioms and the problems addressed by them. The following steps for moving from problem to pattern to implementation are adapted from Buschmann. As I describe the steps, I will use the case of my involvement in a recent Sales Force Automation (SFA) development effort as an example of how each step can be applied practically.

First, you must understand the requirements of your solution and identify the problems associated with it. Requirements definition and problem identification is a well-known development step for which there are a large number of helpful resources, so I will not discuss it in detail here. In the case of our SFA system, the essential requirements were to develop a means for sales agents to submit orders via a handheld device that could wirelessly submit the orders to an office-based order-coordinating server. This coordinating server would then interact with the systems of multiple business partners involved in the order fulfillment process and communicate responses back to the mobile client regarding the state of the order. Among the many problems presented by these requirements are that wireless connections cannot always be guaranteed, and multiple business partners involved in order fulfillment might have differing data formats for the systems with which the coordinating server must integrate.

Second, you must determine which patterns best address the problems you have identified. In Buschmann's model this means identifying the "problem category" (again refer to the table). Problem categories describe the general nature of the problems being addressed and list the patterns that best map to those problems. Elements of the SFA system can be seen in nearly every category, but because it distributes an order-fulfillment process across mobile clients, a coordinating server and multiple back-office systems all working in concert, the system falls primarily into the category of distributed systems. This category presents us with several possible architectural patterns, including the Broker pattern and the Pipes and Filters pattern.

Third, you must compare the candidate patterns by looking at their problem descriptions, benefits and liabilities, and then select the appropriate pattern. In considering the nature of the SFA solution, the Pipes and Filters pattern provides an excellent match for many aspects of the system. For example, the order fulfillment process is essentially a series of data processing steps. In this process the lack of a guaranteed connection in the wireless world requires a store-and-forward mechanism for transfer of the orders between the mobile client and coordinating server. The Pipes and Filters pattern addresses this in the form of a "buffering pipe." In addition, the concept of filters addresses the transformation of data from a transport format into a presentation format on the mobile devices and into the multiple formats of the business partner system in the office.

The SFA case is also an example of how multiple patterns can combine around a primary pattern to produce the total architecture. Though Pipes and Filters is the central pattern of the architecture, a Layers pattern was adopted in the mobile client to wrap the low-level message queuing services and expose them to the client-based order entry application. In this way the client application could be exchanged or easily modified because the wrapper provided a well-defined interface to the messaging services by following an industry standard supported by multiple development tools.

Fourth, once a pattern or set of patterns has been selected, the implementation guidelines for the pattern(s) can be followed. These guidelines can be found accompanying the pattern descriptions in many of the current pattern references. For example, the guidelines for implementing the Pipes and Filters pattern include defining the processing steps, defining the data format to be passed along the pipes and deciding how to implement the pipe connections.

Following the Pipes and Filters pattern implementation guidelines for the SFA system, the many processing steps defined included order input on the mobile device; transformation of the order to a transport format; queuing, transmission and acknowledgement of messages; and transformation of transport formats into partner system formats. A data format (XML) was chosen for transport through the pipes, and message queuing was selected as the means to implement pipe connections with a buffering capability. The capabilities of Microsoft's BizTalk Server were selected for use as a filter for transforming data formats between the coordinating server and business partners.

On a final note on the application of POSA, it is important to realize that POSA is not a software development methodology even though the implementation guidelines included in pattern descriptions can give POSA the appearance of being a method. POSA is a collection of proven architectural experiences that can be utilized regardless of the development methodology chosen. Pattern implementation guidelines are simply issues to consider when using a given pattern and they can be adapted to your specific situation. From this perspective, patterns can function well whether the methodology is iterative, waterfall or something else.

Consulting the experts
Although we have only touched the surface of Pattern-Oriented Software Architecture in this article, we have seen that architectural patterns are an important resource for today's system architects. As the complexity and criticality of information systems continues to increase, the need for good architectures and the architects to produce them will increase. The architects who will create the next generation of information systems will need to draw on as wide a range of experience and models as possible, and patterns are an important resource of this knowledge.

In its architectural guidelines, Hewlett-Packard encourages its system architects to "consider architectures of similar systems, and review the literature on architectural patterns, to identify potential architectures, architectural models or styles." By referencing architectural patterns, a system architect can discover new ways of viewing the system under consideration, and can find guidance in selecting and implementing the appropriate architecture. In support of this, POSA distills a vast body of architectural knowledge into the usable form of patterns that can be mapped to real-world contexts. Pattern-Oriented Software Architecture offers, in a very real sense, a means of consulting with successful architects and their best practices as they apply to your project.

A pattern classification
Problem Categories Architectural Patterns
System Partitioning Layers
Pipes and Filters
Distributed Systems Broker
Pipes and Filters
Interactive Systems Model-View-Controller
Adaptable Systems Microkernel
Source: Adapted from Pattern-Oriented Software Architecture: A system of Patterns, by Frank Buschmann, et al.

POSA distills a vast body of architectural knowledge into the usable form of patterns that can be used to solve common development problems.