The Shape of Things
Dismissing patterns as a programming buzzword is missing the point. Recognizing them during the design phase can help you in the long run.
It all started in 1977. That year, architect Christopher Alexander published
A Pattern Language; Towns, Buildings, Construction. In it, Alexander
introduced the concept of a design pattern to the language of architecture.
A design pattern represents a common way of solving a particular problem,
ranging from such small-scale issues as lighting a space in a pleasing
manner to the large-scale arrangement of communities in a region. Of these
patterns, Alexander says "Each pattern describes a problem which occurs
over and over again in our environment, and then describes the core of
the solution to that problem, in such a way that you can use this solution
a million times over, without ever doing it the same way twice." By identifying
patterns that commonly occur in the realm of architectural and urban design,
Alexander sought to make it easier for non-professionals to communicate
in these realms. Abstracting away the details of a particular building
makes it much easier to discuss building in general.
Although Alexander's work has been influential in architecture (and still
is; check out his web site at www.patternlanguage.com),
for our purposes its major impact has been in computer science. In 1995
Addison-Wesley published Design Patterns: Elements of Reusable Object-Oriented
Software, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides,
who have since become routinely identified as software's "Gang of Four."
This book took the design pattern concept and applied it to software,
identifying 23 patterns that applied to many object-oriented software
systems.
Since then, design patterns have become something of an industry in computer
science. A search for "patterns" in Fatbrain's technically oriented bookstore
turns up 4,500 titles; a Google search on the phrase "design pattern"
gets just over 100,000 hits (a search on the phrase "Britney Spears" gets
just over 600,000 hits, so don't be too impressed). A good place to start
(although boobytrapped with dead links) is the Patterns Home Page at http://hillside.net/patterns/.
Start from there, and you can follow patterns all over the web. You'll
find patterns in architecture, design, implementation, user interfaces,
and quality assurance. You'll find patterns in every computer language
you've ever heard of, and some that you haven't. You'll find pseudo-patterns
and anti-patterns. I suspect most of you readers have at least heard of
design patterns and the Gang of Four.
Sidebar |
Is this sort of column useful to you, or
am I just hanging out with the wrong bunch of developers?
Write me at [email protected]
to let me know! Comments may be used in a future issue
of Developer Central, unless you ask me to keep them confidential.
|
|
|
Despite their pervasiveness as buzzwords, though, I find that very few
developers really have a solid understanding of patterns. Too often, developers
dismiss patterns as templates or recipes for solving a problem, which
completely misses the point. I suspect the misconception accounts for
the failure of many developers to actually take the time to read and study
the Design Patterns book; surely something written six years ago couldn't
contain the recipe to solve the problem you're having today, could it?
To get a real sense of the importance of patterns, you have to start
with machine language-you know, the actual ones and zeroes running around
inside of the computer and telling it to do things. Now, I know most of
you have never had the experience, but back in the day the first computer
I programmed was an Altair 8800. Programs were input one instruction at
a time by flipping switches up for a one and down for a zero (or was it
the other way around? Memory fades). The term project was to successfully
run a program for integer long division (by repeated subtraction, of course).
When you're working in machine language, it's hard to keep track of anything
more complex than long division. The focus is just too narrow.
Then came assembler. With an 8080 assembler program, instead of writing
11000010, I could write JNZ, and a program would translate the mnemonic
into ones and zeros later. The savings of five characters is insignificant;
what matters is that the mnemonic instructions like JNZ and MOVAH and
INXH make it possible to think about software in terms of what's going
on, rather than in the microprocessor's terms. With assembler, you can
get a long division algorithm going in a couple of hours instead of an
entire school term.
The next step up the chain of abstraction (and the place where most developers
today start) is the high-level language. Now if you want integer division
you just write something like intResult = intA \ intB. Interpreters, compilers,
and assemblers will turn this into all the ones and zeros you'll ever
need. Meanwhile, you're free to grasp a program on a statement-by-statement
basis. At this level, you're divorced almost completely from the hardware,
and programming starts to become the stuff of pure thought.
One more level up takes you to algorithms and data structures. Just as
high-level languages abstract away the details of the underlying hardware,
algorithms and data structures abstract away the details of the underlying
language. You can take the data structure of a hash table (a plan for
storing ten gallons of slop in a five-gallon bucket, just in case you've
never run across one) and implement it in C++ or Visual Basic or Lisp
or whatever language your boss wants you to use this week. The algorithm
for performing a depth-first search of a binary tree is another example
of an abstraction that can be implemented in many languages. When you
start thinking at this level, software construction becomes a lot more
fun. Now, instead of laboring over code a line at a time, you're hooking
up B-tree storage to bulletproofed I/O routines and a graphics library.
It's like building a house out of prefab parts instead of two by fours.
But sadly, that's where many software developers start: just short of
the level of abstraction represented by design patterns.
As defined by the Gang of Four, there are four parts to a design pattern:
- The pattern name gives you a way to refer to the entire pattern.
That's as important as the step from ones and zeros to assembler instructions.
If you share a vocabulary of patterns with another developer, she'll
know what you mean when you wonder whether to implement a Decorator
or a Strategy in your software.
- The problem describes where to apply the pattern.
- The solution describes the way to solve the problem. This description
tends to be very abstract, couched in terms of objects and classes rather
than software implementation.
- The consequences describe the trade-offs involved in implementing
the solution.
To take an easy example: the Singleton pattern addresses the problem
of how to maintain exactly one instance of an object, and to have global
state without global variables. The solution is to use a class that always
returns the same internal hidden instance when it's asked for an instance.
The consequences include the potential benefit of security checking when
someone asks for an instance. (That's the stick-figure description of
Singleton. In the Design Patterns book, the discussion of Singleton
takes eight pages.)
Patterns are not easy. Some of the design patterns in the Gang of Four's
book stretch over many pages of discussion and sample implementations
(in C+ and Smalltalk). Just understanding the details of a pattern such
as Observer can take quite a bit of study.
But there's a payoff to this study: ultimately, design patterns help
you solve design problems more quickly. Suppose you're working on the
Next Big Desktop Application, and one piece that your team is dealing
with is the need to keep a table of data in one window synchronized with
a 3D chart of the same data in another window. Your team could spend days
in design meetings trying to work out the right combination of objects,
events, data structures, and algorithms to meet your goal. Or your team
discussion could start out like this:
- "You know, this looks like a pretty typical instance of the Observer
pattern."
- "You're right. But how are we going to get the unexpected update problem
under control?"
The beauty of design patterns is that they make such discussions possible
by giving the participants a shared vocabulary at a high level of abstraction.
And by encapsulating the wisdom of members of the object-oriented design
community who share decades of experience, design patterns help you benefit
from that experience as well. You don't need to reinvent the wheel if
you have a design pattern that points out how well circular objects roll.
One reason many developers of my acquaintance have managed to remain
happily ignorant of design patterns is that Visual Basic and its derivatives
are really cruddy languages for the sort of deep object orientation that
this stuff requires (there have been attempts at defining Visual Basic
design patterns; I'm not aware of any that were vastly successful). That,
I think, is about to change. With the coming of the .NET platform, VB
and VBA developers have the choice of migrating to VB .NET or C#. Either
one offers a language with all the object-oriented goodies you could ever
want-and either one presents you with a good reason to get familiar with
the patterns literature to increase your effectiveness, and ultimately
your salary, as a developer.