Or, In Defense Of Software Patterns.
I was listening to Ruby Rogues podcast episode #56 when the discussion turned to software patterns, and my teeth started grinding.
It wasn’t so much about what was said (though there were enough of those moments, to be sure) as about what was implied or left unsaid. With one exception (to come later) I’m going to leave names out of this, simply because I want the discussion to center on the ideas, not the personalities. Listen to the podcast, and you’ll be clear enough about who said what, if the who of it means that much to you. I’ll just say the guest and the rogues are all not short of accomplishments and as a group contain very good developers.
The implication that came out of it, and that was only halfheartedly challenged, was that software patterns weren’t useful things to teach beginning developers. The statement that made the show notes was “You need to feel the pain and understand the pattern before you begin to understand when and why to use it and when to deviate.” While the statement itself is defensible, it’s really irrelevant to the value of software patterns for either experienced or nascent developers. My own first reaction was, “So?, What’s your point?”
I have two problems with the discussion that ensued (for complete context, listen to the podcast). The first is with the implicit assumption in that statement, left completely unchallenged in the podcast, that you can’t understand something until you experience it first hand. This is patently absurd. I don’t have to fall off a cliff, or stick my finger in a light socket, before I can begin to understand it would be bad for me to do it. There is plenty of secondhand experience I can draw upon to inform my actions. (I used this technique with my kids frequently during their childhood, “I’ve already made that mistake, and this is what happened. It wasn’t pleasant. You go find your own mistakes to make.”)
I could possibly let that statement pass unchallenged if we replaced the concept of “begin to understand” with something like “intimately understand” but even then, I wouldn’t positively support it. We’ve proven as a species we can learn from other people’s mistakes often enough that it’s not a newsworthy event when we do.
Software patterns (including the Law of Demeter, which one voice seemed to hate so much it bordered on obsession) are shorthand for techniques commonly found useful in the field. As such, they are generalizations, meaning while they don’t have universal utility (few generalizations do) they are more often useful than not. Yet (I’m not clear why, except that possibly the speaker had seen bad code excused by the coder claiming to be following a pattern) the concept of patterns as something known by beginners was consistently trashed.
One of the rogues (James Edward Gray II, who gets named because the mention is positive, not negative) brought in the subject of chess, which is the most apt analogy to the concept. His point was arbitrarily rejected, but (without even asking for his permission) I’m going to expand upon it here, because he was ultimately correct.
Beginning chess players are taught various “rules” or principles. They are “chess patterns,” so to speak. One widely known one is “Rooks belong behind passed pawns.” This pattern was preached by (among others) Siegbert Tarrasch in his instruction book The Game Of Chess. An amateur, after watching a game which Tarrasch won by placing his rook in front of, not behind, a passed pawn, accused Tarrasch of teaching incorrect principles. Tarrasch replied, “Very well, then. Rooks belong behind passed pawns. Except when they don’t.”
In the chess world, John Watson and Jacob Aagaard carried on a multi-book discussion of the idea of chess principles and their exceptions. It’s not surprising that Aagaard, a grandmaster whose non-chess specialty is cognitive semiotics, took the “pro” position on patterns, against the American IM. As human beings, we learn by recognizing patterns in the world, then by refining that pattern recognition as we process the exceptions. The refinements come as we add to our knowledge base, but before we can recognize the exceptions to the patterns, we first have to know the patterns.
Every rule we have for significant human action has exceptions. So what? That somehow invalidates the rule? Not every software pattern is applicable in every circumstance. The Titanic sank. What should we do, ban ocean liners?
The 1st World Correspondence chess champion, CJS Purdy wrote: “There are chess players who do not know the principles, and are weak. There are those who know the principles, and are less weak. And there are those who know how weak the principles are, and are strong.”
In chess, the top players got there by following the principles, following the chess patterns, unless there was a reason not to. There in the position was the information necessary to judge whether the principle does or does not apply. Their “default state” is that it applies. That fact is itself the only excuse for the principle’s existence — were it not appropriate more often than not no one would care about it.
That’s the way it is with software patterns. I can’t let the idea that people should not follow patterns more often than they follow them stand unchallenged, as happened in the podcast, because I think that is a dangerously stupid idea.
In our haste to kick over the ceremonial idols of our past (and, as a veteran of SDM/70, I can confirm that plenty of them needed kicking over) we have become entirely too eager to throw away everything, rushing straight through iconoclasm into antinomianism. Baby. Bathwater.
We’ve but to look around us to see the effects of that. Uncle Bob talks about how much knowledge we’ve ignored in his presentation from Ruby Midwest, Architecture, The Lost Years. More directly to the point, at MagRails Aaron Patterson talks about how he speeded up Rails routing in Pattern Matching. The biggest point to take away from that presentation is that he did it not by ignoring the patterns and knowledge of the past, but by using them. (I really don’t think that can be emphasized enough. A better, faster, way was already known, years ago. I don’t want to belittle his achievement, the algorithm still had to be investigated and implemented. But that it took this many years for someone to apply this algorithm is, I think, indicative of how far we’ve gone in ignoring knowledge gained in the past.)
The idea that you have to make the mistakes yourself in order to advance (“You need to feel the pain and understand the pattern before you begin to understand when and why to use it and when to deviate”) is poisonous to the idea of any sort of science. We advance the state of the science (or craft, or trade, or art, call it what you like) of software development not by forcing everyone to recapitulate mistakes of the past, but by focusing our efforts on everyone learning from them.
Does that mean that new (and even experienced) developers will not abuse a given software pattern? Of course not. They absolutely will. But when they do, they (and we, by extension) will learn even more about the advisability and applicability of that pattern. And we will all advance (not just the person who “experienced the pain;” all of us). Tomorrow’s developers will see more details of software development than we do because they’re standing on our shoulders. If we force them to eat the same dirt we did, it may make us feel better about our own past, but it really won’t help them progress beyond us.
The implementation details of this aren’t easy; nothing worthwhile ever is. The final stop is the code, obviously, but before the code comes the idea, and that’s the territory for software patterns, just as the place for chess principles is in the realm of thought, not move. Sometimes that rook belongs somewhere else; sometimes that pattern doesn’t apply. But in neither case can you consider whether it applies until you know the principle, the pattern.
It means bad code will be written. But that’s a universal constant, not a consequence of software patterns. And bad code written in support of even a good pattern should not stand. But was the bad code the result of a good developer following a bad pattern (perhaps an anti-pattern) or is it the result of misapplying a pattern or badly implementing an appropriate pattern? Only in the first case do we question the value of knowing the pattern; in the second case we question ourselves, add to our own knowledge store (and, hopefully, pass the knowledge on to others).
In software development as in chess, a knowledge of the basic patterns of the endeavor is invaluable to our advancement in the field. It is the way in which we “stand on the shoulders of giants,” to borrow Newton’s words. It’s the way we become more productive than those who went before.
Software development patterns allow us to make new mistakes, rather than recapitulate past ones. And while repeating old mistakes will merely lead to our own improvement, making new ones will improve everyone.