Academia.eduAcademia.edu

Sequences as a basis for pattern language composition

2005, Science of Computer Programming

Pattern languages have begun to appear and mature as a presentation of the structures and processes that support the building of complex software systems. A pattern language describes how to compose structures in a particular domain such as telecommunications, client-server architecture, or object-oriented programming, to achieve system-level architectures that are greater than the sum of their parts. A problem lurks on the horizon: How do you compose patterns from multiple domains-from multiple pattern languages-in a single system? For example, today there is nothing other than an ad hoc approach to combining the pattern languages for telecommunications and for object-oriented design to build object-oriented telecommunications systems from the respective pattern languages. To understand the solution to this dilemma, it pays to examine sequences: an important aspect of pattern application that is often overlooked. Sequences are the loci of concern about interleaving patterns, whether from a single pattern language or multiple pattern languages. Sequences are critical because pattern languages represent long-term archives of the rhythms of critical, recurring sequences.

Science of Computer Programming 56 (2005) 231–249 www.elsevier.com/locate/scico Sequences as a basis for pattern language composition Ronald Portera,∗, James O. Coplienb, Tiffany Winna a School of Informatics and Engineering, Flinders University of South Australia, PO Box 2100, Adelaide, South Australia 5001, Australia b Vrije Universiteit Brussel, c/o North Central College, 30 N. Brainard Street, Naperville, IL 60540, USA Received 12 November 2003; received in revised form 10 August 2004; accepted 6 September 2004 Available online 13 December 2004 Abstract Pattern languages have begun to appear and mature as a presentation of the structures and processes that support the building of complex software systems. A pattern language describes how to compose structures in a particular domain such as telecommunications, client–server architecture, or object-oriented programming, to achieve system-level architectures that are greater than the sum of their parts. A problem lurks on the horizon: How do you compose patterns from multiple domains—from multiple pattern languages—in a single system? For example, today there is nothing other than an ad hoc approach to combining the pattern languages for telecommunications and for object-oriented design to build object-oriented telecommunications systems from the respective pattern languages. To understand the solution to this dilemma, it pays to examine sequences: an important aspect of pattern application that is often overlooked. Sequences are the loci of concern about interleaving patterns, whether from a single pattern language or multiple pattern languages. Sequences are critical because pattern languages represent long-term archives of the rhythms of critical, recurring sequences. © 2004 Elsevier B.V. All rights reserved. Keywords: Sequence; HOPP; Idioms; AOP; Aspects; Telecommunications ∗ Corresponding author. E-mail address: [email protected] (R. Porter). 0167-6423/$ - see front matter © 2004 Elsevier B.V. All rights reserved. doi:10.1016/j.scico.2004.11.014 232 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 1. Introduction Modularity appears to be dead. The focus of contemporary design discourse is typified by such non-modular notions as aspects, patterns, and features. Aspects are a grouping of code related to some software feature whose implementation cuts across the original system partitioning. Patterns are structural relationships between parts of a system on many scales; they combine architectural relationship, structure, and process in ways that go beyond modular approaches. Features are collections of marketable functionality which, though they would be attractive as self-contained physical packages, almost always cut across any reasonable physical partitioning of the architecture. Aspects and patterns are both examples of design aids that cut across existing, recognized modules. And yet, the irony is that these examples are themselves modular in some sense. Alexander’s early work viewed patterns as encapsulations of forces [2, p. i], as design modules that allowed one to reason about a limited set of forces in relative isolation. Both patterns and aspects identify key elements of complex system composition at the conceptual level. Aspects, patterns, and features are thus themselves subject to questions of composition. For example, how might one compose multiple aspects on top of a single system? How does one compose features? This problem is as yet largely unsolved. An ordered composition of patterns leads to a system. The structural relationships between patterns are encoded in larger design structures called pattern languages. The term “language” appeals to the notion of a generative grammar that can create any system in a given genre. Much of the software community’s original interest in patterns came from their ability to deal with issues that, from an object-oriented perspective, reflected cross-cutting. Yet, even patterns are not immune from the cross-cutting problem. Most interesting systems are not of a single, pure genre. For example, a telecommunications system may use communication design pattern languages such as those given by Hanmer [1] and Meszaros [21] for fault tolerance and system capacity, respectively. The structural ordering is well defined within each of these pattern languages. Yet what does one do if one wants to build a fault-tolerant system that deals with capacity issues? How does one mix patterns from multiple pattern languages? The problem can become arbitrarily rich: consider adding yet a third pattern language such as Coplien’s language for structuring C++ inheritance hierarchies [11], presuming that the system is to be written in C++ using an objectoriented programming style. The fundamental problem of combining patterns of different genres is not one of spatial dependency, but of the temporal ordering of pattern application. This means that combining pattern languages is more temporal than structural. While expert telecommunications designers have long known instinctively how to combine such pattern languages for a given system and context, articulating that knowledge for less expert designers is a very difficult problem. For the inexpert designer, who may be using particular pattern languages for the first time, the languages offer no help as to how to address the problem of temporal ordering of pattern application. Addressing that problem is the focus of this paper. The structure of the paper is as follows. Section 2 defines pattern languages. Section 3 further motivates the need for composition. Section 4 talks about sequences, and Section 5 discusses pattern languages as encodings of recurring rhythms of sequences. Section 6 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 233 Fig. 1. A language for a garden [5, p. 314]. presents our solution to the weaving problem, and Section 7 outlines a formalization of this solution. Section 8 revisits the relationship to related work in aspect orientation. 2. Pattern languages A pattern language is a collection of parts called patterns, along with a description of how to combine them into meaningful compositions. A pattern language prescribes only the allowable configurations among small groups of patterns; it can be thought of as a way of describing dependencies between patterns. So, in a pattern language diagram, such as the one from Alexander shown in Fig. 1, the arrows show a refinement relationship between patterns. Patterns nearer the bottom of the figure refine patterns above them. We say that G ARDEN G ROWING W ILD is smaller than H ALF -H IDDEN G ARDEN. Intuitively, this means that G ARDEN G ROWING W ILD is applied as a structural refinement inside the structure created by pattern H ALF -H IDDEN G ARDEN. However, a single application of a given pattern may cut across non-overlapping structures created by multiple “larger” patterns. 3. The need to compose pattern languages Understanding how to compose pattern languages is important for two main reasons. First, many systems require a combination of patterns from different domains to function effectively. Second, the nature of pattern languages is such that systems will tend to use patterns from several different languages. A system can require patterns from different domains for a variety of reasons. One reason might be a change in available technology, over time. This happened, for example, 234 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 in the repair of a Gothic cathedral at Mont St. Michel in France. The ceiling had collapsed under the stress and wear of centuries, and the technology originally used to build the ceiling was, at the time of repair, obsolete. Patterns from a different domain than those originally used to construct the ceiling were thus required to repair it. Another reason for combining patterns from different domains in a system is to allow the system design to accurately reflect the intent of the designer. Programming languages that support multiple paradigms recognize this need. They support a combinatorially rich set of hybrid designs, such as can be found in the combination of templates, overloading, and object orientation in C++ [10]. Another, perhaps more compelling motivation for combining pattern languages emerges from the structure of contemporary software pattern languages, and may well be germane to the very concept of pattern languages. Pattern languages are both specific and general. They tend to reflect the interests of a single domain, yet are broad enough to describe a family of systems. So for example, consider a pattern language of fault tolerant software (such as [1]) that describes the recurring structural configurations of reliable telephone systems. Those same recurring structures are present in most telecommunications architectures whether the systems were built using agents, objectoriented, procedural, or data-driven techniques. These techniques and their use in systems may themselves comprise patterns. A pattern language might exist for agents, object orientation, or procedural design, without regard to the telecommunications context. Nevertheless, patterns from those languages should also be present in a telecommunication system using the respective set of techniques. Both the telecommunications pattern language and the technology pattern language were written to capture basic domain knowledge without being too specific, but neither alone is general enough to incorporate the other. A designer must combine the telecommunications and design pattern languages. Further, as an example from the domain of architecture, consider Alexander’s pattern language for houses: it focuses on living space and the construction techniques used to build houses, but it does not cover the design considerations for plumbing or wiring. There may be a plumbing pattern language that contains a pattern O PEN BASEMENT that makes the plumbing accessible for maintenance in the long term. The location of power outlets, which comes in part from the wiring pattern language, will sometimes contribute to the effective layout of an office. These other pattern languages, which exist in real systems and only await being committed to paper, must be woven in with Alexander’s language for houses. Alexander attempted to combine pattern languages as part of the process of designing a university campus. He created a new pattern language that needed to be combined with his original language in order to do the necessary construction [3, p. 107]. The merging process that Alexander used appears to be ad hoc and is not well detailed in his presentation; here, we try to anticipate how he might have integrated those languages or how one might teach someone to achieve such integration. In the organizational pattern research undertaken by Harrison and Coplien [19], the patterns naturally fall into four pattern languages: one each for project management, organizational growth, organizational style, and the relationship between organization and architecture. A given project might need, however, to combine a subset of the patterns from these pattern languages into a single pattern language that describes the organization as a whole. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 235 All of these examples can be likened to the problem of aspect-oriented programming in object-oriented programming languages. An aspect is a design concern that cuts across the chosen partitioning in a given design. Aspects have recently received attention as a way to compose multiple architectural views. Aspects are based largely on programming technology approaches including language features, tools called “weavers” that weave aspects into a system, and other specialized techniques. Fault tolerance is frequently offered as an example of an aspect that cuts across the objects of the call processing architecture. An object-oriented telecommunications system design may encapsulate individual resources and devices as objects: half-calls, terminals, messages, and so forth. There are bona fide design concerns—domains—that do not fit into objects, and fault tolerance is one such domain. Object-oriented design does not model or capture fault tolerance concerns well because, as a discipline, fault tolerance has more general principles than the specialization represented by any object or class, and also because fault tolerance is a system concern that is more concerned with the interactions between objects than with individual objects or classes. One could solve the problem of integrating multiple design domains (pattern languages) by writing different pattern languages for each combination of the “smaller” pattern languages: one for object-oriented fault tolerance, another for procedural fault tolerance, and so forth. Sometimes that is the right thing to do. However, the best-written patterns transcend these concerns because they encapsulate forces germane to their respective domain, leaving other patterns to balance forces from other domains. 4. Sequences: the forgotten structure Pattern languages give only a weak notion of the order in which patterns should be introduced during the construction process. Larger patterns are applied before smaller patterns; larger patterns are shown higher in the language diagram than smaller patterns, and arrows run from larger to smaller patterns. Alexander further notes that adjacent patterns should be applied as close in sequence as possible, but neither Alexander’s theory nor language diagrams indicate how to order adjacent patterns. Further, most system designers using languages work only with the individual patterns and language diagram, and may not even be familiar with Alexander’s theory. The order in which to apply patterns, including adjacent patterns, is critical to the proper use of a pattern language: sequence matters. This is largely why the fundamental problem of composing pattern languages is more temporal than structural. Consider a large pattern and a smaller pattern that are dependent on each other such that the smaller pattern refines the larger pattern. A dependency between two patterns suggests that the introduction of a smaller pattern should not precede the introduction of the larger pattern. However, that says nothing about the partial ordering of two patterns adjacent to each other in the language relative to other patterns in the language. This is worth exploring because, as we noted above, the fundamental problem of composing pattern languages is more temporal than structural. Consider again the pattern language for a half-hidden garden depicted in Section 2. Clearly, the first pattern is H ALF -H IDDEN G ARDEN: realizing the need for it, and locating 236 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 it on the premises. We may then apply G ARDEN G ROWING W ILD and T ERRACED S LOPE. From the perspective of the pattern language graph, this ordering follows common intuitions that one learns about tree traversal in data structure courses. Next, we may decide to apply C OURTYARDS W HICH L IVE. Then we may apply T REE P LACES. And after that, we may apply F RUIT T REES or E NTRANCE T RANSITION. The language does not specify the order in which these patterns should be applied. But the order matters. The presence of a fruit tree may affect the location or nature of the E NTRANCE T RANSITION. Similarly, if E NTRANCE T RANSITION is applied before F RUIT T REES, a different design emerges. Alternatively, we may have no fruit trees at all. It is (at least in part) in this sense that Alexander says that a pattern language can be applied a million times without ever twice being the same. What does matter is sequence. A sequence is the ordering of patterns in a given architecture—or perhaps in a family of architectures—that tells the order in which the patterns should be applied. A sequence is a sort of architect’s tour of the artifact being built. One of the most explicit sequences in Alexander is that for the tea garden in Nature of Order [7]. However, we also find a sequence at the very beginning of A Pattern Language [4]—a sequence for all the patterns in the book. Good design is about following established sequences. To combine multiple pattern languages, one must revisit the sequences from which they were created. Sequence is fundamentally important in many disciplines of social endeavor. Hall [17] talks about its role in a wide range of human activity. In Alexander’s recent work on the nature of order, the Fundamental Process [8] is a basic repeated cycle. The relevance of sequences to software patterns has recently come to light [18]. From a practical viewpoint, sequences can be used as an effective way to present pattern languages. While a pattern language graph serves principally as a guide to the structure of a pattern language, the patterns must still appear on the page in some linear order. One of the best orders in which to present the patterns is the main sequence order, that is, the order that would occur if all the patterns in the language were applied. A sequence may contain information that is lost in a pattern language: for example, the preferred ordering of two patterns at the same level of scale that both apply to the same larger pattern. On the other hand, a pattern language may contain information that is lost in a sequence: for example, the relationship between a pattern and which larger pattern it refines. Domain knowledge can fill in the gaps in both cases. 5. Pattern languages: encodings of structurally recurring rhythms A pattern language is a way of capturing the recurring temporal structure of sequences. Let us say that we observed all the sequences for H ALF -H IDDEN G ARDENS that have the quality that we want them to have. We might be able to find a single set of precedence relationships between patterns that we can formalize as a partial ordering and depict as a directed graph. Creating such a graph requires design insight and care. Perhaps F RUIT T REES follows E NTRANCE T RANSITION 95% of the time; we would be tempted to draw the pattern graph so that F RUIT T REES refines E NTRANCE T RANSITION. Even though the order of these R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 237 patterns matters in the system outcome, it may not be the case that one refines the other in any structural (geometric) sense. A pattern language should reflect more than an encoding of order; it is primarily an encoding of system structure. However, structure says something about order; the common saw that one builds the basement before the rest of the house is an obvious link between structure and order. In addition, we may have a B UILDING E DGE in place before we consider adding a T ERRACED S LOPE, which would seem to violate the ordering of the language. A slope may build up to a building edge, and there would clearly be a structural relationship between the two that the pattern language must communicate. But the time ordering is the domain of sequences, not of pattern languages. Even though the B UILDING E DGE may exist before the T ERRACED S LOPE, we let the pattern language reflect the structural, rather than temporal ordering. 6. Weaving sequences We claim that given a collection of sequences of patterns, a designer can generate at least a rough picture of the structure of the language from which those sequences arise. Consider, for example, being given a collection of sequences of words in a language such English. You could probably generate a grammar for that language, couldn’t you? Not a perfect grammar, but something good enough to torture grade school children with. In fact, grammarians have been doing just this for quite a few years now. As an extension of this idea, we claim that the structure of a combined pattern language (a language built by combining patterns from different languages) can be at least roughly determined using sequence. To do so, the designer needs first to identify a sequence from each of the languages from which patterns are being combined. Depending on the size of the language, the particular sequence used may be simply be a sequence used in a particular design, or it may be generated by observing recurring temporal orderings in a collection of sequences from the language. Using domain knowledge, and an awareness of the structure of the individual languages provided by context, the individual sequences should be interleaved into one larger sequence. The structure of the combined language can then be roughly deduced from the interleaved sequence. The importance of domain knowledge to generating language structure from sequence cannot be understated. For example, with domain knowledge you can figure out from fragments like “the large black cloud” and “the small black dog” that “black”, “small”, and “large” all modify noun things like clouds and dogs; without domain knowledge this is a much more difficult task. A combined pattern language should thus reflect rich domain knowledge embodied in the designer’s domain experience; the language is not a mechanically generated structure. Further, a combined pattern language should maintain the overall structural dependencies of each of the original languages. For example, if A refines B in the original language, then A should be somewhere below B in the new language. The combined language should preserve the overall structure of each of the original languages. Our claim that language structure can be deduced by interleaving sequences assumes the following properties of patterns: 238 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 • Given the right context, a pattern can be individually applied without disturbing any other pattern(s) in the language [5, p. 344]. • Patterns compose structurally and there is a well-defined structural ordering of dependency between them: “... the order of the language is the order in which the patterns need to operate on one another to create a whole. It is a morphological order, similar to the order which must be present in an evolving embryo ...” [5, p. 401]. • There are sequences that recur in different yet similar contexts that consistently lead to good system designs. Alexander provides the example of a sequence used time and time again to generate Japanese tea gardens [7]. Our claim further assumes that structure and sequence are inter-related: Section 6.1 provides a brief overview of the nature and importance of this relationship. Section 6.2 focuses on context, and why the context of a pattern is critical to generating structure from sequence. It offers further insight into the connections between structure and sequence. Sections 6.3 and 6.4 provide examples of interleaving sequences to generate a language. 6.1. Language and sequence: structural and temporal order A pattern language is primarily structural. It expresses relationships of structural refinement between patterns. A sequence is primarily temporal. It expresses relationships of order of application between patterns. A pattern language, though, expresses some notion of sequence, and a sequence expresses some sense of structure. That there should be connections between structure and sequence makes sense. A basement, for example, is almost always built before the rest of the house. It provides the structure on which the rest of the house builds. Specifying the exact nature of the connections between structure and sequence is, however, complex. Alexander offers the following insight: If pattern A is above pattern B in the network of the language, then I must take A before I take B. This is the most fundamental rule [5, p. 379]. The structure of a language thus says something about the order in which patterns should be applied, and the order in which patterns are applied says something about the structure of the language that they come from. A larger-grained pattern ought to be applied before a finer-grained pattern. For example, consider the collection of all possible sequences for generating a H ALF -H IDDEN G ARDEN with particular qualities. A designer observing that collection of sequences might notice that some patterns are always applied prior to other patterns. This ordering would mean that the earlier-applied pattern would be located higher in the structure of the language than the later-applied pattern. Determining exactly how much higher the earlier pattern would be, however, would require domain knowledge. Further, just because, for example, pattern A is above pattern B in a language does not mean that B refines A. Not every pattern at a given level refines every other pattern at higher levels. For example, it may be that F RUIT T REES is usually applied after E NTRANCE T RANSITION, and is therefore at a lower level in the language than E NTRANCE T RANSITION, but that does not mean that F RUIT T REES structurally refines E NTRANCE T RANSITION. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 239 6.2. The importance of context A pattern language is much more than a collection of patterns. It is a collection of interrelated patterns, and the network of relationships between the patterns is as much a part of the language as the patterns themselves. Just as a word is in part defined by its context, a pattern is partly defined by the patterns that surround it and provide its context: The language not only connects the patterns to each other, but helps them to come to life, by giving each one a realistic context, and encouraging imagination to give life to the combinations which the connected patterns generate [5, p. 315]. Solutions for larger problems can therefore be constructed by combining individual patterns, precisely because of the connections of meaning between them expressed in their context. Similarly, relationships between individual words allow the construction of larger concepts through combination. Recognition of the fact that each pattern carries a context with it is critical to understanding the connections between structure and sequence. It is the presence of context in each pattern that allows the language to guide the process of design, thus generating sequence. Further, it is the context that a pattern carries with it into a sequence that allows conclusions about language structure to be drawn from the sequence. Alexander highlights the fact that the structure of a pattern language guides the process of design: ...the real work of any process of design lies in this task of making up the language [emphasis added] from which you can later generate the one particular design. You must make the language first, because it is the structure and the content of the language which determine the design [5, p. 324]. A pattern language thus provides the dynamics for generating sequences, just as the grammar of a natural language provides the dynamics for generating sentences. A pattern language provides the context in which a solution to a problem can be developed. We argue that it is actually not possible to solve a problem without some notion of language, for two reasons. First, a problem always exists in a context, and solving the problem requires some understanding of that context. A pattern language provides context for a problem by locating the position of the problem in the overall structure of the system. Each pattern addresses a particular problem, and the position of the pattern in the language—its context—is based on designers’ experience with existing systems, of how to resolve the forces present in that problem context to solve the problem. The pattern is thus placed in a particular position in the language because it has been shown to be a recurring solution to a particular problem that tends to occur in a particular context. The language therefore identifies the likely context for a given problem. And the language directs the designer to solutions without the need for close analysis of the problem context: the language effectively does this analysis for the designer. As Alexander points out, the language is not just some artificial structure imposed on a system from outside, but is an encapsulation of prior experience of dealing with problems in the system: 240 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 Fig. 2. The relationship between language and sequence. ...there is a deep and important underlying structural correspondence between the Pattern of a problem and the process of designing a physical form, which answers that problem. I believe that the great architect has in the past always been aware of the patterned similarity of problem and process, and that it is only the sense of this similarity of structure that ever led him to the design of great forms [2, p. 132]. Second, all but trivial problems are solved in steps, thus requiring a sequence of successive problem/solution shifts. The structure of a pattern language provides a pathway through a problem by identifying successive problem/solution pairs. It thus allows the solution to a problem to unfold through the use of context. Solving one problem creates a new context and the structure of the language—the connections between patterns—guides the designer as to what that new context is likely to be, how to solve the new problem that presents, and what the next resulting context is likely to be. When a designer expresses a design as a sequence of patterns, he or she is creating an image or representation (in his/her mind, on paper, in a tool, or in a nascent form of the finished artifact) of an artifact. But the sequence also expresses the process of design. That process is, in essence, a sequence of operations, each one of which differentiates the structure that has been laid down by the previous operations. The design space sets up a context that provides the means of identifying which pattern to apply. A pattern, however, has a context in the pattern language, so applying a pattern intertwines two contexts in an important way. But the correspondence noted above that Alexander points out between the pattern of a problem and the process of designing an artifact that solves that problem means that the sequence carries a structural context that can be used, together with domain knowledge, to generate language. Consider a sequence A–B–C. The connections between structure and sequence thus far outlined tell the designer that such a sequence must derive from one of the language structures shown in Fig. 2. (N.B.: an arrow means somewhere above, not necessarily directly above.) Domain expertise can be used to distinguish which of these three possibilities is more likely to be correct, because the pattern language structure reflects the order in the domain. Similarly, domain knowledge can tell the designer when a leaf node of the pattern language has been reached. For this reason, we do not include the option [A separate from B → C] above, for example, because domain knowledge must be used to distinguish this case. Where pattern languages from different domains are being combined, and sequences must be interleaved, context is the key to that interleaving. The design space provides the R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 241 Fig. 3. The HOPP pattern language. problem context. If a pattern from one language fits that context then the designer can apply the pattern. This modifies the problem and context, and the designer must search for a pattern in either language that best fits the modified problem context. The interleaved sequence thus intertwines the contexts of each language. Applying the above outlined principles for reconstructing a pattern language from sequence will, in the case where the sequence is interleaved from two languages, result in a third, distinct language that combines the original two languages. 6.3. An example Consider an application where we wanted to implement H ALF O BJECT P LUS P ROTOCOL using the C++ programming language. H ALF O BJECT P LUS P ROTOCOL (HOPP) was originally conceived as a single pattern [21]. However, an exploration of similar problems and forces on the c2.com WikiWiki Web discussion forum suggests that it is probably a small pattern language [20]. To implement the HOPP pattern language in C++, we might combine the HOPP pattern language with the pattern language for building class structures in C++: the so-called “idioms” pattern language [11]. The HOPP pattern language has the structure shown in Fig. 3. The patterns can be summarized by the following intents. For a more complete description of these patterns, see [20]. L OCAL P RESENCE If you have a single design entity that must appear in and serve multiple contexts in the design, then clone the entity for each context, resulting in a shared, distributed entity. AUTONOMOUS C OPY If a L OCAL P RESENCE is asked to perform an operation that does not modify the object state, then execute that responsibility locally as a const member function. S YMMETRIC R EFERENCE If two objects must maintain a relationship for some time, then synchronize data changes for non-const public methods of both objects to keep collaborators informed. R EMOTE P ROCEDURE C ALL If you need to access functionality across process boundaries or processor boundaries, use a protocol that makes remote procedure calls as transparent as local procedure calls. S PLIT T REE F ROM L EAVES Avoid the cost of updating entire hierarchical data structures by updating the structure separately from the content. 242 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 Fig. 4. The C++ idioms pattern language. The idioms pattern language has the structure shown in Fig. 4. The intents of some of the patterns of interest are as follows; for a more complete description of these patterns, see [11]. H ANDLE B ODY Split each analysis-level object into two implementation objects, one of which represents the identity and signature of the object, the other of which represents the structure and implementation of the object (separate interface from implementation). C OUNTED B ODY If a client wants a local, physical copy of a local object, make a local logical copy that is a handle that references the original body and which is accounted for by a reference count in the original body. The logical copy’s const member functions directly use the structure of the original body, and the non-const member functions clone their own copy of the body on demand. E NVELOPE L ETTER Derive the classes for handle class objects and body class objects from the same base class so that a single handle is plug-compatible with several different bodies. The handle does not need to know a separate interface for the body objects; they are of the same “type” as the handle. V IRTUAL C ONSTRUCTOR Allow a handle to build an object of its own class hierarchy, of a type that is chosen from some supplied context. A BSTRACT FACTORY Allow an object to clone itself, returning a handle/body pair where the handle is of some generic type and the body has the same concrete type as the object for which the cloning request was made. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 243 The question is: how do we combine the structure of the two languages? The answer lies in the sequences used to build each of the myriad systems that these two languages together generate. Let us say that we want to make a component of type DataCall according to these two pattern languages. This might be a connection through a data switch between two mutually remote computing contexts. The two “half-call” objects should behave as one conceptual call object. Where do we start? (1) We want to make a well-behaved C++ class, so we start with H ANDLE /B ODY. Next, we would apply L OCAL P RESENCE to create the object in the second computing context. (2) To “refine” L OCAL P RESENCE to the C++ context we would apply E NVE LOPE /L ETTER and V IRTUAL C ONSTRUCTOR. This allows us to parametrize the state of a new DataCall object in the second computing context, using information from the first computing context to give the new object the same state (and of course the same type) as the original. (3) Next, we adjust the member functions of DataCall according to AUTONOMOUS C OPY, reflecting the fact that some member functions can execute locally. (4) Then we use S YMMETRIC R EFERENCE to update the non-const member functions of DataCall. This is the “update protocol” that Meszaros describes in the original HOPP. (5) We might refine this pattern with R EMOTE P ROCEDURE C ALL; however, there are other possibilities that build on DCOM or CORBA or shared memory. (6) Last, we might note that local computing contexts use DataCall in a call-by-value context, and we might use C OUNTED B ODY to support such use. This combination of patterns represents a sequence. Suppose we had several kinds of DataCall objects; that is, that the logical system design exhibited a class hierarchy beneath DataCall. The process would be much the same as above, except that now we would also incorporate the pattern H ANDLE /B ODY H IERARCHY. We would apply that pattern after applying H ANDLE /B ODY and before L OCAL P RESENCE. That represents another sequence. There are many other possibilities; such as a configuration each with and without S PLIT T REE F ROM L EAVES. Each combination of patterns results in a new sequence. These sequences together all precipitate from one common pattern language. The structure of that pattern language can be inferred from the structures of the sequences, that is, from the composition precedence relationships between them. Each sequence is a total ordering of patterns. Each pattern language is a poset. Looking at these sequences, we can work backwards to create the pattern language. The resulting pattern language from our example might look like Fig. 5. 6.4. Another example One of the problems with providing examples of merging pattern languages is that, as yet, there are only a few published pattern languages from which examples can be sourced. Something very like the merging of pattern languages occurs, however, during the process of learning to program. The conceptual understanding that a novice has at any 244 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 Fig. 5. The merged language. particular stage of his/her learning can be seen as a pattern language, and this language is modified as the novice learns new concepts. If a new concept is at all complex then it forms a small pattern language in its own right, and adding the new concept to the novice’s existing language represents a merging of two languages, not just a simple attachment of a concept to a language, or of one language to another. The example below illustrates such a case. In that example, the pattern languages do not necessarily reflect a realistic view of the programming situation, just that held by the novice at a particular stage of his/her development. Similarly, the use of various Java constructs as the names of the patterns is simply a device to minimize the need for explanation. The patterns so named are both more than, and looser versions of, the Java concepts concerned. For example, the pattern called Class might be better named Class-as-Blueprint, Method might be better named Methodas-Action-Sequence, and so on. A novice might begin by learning the ubiquitous first program “Hello, World!”, in which case he/she would be likely to have the pattern language in his/her head shown in Fig. 6. Notice that this pattern language can only generate one sequence. This is why this is the simplest possible program, as there are no real design choices to be made. The pattern language can develop only the one type of program, that being the output of a literal to the screen. A novice might then move on to examine the variable concept, which, in isolation, can be regarded as a small pattern language in its own right, as shown in Fig. 7. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 245 Fig. 6. The language for “Hello, World!”. Fig. 7. The language for the variable concept. By the use of example programs, which are, after all, made up of pattern sequences, the novice would then likely attempt to fit this isolated understanding of the variable concept into the understanding of the Java language that she/he already has. In other words, the novice merges the two pattern languages. One sequence, based on the use of an instance variable is: C LASS - VARIABLE - D ECLARATION - I NITIALIZATION - C LASS - M ETHOD S TATEMENT S EQUENCE - O UTPUT S TATEMENT. Another sequence, explaining the use and initialization of a local variable is: C LASS - M ETHOD - S TATEMENT S EQUENCE - VARIABLE - D ECLARATION I NITIALIZATION - S TATEMENT S EQUENCE - O UTPUT S TATEMENT. A further example demonstrates how an assignment statement can be used to change the value of an instance variable: C LASS - VARIABLE - D ECLARATION - C LASS - M ETHOD - S TATEMENT S EQUENCE A SSIGNMENT - S TATEMENT S EQUENCE - O UTPUT S TATEMENT. The generation of the sequences shown here could be accomplished in several ways, such as by studying simple programs provided in texts or course materials, or even by trial and error programming given some basic knowledge of the instance and local variable concepts. Weaving these sequences according to the process explained earlier in this section would then result in the merged language shown in Fig. 8. This example illustrates how people progress through levels of understanding. New concepts, as they are learned, need to be fitted into an existing mental picture, and complex concepts usually cause a shuffling of the current understanding of the kind shown in this example. 246 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 Fig. 8. The merged language. 7. The composition process 7.1. A formalization of the composition We can define composition of pattern languages more formally in this way: A pattern language consists of elements called patterns. Consider patterns a1 and a2 from pattern language A, and patterns b1 and b2 from pattern language B. Both A and B are posets under a pattern ordering relation <. A and B represent geometries over non-disjoint spaces. The < relation formalizes the sequence relationship between the patterns; it indicates the order in which patterns can be applied. Within a pattern language, a1  a2 (the pattern composition of a1 and a2) makes sense only if a1 < a2. Assume that a1 < a2 and b1 < b2. Then we can insert a pattern a1 between b1 and b2 if b1 < a1 and a1 < b2. If for no such a1, b1 and b2 does it hold that b2 < b1, and likewise for any composition of any a1 with any b1 such that a1 < b1 and b1 < a2, then we say that A and B have a valid composition, A  B, that can be constructed by the indicated ordering of the patterns, and that A  B is a poset. More formally, each of the elements called a pattern is a function that composes with its adjoining patterns, and for which the < relation indicates the possible order of composition. Each of the pattern languages forms a sort of similarity group [15]. The composition also forms a similarity group. 7.2. Pattern language independence Multiple pattern languages may have patterns in common or patterns that overlap. We can still merge two pattern languages with common patterns merely by ensuring that each pattern is properly ordered in the composed language with respect to all of the compositions in each of the smaller languages being combined. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 247 Some pattern languages should not be combined. Some languages may succumb to a formal partial ordering of patterns, but that does not mean they make sense. Domain boundaries are sometimes cultural, historic, or artificial and may violate otherwise valid technological concerns. For example, object orientation encourages good de-coupling and good local cohesion. However, there are aspects of telecommunications that sometimes make it difficult to decouple modules. A high level call control module may need signaling data from the lowest level modules of the architecture, or the upper levels of a protocol stack may choose to take advantage of low level protocol information to optimize performance, decrease latency, or enhance reliability. Such an architecture would not be in concert with object-oriented principles. At the pattern language level, what is happening is that the introduction of object orientation causes new forces to arise, and the original telecommunications patterns may no longer capture a good modularization of forces. It would be inadvisable to combine all the patterns of a pattern language for object-oriented design with all the patterns of a pattern language for high availability classic telecommunications. It is also true that it makes sense to combine two pattern languages only if they operate on some space in common. Composition makes no sense for independent pattern languages, such as a pattern language for houses and a pattern language for C++ idioms. 8. Relationship to aspects and features Patterns have often been characterized as a way to express cross-cutting structure in a system. This view is consistent with Alexander’s original view that true systems are not modular, and is also in concert with popular software characterizations of patterns as describing micro-architectures: configurations between objects or classes. Aspect-oriented programming is characterized the same way [13]. Most aspects do not capture any generalized context for their application, and this makes it difficult (if not impossible) to compose interfering aspects. This is particularly problematic in AspectJ, where there is no tie from the context of aspectualized code back to the aspect that modifies it or to any other aspects. This is one of the most difficult problems with aspect composition and feature interaction analysis to date. By incorporating the notion of context, pattern languages make it possible to compose multiple systems of cross-cutting structure with each other. One area of future research related to context and cross-cutting relates to the composition filter formalization of aspects [9]. In this formalization, each aspect’s context is manifest as a link between the corresponding filters. It is likely that the technique applied here extends to composition of aspects based on this formalism. Furthermore, if “features” can be formalized as pattern languages—which is likely— this formalism for combining pattern languages might provide a basis for feature combination. Patterns and pattern languages might be the right formalism for addressing the feature interaction problem. We welcome additional research along these lines. 9. Conclusion By selecting patterns from two pattern languages according to the needs of emerging context, developing a sequence of those patterns, and creating a partial ordering of the 248 R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 sequence with respect to scale, structural refinement, and other domain knowledge, we can combine multiple pattern languages into a single pattern language. But just because it is possible to do this does not mean it should always be done; sometimes it is better to leave individual pattern languages alone. One can compose pattern languages pairwise; composing more than two pattern languages reduces to successive pairwise compositions, and the result is sensitive to the composition order. The activity is largely informal and builds on domain knowledge, as we believe is appropriate. The model could further be refined into a fully formal model based on symmetry and symmetry groups, but at this point, it is difficult to establish the value of such formalism. We encourage readers to try this approach and to notify the authors of successes and challenges in its application, and we encourage follow-up exploration, research, and publication in this area. Acknowledgements We give many thanks for inspiration and comments from Joe Davison and Neil Harrison. References [1] M. Adams, J. Coplien, R. Gamoke, R. Hanmer, F. Keeve, K. Nicodemus, Fault-tolerant telecommunication system patterns, in: L. Rising (Ed.), The Patterns Handbook: Techniques, Strategies, and Applications, Cambridge University Press, New York, 1998, pp. 189–202. [2] C. Alexander, Notes on the Synthesis of Form, Harvard University Press, Cambridge, MA, 1964. [3] C. Alexander, The Oregon Experiment, Oxford University Press, New York, 1975. [4] C. Alexander et al., A Pattern Language, Oxford University Press, New York, 1977. [5] C. Alexander, The Timeless Way of Building, Oxford University Press, New York, 1979. [6] C. Alexander, A Foreshadowing of 21st Century Art: The Color and Geometry of Very Early Turkish Carpets, Oxford University Press, New York, 1993. [7] C. Alexander, The Nature of Order; Book 2: The Process of Creating Life, Draft of January 1997, pp. 299–302. [8] C. Alexander, The Nature of Order, Pending publication by Oxford University Press, New York, NY, 2002. [9] L. Bergmans, M. Aksit, Composing crosscutting concerns using composition filters, Communications of the ACM 44 (10) (2001) 5157. [10] J. Coplien, Multi-Paradigm Design for C++, Addison-Wesley, Reading, MA, 1999. [11] J. Coplien, C++ idioms patterns, in: B. Foote, N. Harrison, H. Rohnert (Eds.), Pattern Languages of Program Design 4, Addison Wesley, Reading, MA, 2000, pp. 167–197 (Chapter 10). [12] J. Coplien, Multi-paradigm design, Ph.D. Thesis, Vrije Universiteit Brussel, May 2000. See http://users.rcn.com/~jcoplien/Mpd/Thesis/Thesis.pdf (viewed 7 August 2003). [13] J. Coplien, E. Pulvermüller, A. Speck, A version model for aspect dependency management, in: Proceedings of the Third International Symposium on Generative and Component-Based Software Engineering, GCSE 2001, September 2001, Erfurt, Germany, Springer-Verlag, Erfurt, Germany, 2001. [14] J. Coplien, L. Zhao, Symmetry breaking in software patterns, in: G. Butler, S. Jarzabek (Eds.), Lecture Notes in Computer Science Series, vol. 2177, Springer-Verlag, Berlin, 2000, ff. 37. [15] U. Grenander, Elements of Pattern Theory, Johns Hopkins University, Baltimore, 1996, p. 81. [16] R.E. Grinter, Recomposition: putting it all back together again, in: Proceedings of ACM Conference on Computer Supported Cooperative Work, CSCW ’98, 14–18 November 1998, Seattle, Washington, 1998, pp. 393–403. [17] E.T. Hall, The Dance of Life: The Other Dimension of Time, Doubleday Anchor Books, New York, 1983. [18] N. Harrison, J. Coplien, Pattern sequences, in: A. Rüping, C. Schwanninger (Eds.), Proceedings of the 6th European Conference on Pattern Languages of Programs 2001, UVK Universittsverlag Konstanz GmbH, Konstanz, Germany, 2002. R. Porter et al. / Science of Computer Programming 56 (2005) 231–249 249 [19] N. Harrison, J. Coplien, Organizational Patterns of Agile Software Development, 21 July 2003, http://www.easycomp.org/cgi-bin/OrgPatterns?BookOutline. [20] Hopp Pattern Language, On the WikiWiki Web, 19 July 2003. http://c2.com/cgi/wiki?HoppPatternLanguage. [21] G. Meszaros, Pattern: half-object + protocol (HOPP), in: J. Vlissides et al. (Eds.), Pattern Languages of Program Design–2, Addison-Wesley, Reading, MA, 1996.