Is It Time to Get Over Design Patterns?

There is nothing more dangerous than a clever pattern in the wrong hands

No alt text provided for this image

One of the core principles of good programming is don’t solve the same problem twice. If someone has already invented the perfect bubblesort, you have no business rolling your own. If you’ve got a reasonable regular expression to validate email addresses, you don’t need to do it yourself. And so on.

This logic is easy to understand. Every time you reinvent a piece of functionality, there’s a risk that things will go sideways. You could introduce new bugs or stumble into unexpected shortcomings. At best, your code will suck up extra testing time. At worst, you’ll create problems that will hide in the seams and joints of your application, like bedbugs in the corners of a old bed frame.

So it’s easy to understand the allure of design patterns. If we’re going to solve the same problems over and over again, wouldn’t we be wise to use the canonical solutions, ones created by far smarter programmers and tested over the eons? Or, to put it another way, don’t we have the responsibility to use battle-tested patterns to save time and ensure the best possible final product?

This is how design patterns reel you in.

A brief history of design patterns

The idea of patterns — conceptual models that you can define and reuse — has deep roots, stretching back to real architecture (of buildings) and the work of Christopher Alexander. But design patterns as most programmers know them sprang into existence in 1994, when four coding geniuses wrote a book called Design Patterns: Elements of Reusable Object-Oriented Software.

No alt text provided for this image

Design Patterns set out 23 foundational patterns grouped into three categories: Creational, Structural, and Behavioral. You can review all of them here. Amazingly enough, when people talk about design patterns today — some 25 years later — they’re usually referring to one of the ancient patterns first codified in this book.

This sort of success is no accident. And there’s no denying that the original design patterns were written by sharper programmers than you or me. But design patterns aren’t a neutral part of software design, and using them has a price that’s often overlooked.

The cost of complexity

Design patterns are often sold to programmers with architectural analogies. Imagine you were building a new home. Would you want the tradespeople doing the work to reinvent domestic plumbing systems? Would you want the electrician to cook up his own approach to wiring fuses?

No alt text provided for this image

A few design patterns short of perfection

But building software systems is very different than building houses. For one thing, design patterns aren’t ingredients you can drop straight into your code, like a handy function from a class library. Instead, each pattern is a model that needs to be implemented. Most design patterns define an interaction that spans different objects, which means you need to make changes to several classes. The sheer weight of this extra code complicates your design. They’re especially dangerous for new developers, who never see a coding side-trip they don’t want to take.

Design patterns are opinionated. They embed themselves in your code, and they pull your classes in specific directions.

Even when design patterns are at their best, they force you to trade simplicity for something else. Often, that “something else” is just a vague promise of good encapsulation and a warm fuzzy feeling.

No alt text provided for this image

Even the simplest patterns have a cost and introduce complexity. Consider the humble Singleton pattern—a class that only allows one instance. Despite its conceptual simplicity, there’s roughly a dozen different techniques for implementing the Singleton pattern, depending on whether you need thread safety, lazy loading, serializability, support for inheritance, or you just love enums.

It’s not that Singleton design is an advanced concept. It’s just impossible to design any single code ingredient to be perfectly generalized and perfectly suitable to every use case. And to this day, architects still debate if the Singleton is a virtuous gold-plated pattern or an anti-pattern— something you should strive to avoid, because someday it will betray you.

Ambiguous extensibility

Design patterns are all about increasing abstraction in your code. Patterns like Proxy, Bridge, Adapter, and Facade add layers in between objects. At first, this seems like programming paradise. What virtuous programmer doesn’t want less dependency between objects?

We all know the rule: All problems in computer science can be solved by another level of indirection. But there’s a side effect, too. Every extra layer of indirection adds a new place where you can put a solution.

Keep reading ...

要查看或添加评论,请登录

社区洞察

其他会员也浏览了