I think we've done a poor job as an industry of beating new developers over the head with "know the tradeoffs!" Design patterns are taught without teaching their tradeoffs, and so new developers think that it's best practice to apply every possible design pattern as eagerly as possible.
I agree that naming patterns is useful, but IME they've been a net negative on the code bases I've worked on, since the way they're taught encourages using them mindlessly without considering their costs.
Design patterns can reduce a lot of unnecessary cognitive overhead. For example, a builder pattern that takes a config a returns an evaluation pipeline is really simple and eliminates a lot of runtime if..else conditions.
Are you really trying to argue that a collection of terminology aimed at describing high level concepts, or standard solutions to commonly repeating problems and requirements, is a code smell?
What other good engineering practices are also code smells?
Design Patterns are tools in a box, aiming to create scalable solutions, but the way a solution is implemented is up to the implementer. Design patterns just try to establish the language.
In the same way, any sufficiently complicated C++ program contains an ad hoc, informally specified, bug ridden implementation of half of the Gang of Four design patterns. They would be better off just using the patterns, instead of trying to roll their own half-baked solutions to the same problems.
If you've got one of those problems, use the standard, tested solution. If you don't have one of those problems, don't shoehorn in a solution that doesn't fit.
It's not that hard to grasp (except for junior devs who have recently read a pattern book...)
Is having parameters at all "The Parameter Pattern"? Should we call passing a boolean flag "The Flag Pattern"?
To me, "Design Pattern" implies at least some higher order structure than that (and which is not natively abstractable over in the language in question).
Regarding the strategy pattern, when does it start becoming the pattern and when is it just "passing a function as a parameter"?
sortList(list, [](const item& i) {return i.name();});
struct MySorter
{
bool operator ()(const item&) {...}
};
sortList(list, MySorter{});
class MySorter : public ISorter
{
public:
virtual bool execute(const item&) override {...}
};
sortList(list, MySorter{});So yes, there are trivial things which you can argue the toss on, but in the last month I've used HTTP libraries that don't allow you to supply a strategy for retry logic and machine learning libraries that don't allow a strategy for early stopping.
Yes
> Should we call passing a boolean flag "The Flag Pattern"?
The fact that we call it a flag, in itself a metaphor, shows that this is exactly what is happening already. We just omit the "pattern" as it is not necessary for understanding.
Pattern just means "something that occurs repeatingly". Some things do so obviously, others a bit less obviously.
My experience teaching comp. sci. is that when faced with problems that call for design patterns, ~40% of 20/22 y.o. students are able to come up with the "classical" design pattern implementations on their own in a couple hours without prior exposure to them. For the rest, well, we have the books.
I think this is even mentioned in the GoF book. The point of naming these patterns is not that they're amazingly innovative. The point of "Patterns" is that when we give them a name we can (a) discuss them easier with a common language, and (b), we can recognise when we use them again so to remember the pitfalls of last time.
Other languages, like e.g. Rust (because of lack of HKT), cannot express monads like Haskell can.
But yeah, you can definitely call it a design pattern if that’s what the culture around the language is like. But it would be like Java folks calling interfaces with default implementations for something goofy like “Interface with stateless implementations pattern”, and even they don’t go that far.
But in Haskell, a lot of the time you don't use a monad because you want a monad. You use a monad to do something else - to log in a pure way, for example. That use of a monad to solve a particular problem is a pattern.
I'd even argue that it's using the pattern to compensate for a weakness of the language. (Or, if you prefer, to help with things that are difficult within the language design and philosophy.)
You mean like a bit field?
Did you realized that with only two words you can convey amultitude of information regarding it's use and implementation and properties?
Two words.
Perhaps there is more to design patterns than mindlessly complaining about stuff you don't fully understand.
/s