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.