There has been a lot of talk in the recent years about the harm that design patterns bring to new and seasoned developers. The message is clear: you should not use them as a first solution to a problem. This article examines some of the reasons behind that, and even why you should consider not using them at all.
For some odd reason, a handful of developers equate using design patterns to designing good code. The two have nothing to do with each other. Do not rot your mind thinking a book full of puzzle solutions will make you a good puzzle solver. It won’t, it will trick you into thinking you know more than you actually do. But before I get to the bottom of things, it would be a good idea to get this out of the way:
Knowing design patterns is very important
Despite the criticism, it is still essential you have some idea of design patterns, or at least a vague approximation of how they would appear in code. There is often an underlying reason for using a specific approach to a problem, such as using Event Listeners, MVC or the Multi-Tier Architecture. Knowing design patterns can help you:
- Traverse code faster, allowing you to get the “big picture” sooner than you would otherwise
- Refactor existing modules such that they are decoupled and are less bound to other modules in the application
- Generalize a problem you already know exists, have encountered before, and can solve it with a clean solution from the first attempt
Hopefully, you’ve caught on to the fact that the three points deal with post-written code — or at least someone with prior knowledge and strong hindsight of the problem at hand.
So why are design patterns so bad?
1. They make programmers think in terms of patterns, not in terms of the problem domain
One of the worst things you can do when designing an application is think in terms of code, and omit the fact that you are trying to solve a specific, very often business-oriented problem. I often see new or simply inexperienced game programmers trying to brute patterns into their code without a single clue as to why they need to think in terms of patterns first, or whether they will benefit from that approach at all. Often times, the programmer has some grand design in mind (getting ahead of themselves, real fast) that the pattern will solve (never finishes enough of the project to get to it), yet does not realize how little of the problem they understand, and even less idea of why that approach is suitable at all. (Aside: If you ever meet one of these ambitious programmers, ask them why they chose that approach. The answers get repetitive.)
Instead, the humble and realistic approach is to ask yourself what is the application trying to solve? This will avoid the pattern situation altogether, and you might get lucky and see the project at a stage where you can finally refactor the application to use some patterns, making the next round of modules easier to integrate with the existing modules.
2. They try to replace experience, hindsight, and purpose of the application with design generalizations
In a lot of situations, and in lots of different professions, it’s hard to use good judgement without knowing the problem, and sometimes the only way to know the problem is to solve it once. Solve it twice or three times, and you’ll most often find a pattern emerge. I use the word knowing here in a peculiar way, because while you can be presented with a problem, it’s difficult to find a clean solution without knowing what makes the problem tick.
As such, the best place to use design patterns is after a few attempts at a problem, after you have better assessed the true nature of what it is you’re trying to solve. As a humble example, I often tell myself: I now know the problem, I know when it will come up, and I know enough about the solution to generalize the module so that it will take the least amount of work to adapt new changes. In my experience, (time and other constraints aside) I have found that this approach works fantastically, because it leaves you open with your mind’s possibilities, instead of tying your thoughts down to a book or two full of UML diagrams.
This is what I refer to as the natural way of solving a problem, and is discussed as the next point.
3. Design patterns should emerge from code written, in a smooth transition
Since this is one of the key points of this article, I will repeat it again: You cannot apply a design pattern to a non-existing problem. It is far easier, and you gain a lot more out of it, if you apply a pattern to code that already exists, is hopefully written by you (and you still have the big picture in your head), and is in need of refactoring. Trying to adapt code to a solution that does not need a solution is backwards and a waste of time. Focus your thoughts on what needs to be finished instead of looking for problems to solve without any benefits. You won’t gain anything out of it.
After you’ve written a lot of code, and you’ve told yourself it’s time to fix it up and make it work nicely with other modules, it is a wise idea to see how you can refactor the code. This is where the real patterns come into play. These are not the ones talked about in books (but may and do very often end up that way), but the ones that are spoken in the way you’ve written your code, designed your application and thought out the architecture of your application. This is where three main things come into play which will help you: Your brain, algorithms and data structures. Using just these three, you can come up with all sorts of clean solutions to a problem. You will walk away knowing far more this way than you would blindly reading a book whose intent is to somehow turn you into a master architect. It won’t, you’re fooling yourself. No one ever became a good programmer relying on books alone.
Conclusion
For all their seeming benefits, patterns are very often misused. In recent years, a number of programmers have stepped out and proclaimed that patterns are misused, harmful to programmers and projects, and should be avoided unless derived to from experience. I think that last part can be said to apply to a lot of things. Nevertheless, knowing patterns vital and beneficial to you as a programmer, because you will have some gain out of it if you need to adapt to existing code.
Other articles I found worth reading:
Chris Ericson’s “Design Patterns Are From Hell” (Two articles)
Jeff Atwood’s “Rethinking Design Patterns”
Alex Davies’ “Why Following ‘Design Patterns’ Is a Bad Idea”
There is also an IEEE publication entitled “Design Patterns Are Bad for Software Design”, stating “Design patterns make it too easy to introduce unnecessary complexity into system design and are much too often applied without discipline or experience.” I can’t say I disagree.
Addendum
Here is a small excerpt of the aforementioned IEEE article, almost summarizing my article:
Today, design patterns let average developers design working OO systems that would have otherwise been beyond their capabilities. This might sound like a great thing, but the relative lack of expertise or brilliance can easily result in bigger software design disasters than would occur without them. For example, most GoF patterns are about introducing flexibility by indirection and inheritance. This is great when you use it to reduce code size and simplify logic by applying polymorphism, but it can also be a tool for overengineering and introducing excessive complexity. A designer who can’t decide on a system property can use design patterns to postpone decisions, speculate about features never needed, and lay a heavy burden on system implementers and maintainers.
I recommend anyone with IEEE access to read this article, as it contains far more insight into the problem than the excerpt, and also provides some counter points from other developers.
