Internalise the criteria

Examples of the solutions in design patterns are found in source code for some languages but in features for others. Strategy, Iterator, Prototype, Factory Method, Whole-Part, and Chain of Responsibility all turn up frequently outside of object-oriented code, even when people don’t know about them. This indicates that patterns are hiding near them as the solutions are self-forming. Their presence as primitives in a language doesn’t make them less of a pattern but more. They were valuable and obvious enough to be internalised into a language.

First criterion – They are real

It’s only a pattern if you can give an example. This first criterion should be obvious, but some examples from the published works disagree. So, I shall start with this and claim that examples prove a pattern can be enacted. They provide a starting point for a mental image. Examples allow a pattern description to explain extension or adjustment to match different contexts.

Christopher Alexander claimed, ‘If you can’t draw a diagram of it, it isn’t a pattern’[TTWoB79]. I believe code design patterns need source code, and management patterns need anecdotes, because all patterns need a few structured examples. Buildings need diagrams because they present forms. Code patterns need source code because they illustrate relationships of code forms. Management patterns need anecdotes because they represent timelines of people’s lives. The examples should not only be from where the pattern was applied correctly but also from where they were misapplied or absent. When we learn to use patterns, we learn how to repair things.

Look for evidence that patterns are true and real, but also look for evidence that they are false. Examples such as Functionality Ala Carte and Command have a suspicious lack of insight. Recurring, naturally emerging problems and bugs are curiously missing from their documentation. This is evidence that the pattern was not worked with deeply, or that it was never truly implemented, or important details were omitted for unknown reasons. In this case, reject the pattern as incomplete.

Second criterion – A process and a thing

So, the second criterion for a pattern is a clear description of a state of stress or disrepair. A diagram or code example will help, or a story about the pain can set the scene. The reason why the pattern is applied must be apparent, not just what the solution looks like.

Many so-called design patterns are just wrapped-up solutions. They either don’t help at the root or are not necessary. For example, Memento isn’t a pattern, as it doesn’t have value in itself and doesn’t balance forces. In every case I encountered, the Memento pattern was the data store element of the undo pattern, but it’s not a pattern. It does not form without the undo pattern1 and does not form without command, so it is merely an element of those patterns. There are other instances of something like the Memento pattern if you count serialising objects and de-serialising them back into life, but that’s not what was written into the original pattern.

Another problem with Memento is that it’s incomplete. For example, when you have a large object, why does the pattern suggest requesting a snapshot and then committing the action? This must surely lead to the situation where the Memento must represent all the information necessary to revert any future operation. The implementation section presents this limitation as something which is the responsibility of the command, but why? Either the command knows the target much too intimately, or it will store too much information, or possibly the target is revealing too many different contextual memento creation methods.

When a method on the target can return a Memento, this constraint evaporates. When you design the affected object so it can shallow copy, the constraint vanishes for different reasons. The pattern does not offer either of these solutions and, thus, is unfinished.

A pattern interacts with other patterns. The way Composite interacts with Visitor or Interpreter is weakly defined. The pattern of Pipes-and-filters works well with pure functional transforms and the principle of avoiding global state for concurrency. To interact is not to rely on but to contrast and cooperate.

Third criterion – They are wholesome

Beware of unfinished patterns. Refine them and seek out all the edges. If you don’t, you risk stating there is no solution where one exists. The third criterion is that a pattern stands alone but is related to other patterns.

Reading a file line by line is a pattern repeatedly observed since UNIX’s first years. Formatting strings in printing functions, finite state machines, handing out agents or handles to users of APIs rather than raw memory access, and cursors for query languages are all patterns that we see in programming but that are missing from the GoF book[GoF94]. The criterion for a pattern there seems to be the repeated finding of an object-oriented alternative to an existing solution outside the object-oriented space.

Fourth criterion – They address problems of design

There are non-object-oriented ways to express most of the GoF book patterns. GoF patterns that can be reinterpreted in this way could be considered idioms of an object-oriented design approach to the problem they address. The fourth criterion is that patterns are problem-centric. A pattern or pattern language is not paradigm-specific. It must be centred around solving a problem, not just offering an alternative solution using different tools.

Fifth criterion – They are responsive

The fifth criterion is related to emergence. When people latched onto the idea of patterns, they failed to attribute enough importance to the concept of forces. They understood the context part well, so they made that the way to identify where a pattern fits. If the context is correct but the forces don’t match, it’s not a pattern. It can still be a solution or simply something to be expected. Patterns generate solutions. Forces often generate patterns. If a recurring pattern cannot be found at the centre of a given set of forces, it’s more likely someone’s attempt at a pattern.

For example, I am a primitive human living in the jungle. I know how to make and use string and create tools from raw materials. This is my context. I have access to wood, flint, vines, and other resources. These are also part of my context. There are animals all around the forest. Some fly, some climb, and some move around at ground level. These are all part of the context. This context does not elicit any patterns, as there are no forces. It’s a stage upon which forces will play, but it does not suggest anything independently without first identifying the forces at play.

The forces I add to the system are: I am a hungry human who can scrounge for nuts and berries, but they are not plentiful at ground level. I am big and clever, but I cannot catch the small, weak animals at ground level, as they are too fast, and I need help to reach the ones that climb or fly.

We can see how a few patterns emerged once I added forces to this context. We will make tools to create ways to reach the fruit or animals beyond our reach, set traps for the skittish animals eluding our grasp, or even invent the bow and arrow. These are patterns because they are recurring solutions that resolve forces in a context. They have objective criteria of both context and forces.

Forces are the value of success and the cost of failure for each contextual relationship. The animals want to survive, so they will flee humans as they approach, but we need to get close to catch them so extend ourselves by trap or ranged weapon to resolve the conflicting forces. To get at the fruit higher up, because humans cannot reach that high and free climbing comes with greater and greater risk the higher we climb, we build ladders or climbing gear to reach great heights more safely, resolving those conflicting forces.

It’s the unresolved forces that drive the appearance of patterns. This is the last criterion.

  1. They are real: there are real examples.
  2. They are a process and a thing: the state of distress is well described. They repair and make things better.
  3. They are wholesome: they are both fully contained and related to other patterns. They support, not inhibit, the resolution of neighbouring problems.
  4. They address problems of design: a pattern or pattern language is not paradigm-specific and not an implementation.
  5. They are responsive: patterns must be emergent from the unresolved forces and resolve them.
1

The memento iterator pattern in the GoF book is quite a stretch and is almost an anti-pattern as it splits lifetime responsibility between two separate objects, hence my discounting it.