Continuing his history of Parameterise from Above, Kevlin Henny looks at Singletons and Context Objects.
The odyssey of the PARAMETERIZE FROM ABOVE (PfA) pattern started in 2001. It emerged from a recurring recommendation made during design consultancy [ Henney2007a ] and matured through its incorporation in the Programmer's Dozen collection of thirteen recommendations [ Henney2007b ]. The essence of the pattern is that parameterization is better done through explicit parameters at the point of configuration or call than through the automagic and coupling of global state.
In this third instalment of 'The PfA Papers', I will continue to chart the emergence and refinement of PARAMETERIZE FROM ABOVE by pursuing another strand in its history and development: the context object. (Although it may seem a little strange to chart the development of a pattern that has yet to be documented, things can exist in a culture without actually, err, needing to exist, so to speak.)
Context objects
The brute-force approach to capturing and passing execution context between components in a program sidesteps the question of passing altogether: represent the execution context as global state in the program.
If you are feeling a little guilty about having global variables in your code (sometimes they are called static variables just to assuage your guilt), you can always use SINGLETON - it may not do much for the quality of your code, but you get to accumulate another Gang-of-Four pattern-usage point! (Yes, there are teams and developers who do something like this and take it seriously.) However, whichever way you look at it, SINGLETON simply wraps up the global state and puts a nice face on it. SINGLETON doesn't address the deeper issues of coupling and hardwiring that are the real problem with global variables. And, for good measure, SINGLETON makes the basic problem harder by introducing new challenges, such as the subtleties involved in correctly initialising a Singleton in a multithreaded environment.
However, this is not just a random excuse to pick on the faults of Singleton and global variables. In a system where the code, the program state, the execution paths, etc., are all partitioned across projects, packages, classes and functions, objects, processors and threads, and so on, the notion of global state is less meaningful and less manageable. This is the root of the problem.
OK, so perhaps a little PfA would do the trick? Well, the smallest application of PfA you can have is to pass a single argument of simple type. So, it stands to reason that a slightly larger application of PfA is to pass two arguments, each of simple type. A little induction suggests that you can pass all the execution context you ever need by having a sufficiently long argument list. However, a little reality check tells you that this is not going to work out too well: long argument lists are a pain [ Henney2006 ]. As Alan Perlis once put it [ Perlis1982 ]:
If you have a procedure with 10 parameters, you probably missed some.
The issue is that not only is a long argument list cumbersome, its content is inherently unstable. It is the wrong application of PfA: rather than PfA in sprinkles, you need to PfA in chunks. The solution is to recognise that the unit of stability is the concept of what the argument list represents - the context - and not the individual elements. What you parameterize should ideally be aligned with the concept as a whole and the unit of stability, which, in this case, means that you pass through an object representing the context, not a fragmented set of individual properties. Of course, that's not the end of the story: if you treat your context object as little more than a bucket of arbitrary parameters, you shouldn't be surprised when it degenerates into a bucket of arbitrary parameters.
From prehistory to the present
There are many ways to look at patterns: one is that a pattern is a recurring practice; another identifies the pattern as the documented description of said practice. The former view means that many patterns are in use without documentation or even agreement on a common name: they are just 'the way we do things here' or 'how I've always seen that problem solved most effectively'. The latter view emphasises that pattern authors do not own the patterns they describe: they own their descriptions. You cannot steal a pattern, only be inspired by its description or application.
Taking these two views together, it seems obvious that there can be many competing descriptions for the same practice. Some of these may emerge independently; some of these may be related by refinement or specialisation to a context. So it is with the CONTEXT OBJECT pattern. The story of CONTEXT OBJECT's description in pattern form is a little like a long wait for a bus, only to have two (or more) turn up at once.
In 2002 Allan Kelly started documenting what came to be called ENCAPSULATED CONTEXT and has since been included in Pattern Languages of Program Design 5 in 2006 [ Manolescu+2006 ]. It was some of the discussion and feedback around the pattern that prompted me to write up CONTEXT ENCAPSULATION, a pattern language of four patterns that covered the design space of context objects - as it turned out, a small pattern language but a big paper. This paper was workshopped at the EuroPLoP conference in 2005 [ Henney2005 ]. The root pattern description went on to form the basis of the CONTEXT OBJECT write-up in POSA4 [ Buschmann+2007a ].
This thread of history is interwoven with other threads, making the timeline a little more tangled. In September 2003 I was in Oslo attending the JavaZone conference. John Crupi, one of the authors of Core J2EE Patterns [ Alur+2003 ], was presenting some of what was new in the second edition of that book, including - you guessed it - the CONTEXT OBJECT pattern. I was there presenting the Programmer's Dozen [ Henney2007b ], so the connection to PfA was reinforced, as was the commonality with Allan's work.
It turns out that 2005 was a busy year for CONTEXT OBJECT on the pattern conference front: I submitted CONTEXT ENCAPSULATION at EuroPLoP in Bavaria; Arvind Krishna, Doug Schmidt and Michael Stal wrote a version of CONTEXT OBJECT as a standalone pattern for PLoP in Illinois [ Krishna+2005 ]; Uwe Zdun included CONTEXT OBJECT as one of a collection of patterns at VikingPLoP in Finland [ Zdun2005 ]. Each paper took a different point of view and placed the pattern in a different context, but the recurrence and soundness of the practice was clearly established. And, because pattern papers are considered to be works in progress, later versions of each paper cross-referenced one another!
The idea of capturing execution context as an object or some kind of structure is perhaps older than you think. For example, in the 1970s the technique was used in Scheme's eval procedure to provide context for evaluation of an expression [ Abelson+1984 , Scheme ]. It has also appeared in pattern form many times, but hidden as part of a larger pattern. For example, CONTEXT OBJECT is a key player in the INTERPRETER pattern [ Gamma+1995 ], which, with hindsight, can be seen as a pattern compound comprising COMMAND, CONTEXT OBJECT and COMPOSITE Buschmann+2007b]. Likewise, CONTEXT OBJECT plays an essential role in the INTERCEPTOR pattern [ Schmidt+2000 ]. More explicitly, PARAMETER OBJECTSs or ARGUMENTS OBJECTs have also previously been identified and described in pattern form [ Noble1997 , Fowler1999 ].
So, it's not just that two (or more) buses turn up at the same time: quite a few buses have already been past.
Encapsulated Context
Documenting a pattern is a journey of understanding, with snapshots taken along the way. One example of how things can change is the name. Allan's pattern description started life with the longer, imperative name of ENCAPSULATE EXECUTION CONTEXT. This was later shortened to ENCAPSULATE CONTEXT. The directive-based name then shifted to a noun phrase that described the resulting outcome, ENCAPSULATED CONTEXT.
My interest and involvement goes back to the ENCAPSULATE EXECUTION CONTEXT days, but what happened later was just as interesting [ Henney2005 ]:
It all started a couple of years ago
There was recognition that the scope of the pattern was perhaps greater than could be contained conveniently within a single pattern. Most of the subtlety was in realizing the pattern effectively, and the options available and decisions that needed to be taken formed a long tail in the presentation of the pattern. Following its inclusion in the EuroPLoP proceedings [ Kelly2003 ], the paper was also published in the ACCU's Overload magazine [ Kelly2004 ], where it generated some heated discussion on the editorial review team [ Overload2004 ] and the letters page [ Overload2005 ]. Although ENCAPSULATED CONTEXT's description contained careful discussion of how to avoid having a context object turn into an uncohesive blob of code, this discussion sometimes appeared to be overlooked.
Allan managed to sum up the tension felt by someone struggling not just with the root problem that leads to ENCAPSULATED CONTEXT, but also in its effective application [ Henney2005 ]:
The devil is in the detail.
You have this system...
- Try globals... well, probably you don't: the one thing you learned in school was no globals.
- You try for SINGLETON, it is in the book, it is good... but then you find you have these nasty ripples... then someone tells you it's a bad thing and it's obvious to you.
- So you try passing parameters: they overwhelm you. You refactor a bit (à la Fowler) and before you know it you've got ENCAPSULATED CONTEXT.
- You carry on down this path, you get more mileage here, but over time it starts to look like Foote's BIG BALL OF MUD.
The solution is to reduce the coupling, improve the cohesion, but how?
The question of how to deal with the BIG BALL OF MUD is an important consideration in applying the pattern. Don't mention it, and that will be considered an oversight or weakness of the pattern. However, documenting everything as equally significant is likely to overwhelm the reader. The core advice remains sound, but what is needed is separation.
Context Encapsulation
It was this question of communicating the core idea while still communicating the follow-on considerations, as well as the flurry of correspondence in Overload, that got me interested in looking at ENCAPSULATED CONTEXT from a different point of view [ Henney2005 ]:
Recasting the pattern in terms of a pattern language rather than a single pattern allows the flow of design issues to be identified more explicitly, promoting each of the considerations and decisions as a response to the issues raised in another pattern. Instead of considering the coupling and cohesion issues as simply being implementation details within a single pattern, the design process is made more explicit by naming and connecting some of these design decisions. Pulling support patterns out of a larger root pattern helps to manage pattern scope, which can otherwise creep with each new consideration that is incorporated.
At the beginning of 2005 I had been playing around with the idea of reasoning about pattern languages in terms of processes, which gave rise to a grammatical perspective, and relating this to pattern compounds and pattern sequences. That sounds like a lot of abstract pattern theory, but does it have any practical application? The discussion about ENCAPSULATED CONTEXT came along at just this point. I realised that it might offer a particular vehicle for exploring the idea in a practical way: small enough to keep down to a handful of patterns and combinations; rich enough and real enough to illustrate the idea in practice.
The Context Encapsulation pattern language contains four patterns. The root of the language is ENCAPSULATED CONTEXT OBJECT, a name that blends ENCAPSULATED CONTEXT with CONTEXT OBJECT. The other three patterns in the language address the design decisions that can flow from an ENCAPSULATED CONTEXT OBJECT. These four protagonist patterns are summarised as follows [ Henney2005 ]:
ENCAPSULATED CONTEXT OBJECT: Pass execution context for a component, whether it is a layer or an individual object, as an object rather than as a long argument list of individual configuration parameters or implicitly as a global service. The execution context may include external configuration information and services such as logging.
DECOUPLED CONTEXT INTERFACE: Reduce the coupling of a component to the concrete type of the ENCAPSULATED CONTEXT OBJECT by defining its dependency in terms of an interface, whether interface or INTERFACE CLASS, rather than the underlying implementation type. This allows substitution of alternative implementations, including NULL OBJECTS and MOCK OBJECT.
ROLE-PARTITIONED CONTEXT: Split uncohesive ENCAPSULATED CONTEXT OBJECT interfaces into smaller more cohesive context interfaces based on usage role, each expressed with a DECOUPLED CONTEXT INTERFACE or through a ROLE-SPECIFIC CONTEXT OBJECT.
ROLE-SPECIFIC CONTEXT OBJECT: Multiple context interfaces may be realized either together in a single object or with one object per role. The latter option allows independent parts of a context to be more loosely coupled and separately parameterized.
The devil may well be in the details, but the details are in the paper. 'The PfA Papers' is intended to shed light on the history and insights around PARAMETERIZE FROM ABOVE, so we should probably get back to the main act.
And so to
Given the undocumented state of the PARAMETERIZE FROM ABOVE pattern, it is perhaps noteworthy that tucked away in the notes at the end of CONTEXT ENCAPSULATION is a discussion of PfA and the relationship both to the patterns in the paper and elsewhere. The notes include the following summary of PARAMETERIZE FROM ABOVE:
Within a layered system, some commonly used complex objects or simple values, used by different layers or by many different parts of a given layer, may find themselves expressed in global form, e.g. as SINGLETON or MONOSTATE objects. This parameterizes components from below, but hardwires their dependencies, increasing the coupling of the component and making alternatives difficult or impossible to substitute. Instead, invert the relationship, so that these objects are passed in from above, i.e. so that the calling or owning component in the layer above passes in the appropriate instance.
The relationship to CONTEXT OBJECTs is also made clear:
Whether in terms of individual parameterizing integers or larger- scale, architecturally significant objects, to PARAMETERIZE FROM ABOVE represents a common reaction to unnecessary system-wide hardwiring of certain assumptions and facilities, and hence it is often employed in reaction to global variables, SINGLETONs, etc. Thus, an ENCAPSULATED CONTEXT OBJECT is an application of PARAMETERIZE FROM ABOVE, made more specific with respect to its context (sic) of application and its decomposition in terms of other patterns.
References
[ Abelson+1984] Harold Abelson, Gerald Jay Sussman and Julie Sussman, The Structure and Interpretation of Computer Programs , MIT Press, 1984
[ Alur+2003] Deepak Alur, John Crupi and Dan Malks, Core J2EE Patterns , 2nd edition, Addison-Wesley, 2003
[ Buschmann+2007a] Frank Buschmann, Kevlin Henney and Douglas C Schmidt, Pattern-Oriented Software Architecture , Volume 4: A Pattern Language for Distributed Computing , Wiley, 2007
[ Buschmann+2007b] Frank Buschmann, Kevlin Henney and Douglas C Schmidt, Pattern-Oriented Software Architecture, Volume 5: On Patterns and Pattern Languages , Wiley, 2007
[ Fowler1999] Martin Fowler, Refactoring , Addison-Wesley, 1999
[ Gamma+1995] Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, Design Patterns , Addison-Wesley, 1995
[ Henney2005] Kevlin Henney, 'Context Encapsulation', EuroPLoP 2005, July 2005, http://www.two-sdg.demon.co.uk/curbralan/papers/europlop/ContextEncapsulation.pdf
[ Henney2006] Kevlin Henney, 'Long Argument Lists', Reg Developer , June 2006, http://www.regdeveloper.co.uk/2006/06/28/argument_lists/
[ Henney2007a] Kevlin Henney, 'The PfA Papers: From the Top', Overload 80 , August 2007, http://accu.org/index.php/journals/1411
[ Henney2007b] Kevlin Henney, 'The PfA Papers: The Clean Dozen', Overload 81 , October 2007, http://accu.org/index.php/journals/1420
[ Kelly2003] Allan Kelly, 'Encapsulate Context', EuroPLoP 2003, June 2003
[ Kelly2004] Allan Kelly, 'Encapsulate Context', Overload 63 , October 2004, http://accu.org/index.php/journals/246
[ Krishna+2005] Arvind S Krishna, Douglas C Schmidt and Michael Stal, 'Context Object', September 2005, http://www.dre.vanderbilt.edu/~arvindk/Context-Object-Pattern.pdf
[ Manolescu+2006] Dragos Manolescu, Markus Voelter and James Noble (editors), Pattern Languages of Program Design 5 , Addison-Wesley, 2006
[ Noble1997] James Noble, 'Arguments and Results', The Computer Journal , 1997, http://citeseer.ist.psu.edu/107777.html
[ Overload2004] 'Editorial', Overload 64 , December 2004, http://accu.org/index.php/journals/249
[ Overload2005] 'Letters to the Editor', Overload 65 , February 2005, http://accu.org/index.php/journals/259
[ Perlis1982] Alan J Perlis, 'Epigrams in Programming', ACM SIGPLAN , September 1982, http://www.cs.yale.edu/quotes.html
[ Scheme] 'Scheme in Scheme', http://academic.evergreen.edu/curricular/fofc00/eval.html
[ Schmidt+2000] Douglas C Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann, Pattern-Oriented Software Architecture, Volume 2: Patterns for Concurrent and Networked Objects , Wiley, 2000
[ Zdun2005] Uwe Zdun, 'Patterns of Argument Passing', VikingPLoP 2005, September 2005, http://wi.wu-wien.ac.at/~uzdun/publications/arguments.pdf