I’ve occasionally come across developers who believe that the use of design patterns over-complicates systems and results in code that is harder to understand.
The same developers often don’t know or understand many design patterns; if you were to ask them to name a few, you would most invariably hear MVC and singleton… and then silence. Prodding for other patterns might result in looks of confusion and an explanation on how they have come to the conclusion that patterns over-complicate solutions.
What is a design pattern?
It’s often been said that a design pattern is a reusable solution to a common problem. While this may be true, I think that believing that these problems are too common can be dangerous. If the problem appears to be truly common, we can be tempted to make a pattern our “golden hammer” — our solution to everything. After all, we genuinely do want to avoid re-inventing the wheel, which is a good thing… but we have to be careful that we don’t try too hard to force something that is not a wheel to look like a wheel, complicating our original problem in the process.
Attempting to wrap our problem inside of a different, known problem that has a “prescription” will certainly increase complexity. This could continue to escalate as the original problem is better understood or new features are required and changes to the system are needed to support this. Will we resist proper refactoring as we try to jam our problem into our “solution”? We need to take care in ensuring that we understand properly the problem that we are trying to solve. If it looks like a duck, walks like a duck, but quacks like a pig, maybe the old duck pattern doesn’t quite fit.
In my opinion, an object-oriented design pattern should be thought of as an example of solving a specific problemusing principles that demonstrate effective object-oriented design. It should highlight methods of solving specific problems in ways that encourage thinking about good object-oriented principles. They should hold to ideas like SOLID, a set of principles that encourage us to develop habits toward keeping our systems more maintainable and extendable and more testable.
If we can begin to understand why a pattern is beneficial to a specific problem, we should be able to remain flexible and adapt to unique situations to solve problems in a clean and maintainable way. We should be able to apply a similar thought process – how can I solve a problem while ensuring that my code is maintainable, extendible, and remains testable? I think we should focus more on the why, not so much on the what. Knowing that MVC stands for Model-View-Controller is much less important than understanding the problem that it tries to address.
So, should I create my own patterns?
As we continually refactor and apply object-oriented principles to our architecture, along with proper, meaningful naming, the structure of our applications should evolve into local patterns. These structures can be used throughout a system to keep it consistent where similar behavior is required. Congratulations, you now have your own pattern – a reusable solution to a problem that is commonfor you. It might not be the best solution, and you might think of a better way tomorrow, but you’re now thinking about structure and problem solving at a higher level, creating adaptive solutions and retaining good programming principles as strange beastly problems come your way.
On the other hand, if we are so lucky to be building a system that addresses some problems that map exactly to a known design-pattern, using these can enable us to communicate through a shared vocabulary. If we both share understanding of certain patterns, by telling you that my system uses MVVM or uses a factory pattern to create certain types of objects, you can infer a lot about the system and where you could begin to make changes if you needed to maintain or extend the system. This shared vocabulary allows us to communicate large ideas in fewer words and helps us to understand systems more quickly without examining them in great detail. When we build systems, we should also consider that we are communicating an idea – how well we can communicate structure has an impact on maintainability of a system.
While it is true that we need to avoid trying to jam our solutions into existing patterns when they don’t fit, this isn’t a good excuse for not learning about them. I believe that we should be using them as a tool to better understand methods of addressing problems that stay true to object-oriented principles, so that we can effectively structure our applications and apply our own patterns. Learning about our history helps us to avoid making similar mistakes in the future.
The danger in focusing too narrowly on existing, common patterns is that we can limit ourselves from thinking about and applying their principles in new ways. There is no list of patterns that solve all problems for all time, just a few examples from some of those that went before us and wanted to leave us some ideas that worked for them.
So, I challenge you to try to learn at least one new pattern and absorb the reasoning behind it. You never know when learning something new will come in handy…