Unpopular opinion, but I think the Design Pattern book created more problems than it solved. It encouraged people to come up with clever designs for object-oriented systems. Object-oriented systems themselves tend to get too complicated. And then making people think they have to use some kind of smart design encourages an addition of complexity.
The first rule of design should be make it as simple as possible. And this book, I think, does the opposite for many people.
I don't think that is an unpopular opinion at all, and I like OO programming just fine. People latched onto Design Patterns like that were tablets from God whereas the book was better thought of as giving a taxonomy to existing practices (and not even best practices.) Different subsets of their patterns work better in different languages, and it is pointless to force a specific pattern into a design where it doesn't fit naturally.
I think it is useful to say "This design could be thought of as a delegate" when explaining your code, but saying "We need a delegate design pattern here" is needlessly prescriptive.
> People latched onto Design Patterns like that were tablets from God whereas the book was better thought of as giving a taxonomy to existing practices (and not even best practices.) Different subsets of their patterns work better in different languages, and it is pointless to force a specific pattern into a design where it doesn't fit naturally.
> I think it is useful to say "This design could be thought of as a delegate" when explaining your code, but saying "We need a delegate design pattern here" is needlessly prescriptive.
1000% this. The authors of the book describe it as a catalog of existing solutions to be applied appropriately given specific criteria, not as a panacea to all engineering problems. I've worked with a few architectural prescriptivists who shoehorned everything into a GoF Design Pattern - and amusingly enough none of them had actually read it and so could only name the common ones like Repository, Factory, or Singleton. Everything that wasn't one of these was just a Facade as far as they were concerned. This definitely worked but it left much to be desired once you started venturing out of rote CRUD territory.
On the other hand I had one Team Lead that shunned such tradition and purposefully mashed several things I'd written (Facotries, Repositories, and a Service that encapsulated everything) into a single giant "Helper" class destroying any abstraction or separation of concerns in the process. I guess it made little difference because that team never wrote unit tests but it wasn't good design by any stretch.
I digress but the idea is thus: some things in our field are common and timeless. It's helpful to give them names and to understand what the historical pain points are. It's not helpful to use them as a whooping stick.
What it was trying to be was misunderstood. Arguably, there were too few patterns and they were provided as a way to build software like LEGOs.
I've read "A Pattern Language: Towns, Buildings, Construction" which was the inspiration for the GoF book. That book had 253 patterns and they were written as "here are ways architects solve common problems". Pattern 148 - small work groups
> When more than half a dozen people work in the same place, it is essential that they not be forced to work in one huge undifferentiated space, but that instead, they can divide their workspace up, and so form smaller groups.
> In fact, people will feel oppressed, both when they are either working in an undifferentiated mass of workers and when they are forced to work in isolation. The small group achieves a nice balance between the one extreme in which there are so many people, that there is no opportunity for an intimate social structure to develop, and the other extreme in which there are so few, that the possibility of social groups does not occur at all.
> ...
> Break institutions into small, spatially identifiable work groups, with less than half a dozen people in each. Arrange these work groups so that each person is in at least partial view of the other members of his own group; and arrange several groups in such a way that they share a common entrance, food, office equipment, drinking fountains, bathrooms.
> Lay the workgroups out with respect to each other so that the distances between groups is within the constraints of OFFICE CONNECTIONS (82), and give each group office space which leaves room to expand and to contract-FLEXIBLE OFFICE SPACE (146); provide a common area, either for the group itself or for several groups together or both —- COMMON AREA AT THE HEART (129). Treat each small work group, in every kind of industry and office, as a place of learning—MASTER AND APPRENTICES (83). Give it its own stair, directly to the street—OPEN STAIRS (158). Arrange the individual workspaces within the small work group
according to HALF-PRIVATE OFFICE 152) and WORKSPACE ENCLOSURE (183) . . . .
It's a not a dictate, but rather descriptive of "these are problems and ways people solved them" along with maintaining a unified vision of the design.
The GoF book became prescriptive instead. People used the patterns in anticipation of the problems rather than because they had them.
> Bill Venners: Is the value of patterns, then, that in the real world when I feel a particular kind of pain I'll be able to reach for a known solution?
> Erich Gamma: This is definitely the way I'd recommend that people use patterns. Do not start immediately throwing patterns into a design, but use them as you go and understand more of the problem. Because of this I really like to use patterns after the fact, refactoring to patterns. One comment I saw in a news group just after patterns started to become more popular was someone claiming that in a particular program they tried to use all 23 GoF patterns. They said they had failed, because they were only able to use 20. They hoped the client would call them again to come back again so maybe they could squeeze in the other 3.
> Trying to use all the patterns is a bad thing, because you will end up with synthetic designs—speculative designs that have flexibility that no one needs. These days software is too complex. We can't afford to speculate what else it should do. We need to really focus on what it needs. That's why I like refactoring to patterns. People should learn that when they have a particular kind of problem or code smell, as people call it these days, they can go to their patterns toolbox to find a solution.
---
The Patterns from GoF became the goal without understanding what a Pattern is. It's a way to hold complexity. A function call is a Pattern. Store volatile registers onto stack, put return address onto stack, put parameters onto stack, jump to new instruction, restore registers.
That Pattern is now hidden inside of `foo(bar, qux)` and that hides a lot of the complexity for what is being done.
But we don't come with the idea that to write a good program, you must use functions. Well, you should because they're likely complex enough to need them... but we use them when we need to manage that complexity.
A phrase I used before was that the GoF isn't a cookbook but rather a bestiary of complexity.
The problem is when people use Patterns in anticipation of complexity that isn't there. So when they're putting patterns in places, as a maintainer you see dark and (maybe) empty cages. Do you want to stick your hand in it to see if it will get bitten off?
Don't have empty complexity cages. And when you do need the complexity cage, properly illuminate it with a clear description of what it is and what complexity it contains.
I think design patterns should be more descriptive, but people try to use them prescriptively.
Being able to say "circuit breaker" pattern or "visitor" is a time efficient way to communicate complicated ideas. Its value is being able to conserve the limited bandwidth speaking has.
Bad coders will always find something or another to justify their work with and it just so happens the most popular book is often referenced, for good and bad.
You're right, but the key thing about description and prescription is that they aren't really separate. You constantly have to ask "does this work well here?", "should I replicate it there?", and so on. They deal with the same thing in different modes of interaction, and so being able to structure these analyses is important to doing each well.
You'd be surprised at how often seniors don't actually ask those questions when it comes to prescriptive standards. They get used first and questions only come up when it's too late.
100% agree. The worst offenders imho are DRY and inheritance. In most cases it causes garbage code that adheres to some lofty goals but sucks to be maintained. We actually do the opposite of DRY: isolate behaviour, even when shared. If complex enough and shared: build a lib. But one use case = one app functionality. We are so happy and productive with that. Throw in ports + adapters and use cases (= one feature) and you're set.
You know what sucks more than fixing problems with inheritance? Fixing 20 different copies of the same bug, or just having to copy over dozens of methods in the first place. If you feel like inheritance is wrong, it's probably because you've got too many corner cases and too many responsibilities shoved into a class. Composition can help in such cases, but there's maybe no magic pattern if each object is too different from the rest.
I think it's different in this case. It was a product of its time, dealing with languages designed and used in its time. The concept of defining and applying design patterns based on Christopher Alexander's work was solid. The problem has always been that people didn't understand that these were examples for a specific world, and that other worlds would and should either have different patterns or those patterns would look different.
I think GoF is all right, when viewed as a book of gadgets. That is, if you have this problem, then consider this mechanism as a fix.
The problem is, people treat it like a "here's how to do OO design" book. It is not suited to that, and especially not suited to being the one and only OO design book that people read.
I guess this is my actual problem with it, or at least the way that it's been received. It implicitly posits that programming is a collection of gadgets. A gadget is a fine thing, when you have decided _what_ you want to do and are looking for a way to do it.
But a gadget-centric process, whether is patterns or microservices, constrains the design space to assemblies. and that a really small and clunky part of the space.
Actually, I think it's the other way around. Trashing the GoF is a sign of a blind trend follower. Someone who lauds them are bucking the trend and might have interesting things to say about it.
It's kind of the "barber pole" of fashion. Independent of the merits of the thing at hand (it may be GoF, a language, a library, Uncle Bob; even outside programming like research methods; outside science like word use and euphemisms etc), the in-crowd moves faster and arguing against a perceived popular thing can make you (feel/appear like) a trendsetter, a visionary.
It goes in cycles, once the contrarian position becomes established, reverting to the original becomes the new cool. The "it's good actually", or that meme where the dumb guy thinks simple thing X, the mediocre average guy thinks a loooong, elaborate sophisticated thing Y, and the wise guru thinks simple thing X again.
GoF was long enough ago that if you're advocating for it, it seems dated, it seems you're either a novice or someone who came of age at that time and has not read anything new since. It's like someone suddenly discovering Kahneman and cognitive biases and argumentation fallacies and proselytizing on them. Regardless of the merits, culture has moved on, has digested it, built in the good parts, spat out the bad, and the zeitgeist is elsewhere.
I tend to agree. The OOP-all-the-things mantra created many problems; lots of books were printed (more than necessary), and lots of evangelists made their name on unnecessary abstractions over abstractions.
One might blame Java for that, but it's a chicken-and-egg problem.
I think you underestimate how chaotic things would get without some basic concepts like patterns laid out. Like so many things in this industry, disproportionate attention is drawn to perceived problems rather than things that quietly work well with the same tech.
In my experience, design patterns cause a lot of problems when developers reach the stage when they understand them enough to know how to implement them, but not when (and even more importantly, when not).
Most design patterns were invented as workarounds to specifics and limitations of certain languages/paradigms, and work great in that case -- but are much more limited, or even downright dangerous, when used in other contexts. As a clear example, the GoF patterns focus on strongly typed OOP languages like Java or C++, and will result in difficult to maintain bloatware if copied directly to dynamic languages like Python, Javascript or PHP (source: been there, done that, got the t-shirt).
ruby engineers are the kings of over-engineering. ruby kinda feeds that beast with the way you can construct "elegant dls's" but they are never really elegant in practice.
The first rule of design should be make it as simple as possible. And this book, I think, does the opposite for many people.