The best solutions usually consist of smaller, simple mechanisms that solve problems in a reliable and efficient manner. Large, complex systems are often developed from just such mechanisms. Knowledge of these mechanisms is often found in the heads of individual developers and architects. Design patterns are useful for developers and architects because they:
- Document simple mechanisms that has proven practice
- Provides common definitions and descriptions
- Provides brief descriptions of solutions as a combination of patterns
- Enables reuse of architectural-, design- and implementation decisions
For a design pattern to reach proliferation and use, it is required to be documented and categorized in an easy and understandable manner. Such documentation is usually called a pattern catalog. [GoF] gives a suggestion of how a pattern catalog can be designed and how the patterns can be categorized. This categorization has two dimensions, purpose and scope. Purpose defines what a design pattern is supposed to accomplish. According to the [GoF] definition, a pattern has creational, structural or behavioral purpose. Scope defines whether the pattern applies to a class or object, ie instance of the class.
[GoF] has since then received a number of followers in terms of design patterns. Another book that has become a benchmark in the topic is “Pattern-Oriented Software Architecture” by Buschmann et al [POSA]. [POSA] widens the definition of a pattern in various aspects, for instance that a pattern does not necessarily have to be object-oriented.
Pattern- and problem categories
[POSA] also make a different categorization of patterns than the equivalent in [GoF]. Their classification scheme is based upon two criteria, pattern categories and problem categories. Problem categories provide a problem-oriented view to the use of patterns. Every pattern addresses a specific problem that may arise in a design situation, and this categorization criteria groups patterns into different problem areas.
Pattern categories in its turn are a division of patterns on different abstraction levels. Architectural patterns are patterns used in the coarse-grained design and establishment of architectures. Design patterns extend and refine the coarse-grained design, and are also used in the more detailed design. An architectural pattern is on a higher level of abstraction than a design pattern and has a greater impact on the architecture as a whole. It is still, however, something that presents a solution to a specific recurring problem, as opposed to a style that is rather a categorization of architecture. [POSA] makes a distinction between styles, architecture patterns, design patterns and so-called idioms. Styles are very similar to architectural patterns, but differ in some important respects:
- Styles describe only the overall structural framework for applications, while architectural patterns define the basic structure of an application
- Styles are independent of each other, but a pattern depends on the smaller patterns it contains and on the larger patterns in which it is contained
- Patterns are more problem-oriented than styles. Styles are independent of a specific design situation
Idioms finally, are used within implementation of architecture into a programming language. An idiom was according to the original definition, tied to a specific programming language and only applicable for software.
Although [GoF] has been a source of inspiration for the authors of [POSA], they do, to a certain extent, criticize it in respect of the classification of patterns mentioned. As an example, they think that the difference between structural- and behavioral patterns are too vague. Problem categories more explicitly express the problem areas a developer faces when designing software. The scope criterion doesn’t really give any guidance for a developer to select a pattern. That is because it doesn’t relate to any specific design situation. Scope criterion also isn’t applicable to non-object-oriented patterns, such as Layers and Pipes and Filters.
Both [POSA] and [GoF] demonstrate a number of patterns that can be reused during development. You will of course not need all of these patterns every time, but knowing that they exist and their meaning makes it next time easier to find a solution to a problem or to solve a problem in a general way. Once you create your own patterns, you could relate them to existing ones and classify them according to existing classification schemes.
Evaluation of patterns
How do you know when to use a pattern and in which design situation? One way to evaluate patterns is to relate them to various “non-functional” requirements, or quality attributes. Patterns are often used to solve various “non-functional” requirements. However, these quality attributes are often in conflict with each other.
As well as design patterns, quality attributes are often grouped into different categorizations. Different quality attributes can then further be divided into “subcategories”, as for example, performance and modifiabilty in the image below:
Performance and modifiability requirements are often conflicting. If you want one, you often have to compromise on the other. Even within a “subcategory” there may be a conflict. The performance attribute as an example, distinguishes between response time and throughput. Optimizing for one can sometimes be detrimental to the other. One example is indexing of a database table. A general rule is that the index improves response time, while throughput declines.
As for modifiability, one can distinguish between configurability and maintainability. Focusing on configurability gives the best possible flexibility. Addressing the configurability attribute may for example concern usage of configuration files and meta-databases. Unilaterally optimizing for configurability will likely have consequences for performance. A guideline could thus read: “If performance is an important issue, so transform the modifiability requirement from configurability to maintainability”. Maintainability refers to how well and easily we can maintain our application. During a system’s lifecycle, we know for sure that we will have to change program code in a number of different components. Research studies have shown that efficiency drastically drops during maintenance phase, in contrast to development. Therefore it is of importance to consider the maintainability quality attribute.
One way to perform transformations as mentioned above is to apply the right design patterns. Design patterns are designed to make the application code more general, and therefore easier to maintain. Generally speaking, most design patterns are conducive to the modifiability quality attribute, such as maintainability, configurability, interoperability and reuse. Architecture patterns in its turn makes important “trade-offs” those quality characteristics in between.