If you think object-oriented development is hard to do well, try pattern development! The mathematician in me likes to think of it as the ``integration'' of object-oriented design: it's the sum of innumerable little experiences over an interval of applications.
Yet pattern development seems a good deal harder than what I learned in calculus class.
Integrals don't interfere with one another, which lets you solve them independently (although knowing how to solve one often helps you solve others).
A pattern, in contrast, doesn't work in a vacuum. It provides the solution to just one problem; so it must cooperate with other patterns. Therefore a pattern writer must contemplate not one pattern but several, even some as yet unwritten. And that's but one of many challenges in the pattern development process.
If you're an aspiring pattern writer, you'll need all the help you can get.
We certainly learned a lot about pattern development in writing Design Patterns. So what I've tried to do this time is boil down our experience into seven habits we adopted, largely unconsciously, over the four-some-odd years it took to write the book.
Taking these habits to heart should help you hone your pattern-writing abilities far faster than we did.
The single most important activity in pattern writing is reflection. Bruce Anderson, an early influence on our work, has offered up this mantra for years. Take time off periodically to reflect on what you've done. Think about the systems you've built, the problems you've had, and how you solved (or didn't solve) them.Such diversions are all but unthinkable in this day of ever-shortening development times. But reflection is crucial. There's no better way to get into a creative rut than to hack mindlessly. You may produce lots of working code, but code mass is a poor measure of one's productivity.
The mark of a good design is precisely the opposite---it is small and elegant. It does much without bulk. It implements everything ``once and only once,'' as Kent Beck likes to say. It's also flexible; large bodies of code generally aren't.
Now, it's probably impractical to expect people to take a month off per year for contemplation. But what you can do is record your experiences incrementally. When you have a non-trivial problem to solve, try to write about it immediately. Jot down some notes describing the problem and why it's difficult. Then start working on it. Whenever you try a new approach, jot it down. If it fails, jot that down too, along with why it failed. Do the same if it succeeds.
Almost everyone can spend five percent of their time jotting down experience---it just takes discipline.
If you do this religiously, you'll be amazed at the written experience you accumulate. This is the raw material of patterns. There's still much to do, certainly, but you've got the all-important nuggets of wisdom from which to refine the gold.
Another important activity along these lines is to look at as many other systems as you can, systems designed by other people. The best way to learn from other systems is to actually build with them. If you don't have the time or money to do that, then at least read about them. Seek an understanding of the problems they address and how they address them. Study specifications and documentation. Read papers on research systems. Browse through OOPSLA and ECOOP proceedings.
Software---Practice & Experience is another good source of design and implementation information.
When you examine a system, glean everything you can from it. Try to identify patterns you already know. Evaluate how the solutions you find vary from those of published patterns. Be on the lookout for novel design solutions---they may represent new patterns. But keep in mind that relatively few design solutions are truly new. More often, people use variations on known solutions. A new and unique solution might not be widely applicable enough to cast in pattern form.
If you do find something that seems new, make sure it is applicable in other contexts before you try to write it up as a pattern. We had one inviolable rule as we developed Design Patterns: we had to find two existing examples of a problem and its solution before we would write a pattern for it. This was a particularly important rule for us to follow, because we were exploring unfamiliar territory, and we wanted to make sure what we wrote was grounded in reality.
We didn't want to end up with a set of solutions to problems no one had. Ultimately we discarded many patterns that seemed quite appealing and potentially useful but hadn't seen real use.
Once you have the raw materials, how do you go about writing them up in pattern form?Well, first of all, don't assume there is only one pattern form. No one form suits everybody. Some people prefer a more prosey style like Alexander's. Others favor the more fine-grained approach used in Design Patterns. Still others adopt totally different structures. The attribute shared by all these structures is just that---structure.
If there's one catchphrase that people largely agree on, it is the Alexandrian canon that a pattern is ``a solution to a problem in a context.'' Now I'll be so bold as to amend the canon: A pattern is a structured exposition of a solution to a problem in a context. Patterns have recognizable parts that guide their application and comparison.
These parts include a name, a statement of the problem, the context and justification of its solution, and the solution itself. This is essentially the structure of Alexander's patterns. Our patterns further decompose these fundamental elements into more focused treatments, such as the Applicability, Participants, and Consequences sections. The proceedings of the 1994 Pattern Languages of Programming (PLoP) conference includes surprisingly diverse variations on these themes.
So the first step in getting a pattern down on paper is to decide on its structure. The more information your average pattern has, the more important the structure becomes. Consistent structure lends uniformity to patterns, letting people compare them easily. Structure also helps people search for information. Less structure means more prose, which might be fine for casual reading but unacceptable for comparison and reference purposes.
Once you've settled on a structure, make sure you follow it consistently. You needn't be afraid to change the structure, but you'll have to change it in every pattern---and that gets increasingly expensive as your patterns mature.
In our patterns, the Motivation section comes up-front. That's because people seem to understand concepts better when they are presented in concrete terms first and then more abstract terms. The concrete example in the Motivation section gives the reader a frame of reference for the problem and its solution.
Another thing this section demonstrates is why other approaches to the problem fail, again in concrete terms. With the Motivation section as an introduction, the reader is better able to appreciate the general solution.
A corollary to concreteness is the need for lots of examples from the real-world. Examples should not be the sole estate of a Motivation section.
Use examples and counterexamples throughout the pattern to illustrate key points. Even the most abstract sections in our template (i.e., Applicability, Structure, Participants, and Collaborations) at times include examples. For instance, some of the Collaboration sections include interaction diagrams that show how objects communicate at run-time. Refer to such examples when discussing the abstract aspects of the pattern---be concrete even when you're being abstract.
Another corollary might be termed ``telling the whole truth.'' That means you must warn your reader about potential pitfalls of the pattern. It's all too easy to dwell on its positive aspects; it's not so easy to appreciate its faults and talk frankly about them. No pattern is free of drawback, be it extra cost, ill-behavior under certain circumstances, or whatever. Make sure your reader understands how the pattern can fall short.
There's a tendency to avoid when you're developing multiple patterns. As a you work on a pattern, it tends to grow both in detail and in scope. It's easy to forget about other patterns in the meantime. The distinctions between patterns blur as a result, making it hard for others to understand the patterns collectively. They start to overlap in scope and purpose. It all may seem perfectly clear to the author, but it probably won't be clear to newcomers. They won't know when to use one pattern and not another, because their differences aren't obvious.
Therefore make sure your patterns are orthogonal and that they work synergistically. Continually ask yourself, ``How is pattern X different from pattern Y?'' If two patterns solve the same or similar problems, you can probably merge them. Don't worry if two patterns use similar class hierarchies.
There are only so many ways to use the relatively few mechanisms inherent in object-oriented programming. Often the same arrangement of classes will yield substantially different object structures that address widely varying problems. Let the intents of the patterns be your guide to their differences and not the class structures that implement them.
A good way to test how orthogonal and synergistic your patterns are is to keep separate documents in which to compare and contrast your patterns. In Design Patterns we dedicated several sections to this purpose.
The simple act of trying to explain pattern relationships in written form gave us new perspectives on our patterns. More than once it forced us to rethink some of them.
My only regret is that we didn't concentrate on relationships earlier in the game. I recommend you start writing down such supplemental material as soon as possible. It may seem like a silly thing to do, especially when you don't have a lot of patterns to compare.
But as soon as you have just two patterns, the possibility of overlap emerges. Spending time comparing and contrasting them early on will help keep your patterns distinct and complementary.
The quality of your patterns is determined by how well you present them. You could discover the best pattern in the world, but it won't help anybody unless you convey it effectively.
By ``presenting'' I mean two things: typesetting and writing style. Good typesetting is a matter of skill in page layout, typography, and graphics, not to mention printer quality. Use the best software tools (word processor, drawing editor, etc.) you can. Make liberal use of drawings to illustrate key points.
You may not think you need any drawings, but chances are you do. At the least they break monotony, and at best they'll get your point across as no amount of explanation can.
Not all drawings have to be formal class and object diagrams; informal drawings and even sketches often convey just as much information and more. If you are ``artistically challenged,'' then have someone else do the drawings for you.
Good writing style is even more important than good typesetting. Write clearly and unpretentiously. Favor a down-to-earth style rather than a stuffy, academic one. People understand and appreciate a conversational tone, making them more receptive to the material. Clarity and ease of reading are important in most writing, but they're especially important for pattern writing.
The pattern concept is new enough and the subject matter complicated enough that some people have a hard time seeing the point of it all. Everything that can be done to make a pattern approachable should be done.
The best way to learn how to write conversationally is to try your hand at it. Make sure that everything you write is something you could hear yourself saying to friend. Avoid the passive voice. Break up long sentences and paragraphs. Use everyday words, and don't be afraid to use contractions.
Above all, make it sound natural.
Another thing everyone should do at some point in life is read a book or two on writing style. There are many to choose from. My three favorites are Strunk and White's The Elements of Style (whose organization, remarkably, is not unlike a series of patterns), Joseph M. Williams' Style: Ten Lessons in Clarity and Grace, and John R. Trimble's Writing with Style: Conversations on the Art of Writing.
Books like these are packed with tips and techniques for good, clear writing. They can help you improve your patterns independent of their technical content.
You won't get a pattern right the first time. You won't even get it right the first ten times. In fact, you'll probably never get it totally right.
Pattern writing is an on-going process. The fact that the field is new doesn't help matters. But even if it weren't...even if there were lots of examples of good patterns and books to help you write them, pattern development (like any other kind of development) would still be an iterative process.
Expect to write and re-write your patterns many times. Don't look for perfection in one pattern before you begin work on the next.
Remember, patterns don't exist in isolation; they affect one another. A significant change to one could very well impact others. As with any iteration, your efforts should converge at some point, but that's just the point where the patterns have stabilized enough to let other people read, understand, and comment on them.
Cervantes was right: ``The proof of the pudding is in the eating.'' The acid test of a pattern comes when it's put to use. Actually, no pattern can be trusted until it is used by someone other than its author. Patterns have the insidious property that they are usually perfectly understandable to people who are familiar with the problem involved and its solution. Such people have used the pattern before unconsciously.
Thus when they see the pattern, they can recognize it immediately, even if it isn't presented very well. The real challenge is to make the pattern understandable to people who have never run across the problem before. There's no way to do that without getting and incorporating feedback from just such people.
Encourage your colleagues to discuss design in terms of your patterns. (It's okay for the author to participate in such discussions.) Look for opportunities to use the patterns in your day-to-day work. Try to disseminate your patterns as widely as you can. You might even submit them to conferences like JavaOne or to publications like Journal of Object-Oriented Programming. Such exposure will maximize the use of your patterns.
Once the feedback starts rolling in, be prepared to hear the worst. I can't remember how many times I was shocked to learn that something that seemed thoroughly comprehensible to me thoroughly confounded someone else. The negative feedback can be disheartening, especially at the beginning when you're most vulnerable and also most likely to receive it from people. While some criticism might not be valid or might result from a simple misunderstanding, most of it will probably be legitimate.
Give your reviewers the benefit of the doubt. Bend over backwards to make them happy. You may end up making many, many more people happy in the long run.
Adopting these habits won't guarantee your success as a pattern writer, of course. Nor is this list exhaustive. But at least it should help you focus your efforts profitably. The better your patterns are, the more impact they'll have.
That's not to say everyone should be a pattern writer, however. Pattern writing involves a nontrivial investment, and not everyone can justify it. Everyone should try pattern writing at least once, since you can't know if you're good at it otherwise.
As time passes, though, I expect the number of pattern writers to be dwarfed by the number of pattern users---much as programming language users (thankfully) dwarf the ranks of language creators.
Gamma, E., R. Helm, R. Johnson, J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading, MA, 1995.
Yet pattern development seems a good deal harder than what I learned in calculus class.
Integrals don't interfere with one another, which lets you solve them independently (although knowing how to solve one often helps you solve others).
A pattern, in contrast, doesn't work in a vacuum. It provides the solution to just one problem; so it must cooperate with other patterns. Therefore a pattern writer must contemplate not one pattern but several, even some as yet unwritten. And that's but one of many challenges in the pattern development process.
If you're an aspiring pattern writer, you'll need all the help you can get.
We certainly learned a lot about pattern development in writing Design Patterns. So what I've tried to do this time is boil down our experience into seven habits we adopted, largely unconsciously, over the four-some-odd years it took to write the book.
Taking these habits to heart should help you hone your pattern-writing abilities far faster than we did.
HABIT 1: TAKING TIME TO REFLECT
The single most important activity in pattern writing is reflection. Bruce Anderson, an early influence on our work, has offered up this mantra for years. Take time off periodically to reflect on what you've done. Think about the systems you've built, the problems you've had, and how you solved (or didn't solve) them.Such diversions are all but unthinkable in this day of ever-shortening development times. But reflection is crucial. There's no better way to get into a creative rut than to hack mindlessly. You may produce lots of working code, but code mass is a poor measure of one's productivity.
The mark of a good design is precisely the opposite---it is small and elegant. It does much without bulk. It implements everything ``once and only once,'' as Kent Beck likes to say. It's also flexible; large bodies of code generally aren't.
Now, it's probably impractical to expect people to take a month off per year for contemplation. But what you can do is record your experiences incrementally. When you have a non-trivial problem to solve, try to write about it immediately. Jot down some notes describing the problem and why it's difficult. Then start working on it. Whenever you try a new approach, jot it down. If it fails, jot that down too, along with why it failed. Do the same if it succeeds.
Almost everyone can spend five percent of their time jotting down experience---it just takes discipline.
If you do this religiously, you'll be amazed at the written experience you accumulate. This is the raw material of patterns. There's still much to do, certainly, but you've got the all-important nuggets of wisdom from which to refine the gold.
Another important activity along these lines is to look at as many other systems as you can, systems designed by other people. The best way to learn from other systems is to actually build with them. If you don't have the time or money to do that, then at least read about them. Seek an understanding of the problems they address and how they address them. Study specifications and documentation. Read papers on research systems. Browse through OOPSLA and ECOOP proceedings.
Software---Practice & Experience is another good source of design and implementation information.
When you examine a system, glean everything you can from it. Try to identify patterns you already know. Evaluate how the solutions you find vary from those of published patterns. Be on the lookout for novel design solutions---they may represent new patterns. But keep in mind that relatively few design solutions are truly new. More often, people use variations on known solutions. A new and unique solution might not be widely applicable enough to cast in pattern form.
If you do find something that seems new, make sure it is applicable in other contexts before you try to write it up as a pattern. We had one inviolable rule as we developed Design Patterns: we had to find two existing examples of a problem and its solution before we would write a pattern for it. This was a particularly important rule for us to follow, because we were exploring unfamiliar territory, and we wanted to make sure what we wrote was grounded in reality.
We didn't want to end up with a set of solutions to problems no one had. Ultimately we discarded many patterns that seemed quite appealing and potentially useful but hadn't seen real use.
HABIT 2: ADHERING TO A STRUCTURE
Once you have the raw materials, how do you go about writing them up in pattern form?Well, first of all, don't assume there is only one pattern form. No one form suits everybody. Some people prefer a more prosey style like Alexander's. Others favor the more fine-grained approach used in Design Patterns. Still others adopt totally different structures. The attribute shared by all these structures is just that---structure.
If there's one catchphrase that people largely agree on, it is the Alexandrian canon that a pattern is ``a solution to a problem in a context.'' Now I'll be so bold as to amend the canon: A pattern is a structured exposition of a solution to a problem in a context. Patterns have recognizable parts that guide their application and comparison.
These parts include a name, a statement of the problem, the context and justification of its solution, and the solution itself. This is essentially the structure of Alexander's patterns. Our patterns further decompose these fundamental elements into more focused treatments, such as the Applicability, Participants, and Consequences sections. The proceedings of the 1994 Pattern Languages of Programming (PLoP) conference includes surprisingly diverse variations on these themes.
So the first step in getting a pattern down on paper is to decide on its structure. The more information your average pattern has, the more important the structure becomes. Consistent structure lends uniformity to patterns, letting people compare them easily. Structure also helps people search for information. Less structure means more prose, which might be fine for casual reading but unacceptable for comparison and reference purposes.
Once you've settled on a structure, make sure you follow it consistently. You needn't be afraid to change the structure, but you'll have to change it in every pattern---and that gets increasingly expensive as your patterns mature.
HABIT 3: BEING CONCRETE EARLY
In our patterns, the Motivation section comes up-front. That's because people seem to understand concepts better when they are presented in concrete terms first and then more abstract terms. The concrete example in the Motivation section gives the reader a frame of reference for the problem and its solution.
Another thing this section demonstrates is why other approaches to the problem fail, again in concrete terms. With the Motivation section as an introduction, the reader is better able to appreciate the general solution.
A corollary to concreteness is the need for lots of examples from the real-world. Examples should not be the sole estate of a Motivation section.
Use examples and counterexamples throughout the pattern to illustrate key points. Even the most abstract sections in our template (i.e., Applicability, Structure, Participants, and Collaborations) at times include examples. For instance, some of the Collaboration sections include interaction diagrams that show how objects communicate at run-time. Refer to such examples when discussing the abstract aspects of the pattern---be concrete even when you're being abstract.
Another corollary might be termed ``telling the whole truth.'' That means you must warn your reader about potential pitfalls of the pattern. It's all too easy to dwell on its positive aspects; it's not so easy to appreciate its faults and talk frankly about them. No pattern is free of drawback, be it extra cost, ill-behavior under certain circumstances, or whatever. Make sure your reader understands how the pattern can fall short.
HABIT 4: KEEPING PATTERNS DISTINCT AND COMPLEMENTARY
There's a tendency to avoid when you're developing multiple patterns. As a you work on a pattern, it tends to grow both in detail and in scope. It's easy to forget about other patterns in the meantime. The distinctions between patterns blur as a result, making it hard for others to understand the patterns collectively. They start to overlap in scope and purpose. It all may seem perfectly clear to the author, but it probably won't be clear to newcomers. They won't know when to use one pattern and not another, because their differences aren't obvious.
Therefore make sure your patterns are orthogonal and that they work synergistically. Continually ask yourself, ``How is pattern X different from pattern Y?'' If two patterns solve the same or similar problems, you can probably merge them. Don't worry if two patterns use similar class hierarchies.
There are only so many ways to use the relatively few mechanisms inherent in object-oriented programming. Often the same arrangement of classes will yield substantially different object structures that address widely varying problems. Let the intents of the patterns be your guide to their differences and not the class structures that implement them.
A good way to test how orthogonal and synergistic your patterns are is to keep separate documents in which to compare and contrast your patterns. In Design Patterns we dedicated several sections to this purpose.
The simple act of trying to explain pattern relationships in written form gave us new perspectives on our patterns. More than once it forced us to rethink some of them.
My only regret is that we didn't concentrate on relationships earlier in the game. I recommend you start writing down such supplemental material as soon as possible. It may seem like a silly thing to do, especially when you don't have a lot of patterns to compare.
But as soon as you have just two patterns, the possibility of overlap emerges. Spending time comparing and contrasting them early on will help keep your patterns distinct and complementary.
HABIT 5: PRESENTING EFFECTIVELY
The quality of your patterns is determined by how well you present them. You could discover the best pattern in the world, but it won't help anybody unless you convey it effectively.
By ``presenting'' I mean two things: typesetting and writing style. Good typesetting is a matter of skill in page layout, typography, and graphics, not to mention printer quality. Use the best software tools (word processor, drawing editor, etc.) you can. Make liberal use of drawings to illustrate key points.
You may not think you need any drawings, but chances are you do. At the least they break monotony, and at best they'll get your point across as no amount of explanation can.
Not all drawings have to be formal class and object diagrams; informal drawings and even sketches often convey just as much information and more. If you are ``artistically challenged,'' then have someone else do the drawings for you.
Good writing style is even more important than good typesetting. Write clearly and unpretentiously. Favor a down-to-earth style rather than a stuffy, academic one. People understand and appreciate a conversational tone, making them more receptive to the material. Clarity and ease of reading are important in most writing, but they're especially important for pattern writing.
The pattern concept is new enough and the subject matter complicated enough that some people have a hard time seeing the point of it all. Everything that can be done to make a pattern approachable should be done.
The best way to learn how to write conversationally is to try your hand at it. Make sure that everything you write is something you could hear yourself saying to friend. Avoid the passive voice. Break up long sentences and paragraphs. Use everyday words, and don't be afraid to use contractions.
Above all, make it sound natural.
Another thing everyone should do at some point in life is read a book or two on writing style. There are many to choose from. My three favorites are Strunk and White's The Elements of Style (whose organization, remarkably, is not unlike a series of patterns), Joseph M. Williams' Style: Ten Lessons in Clarity and Grace, and John R. Trimble's Writing with Style: Conversations on the Art of Writing.
Books like these are packed with tips and techniques for good, clear writing. They can help you improve your patterns independent of their technical content.
HABIT 6: ITERATING TIRELESSLY
You won't get a pattern right the first time. You won't even get it right the first ten times. In fact, you'll probably never get it totally right.
Pattern writing is an on-going process. The fact that the field is new doesn't help matters. But even if it weren't...even if there were lots of examples of good patterns and books to help you write them, pattern development (like any other kind of development) would still be an iterative process.
Expect to write and re-write your patterns many times. Don't look for perfection in one pattern before you begin work on the next.
Remember, patterns don't exist in isolation; they affect one another. A significant change to one could very well impact others. As with any iteration, your efforts should converge at some point, but that's just the point where the patterns have stabilized enough to let other people read, understand, and comment on them.
HABIT 7: COLLECTING AND INCORPORATING FEEDBACK
Cervantes was right: ``The proof of the pudding is in the eating.'' The acid test of a pattern comes when it's put to use. Actually, no pattern can be trusted until it is used by someone other than its author. Patterns have the insidious property that they are usually perfectly understandable to people who are familiar with the problem involved and its solution. Such people have used the pattern before unconsciously.
Thus when they see the pattern, they can recognize it immediately, even if it isn't presented very well. The real challenge is to make the pattern understandable to people who have never run across the problem before. There's no way to do that without getting and incorporating feedback from just such people.
Encourage your colleagues to discuss design in terms of your patterns. (It's okay for the author to participate in such discussions.) Look for opportunities to use the patterns in your day-to-day work. Try to disseminate your patterns as widely as you can. You might even submit them to conferences like JavaOne or to publications like Journal of Object-Oriented Programming. Such exposure will maximize the use of your patterns.
Once the feedback starts rolling in, be prepared to hear the worst. I can't remember how many times I was shocked to learn that something that seemed thoroughly comprehensible to me thoroughly confounded someone else. The negative feedback can be disheartening, especially at the beginning when you're most vulnerable and also most likely to receive it from people. While some criticism might not be valid or might result from a simple misunderstanding, most of it will probably be legitimate.
Give your reviewers the benefit of the doubt. Bend over backwards to make them happy. You may end up making many, many more people happy in the long run.
NO SILVER BULLET
Adopting these habits won't guarantee your success as a pattern writer, of course. Nor is this list exhaustive. But at least it should help you focus your efforts profitably. The better your patterns are, the more impact they'll have.
That's not to say everyone should be a pattern writer, however. Pattern writing involves a nontrivial investment, and not everyone can justify it. Everyone should try pattern writing at least once, since you can't know if you're good at it otherwise.
As time passes, though, I expect the number of pattern writers to be dwarfed by the number of pattern users---much as programming language users (thankfully) dwarf the ranks of language creators.
References
Coplien, J. and D. Schmidt, eds. Pattern Languages of Program Design, Addison-Wesley, Reading, MA, 1995.Gamma, E., R. Helm, R. Johnson, J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading, MA, 1995.
No comments :
Post a Comment