4 ms·
This is great. I always thought that GoF patterns is largely obsolete in 2022, it would be nice if the author agreed and has a list of GoF patterns that really
by rr808 5y ago
This is great. I always thought that GoF patterns is largely obsolete in 2022, it would be nice if the author agreed and has a list of GoF patterns that really dont make sense any more. Builder was one I thought should be included but OP seems to think its relevant (though different).
- jerf 5y agoIn terms of obsolete GoF patterns, Flyweight is my nomination. It's not that it's useless, is just that in an era of 64 MB of RAM, it makes sense that people might need to know about it, but in an era of 64 GB of RAM the need is diminished to the point that only the people who have those problems need to worry about it. And if you do have those problems, it isn't even necessarily what you would reach for first. Though it's at least on the list.
- hermitdev 5y agoI think I've used flyweight in exactly one production system, and it was a trading system. Lots of transactions (easily tens or hundred of millions in a given day in a single process), lots of duplicated instrument data. Perfect use case for flyweight. But, yeah. It's a fairly rare use case. Good to know about, but not necessarily one you need to keep fresh in mind, ready for use.
- hcrisp 5y agoLuciano Ramalho in his book "Fluent Python" mentioned that some (most?) of the GoF patterns are unneeded in a dynamic language like Python. I see [0] he is favorable to this site's author, so it is probably worth a look. [0] https://twitter.com/ramalhoorg/status/960746929025142784?s=20&t=5bJW1H_sB25B7KZvwNEX0g https://twitter.com/ramalhoorg/status/960746929025142784?s=2...
- stingraycharles 5y agoInteresting, thanks for sharing. Is the opposite also true, that when a language is statically typed, design patterns are likely to be needed?
- javcasas 5y agoIt depends on the language expresiveness, not on it being static/dynamic types. Dynamic languages tend to have less limitations to expresiveness (no typechecker in the middle) and then you have programming languages with static types and decent typecheckers that don't require design patterns because they are still very expressive.
- polynomial 5y agoHow did you happen to see that? That tweet is perfectly relevant, it's byond uncanny that you had it at the ready.
- hcrisp 5y agoCoincidence. I was trying to find the reference to Ramalho's comment about GoF and found his comment in a random search.
- hcrisp 5y agoI found the quote. He says Peter Norvig wrote that "16 out of 23 patterns have qualitatively simpler implementation in Lisp or Dylan than in C++ for at least some uses of each pattern" and that Python shares some of the dynamic features of these languages such as first-class functions. I wonder if making GoF patterns simpler or even "invisible" in C++ using functions or callable-objects is implicitly not allowed because of the static typing of the language or if it just wasn't considered by the authors.
- javcasas 5y agoMost of the design patterns exist because of limitations in programming languages, especially java/c++/c#. The strategy pattern disappears when you can store functions in data structures. The abstract factory pattern disappears when you can pass functions as parameters. The builder pattern disappears when your progamming language has named parameters. The observer pattern is callbacks with additional steps. The mediator pattern disappears with support on variants of functional reactive programming. The iterator pattern disappears by using your favourite version of generators (or just go hardcore like Haskell and do foldable/traversable). IMO GoF has been obsolete for the last 20 years (50 years if you consider that languages like ML, Lisp and friends already existed then).
- valenterry 5y agoStoring functions in datastructures with the purpose of applying a different logic depending on context/configuration but with the same goal _is_ the strategy pattern. It doesn't matter if you call it like that or not.
- javcasas 5y agoDo we have a special name for storing numbers in data structures? Do we have special names for storing strings in data structures? Do we have special names for storing lists in data structures? Do we have special names for storing source code as strings in data structures? Do we have special names for storing abstract syntax trees as data structures? Do we have special names for storing compiled code as data structures? Do we have special names for storing pairs of compiled code and related memory in data structures? Why do we need special names for storing functions in data structures? When I filter the list of numbers it's not a strategy pattern. Neither is when I filter the string list, or the AST list, or the compiled code+closure list. But, somehow, if it's a function list then it's a strategy pattern. Free your mind of unnecessary labels.
- valenterry 5y ago> Do we have a special name for storing numbers in data structures? Yes, we do. For instance, if I store numbers that describe a limit, I'll call it a limit. And it will give a hint how it is used. Do I call all numbers in a data structure limit? Of course not - the same is true for functions in datastructures. > Why do we need special names for storing functions in data structures? Well, it is helpful. There are many reasons to store functions in datastructures. For example to do mappings, to cache/memoize them or even to create interpretable datastructures, using free monads. But the strategy pattern describes the situation where there are multiple functions and they all serve the same purpose and have the same interface (and thus are interchangeble) and usually one is chosen and applied - but it is expected to be different ones, depending on the context. Do we really need a name for that or use it in code? I don't know. But that's not the my point - which is that the concept doesn't go away just because it is easier to use it. > When I filter the list of numbers it's not a strategy pattern. Neither is when I filter the string list, or the AST list, or the compiled code+closure list. Sure, if you don't change the way you filter then it's not a strategy pattern. > But, somehow, if it's a function list then it's a strategy pattern. Now you have lost me. Maybe we disagree because we are talking about a different thing?. A list of functions does not make a strategy pattern. And very often, strategies are implemented using inheritance (or composition) without any lists being involved. At least that's how I remeber the pattern when I saw it (in the pure functional programming world we indeed rarely call it like that) and how it's written in the GoF book.
- happymellon 5y agoBuilder patterns work very well for generation of templates. I use them a fair amount when dealing with Amazon's CDK as it helps with fixing a lot of readability issues. I see people claim that GoF patterns are obsolete, and that builder is one of the ones that are old hat, but for making configurations readable it can be the best solution.
- javcasas 5y agoWhat's the advantage of: t = TemplateBuilder() .withFoo(foo) .withBar(bar) .excludeBaz() .build() over: t = Template(foo=foo, bar=bar, baz=none)
- culturedsystems 5y agoI agree there's not much point using this kind of simple builder if you have named function parameters, but the GoF builder pattern has a couple of additional features which can still be useful. In the GoF examples the construction process is more complicated (maybe the order in which construction steps take place is significant, and maybe parts of the construction might be conditional), and the same construction algorithm can be used to produce different types of object. If I remember correctly, the main example in the GoF book is a builder for creating documents by adding a title, subtitle, paragraphs, etc, and the document being constructed might be a UI representation, an RTF file, HTML, etc.
- valenterry 5y ago> maybe the order in which construction steps take place is significant That is just horrible... > maybe parts of the construction might be conditional No builder pattern needed for that, just use optional arguments and/or an option/nullable type.
- hermitdev 5y agoI think the builder pattern is more useful when you have sets of parameters that make sense together, but may be mutually exclusive with others. A more compelling example would be an IP address builder that supported different versions. ipv4 = IPAddress().v4("127.0.0.1").build() ipv6 = IPAddress().v6("::1").build() Trying to perform something like this in Python with merely a constructor on an IPAddress type would lead to a not-so-obvious interface (such as use X set of named args to construct a v4 address or use Y set of named args to construct a v6 address, but using X & Y in the same constructor is a runtime error). This is my contrived example for where the builder pattern might make sense. With your example, I don't see any compelling advantage to use the builder pattern. In fact, I'd argue as-is, the builder is unnecessary, is more verbose, adds additional complexity, and you should just use the constructor with named args instead. The point behind the builder pattern is to perform nontrivial initialization that is hard/difficult/impossible to perform in a normal constructor a la C++, C#, Java, etc. If you're not performing nontrivial initialization, you've just introduced extra verbosity and complexity for no gain, so don't use the pattern then. This is, of course, just my opinion. For example, if you see code that has a lot of overloaded constructors followed by an `init` function that must be called after construction, or code with a lot of overloaded `init`-type functions, only one of which shall be called; the builder pattern might make sense there.