Design Patterns in Dynamic Programming (1996) [pdf]
norvig.com
norvig.com
Or as someone else once put it, "design patterns" might more accurately be called something like "palliative idioms for pain points in static manifestly typed class-oriented languages."
That's a little bit unfair, given Smalltalk's place in all this, but one of the wastes of time over the last 20 years has been the ways in which some dynamic languages cargo-culted practices from, say, the Java world because Design Patterns™ were The Mark of A Professional™.
The fact this happened in JavaScript with Angular is particularly atrocious.
New hypothesis: Some practices make all the sense in the world in huge enterprise projects, and no sense at all in small utility projects.
Funny enough though. Those that I work with still write a lot of what I would call scripts, but they're super over architected and a lot of time is wasted and it is hard to read them. Sometimes simplicity is best as you observed.
class GetNoCacheDefaultCookieJarStrategy {
...
}
fetch('https://google.com', new GetNoCacheDefaultCookieJarStrategy())
over const my_usual_fetch_opts = {...}
fetch('https://google.com/', my_usual_fetch_opts)
There are almost no uses of the strategy pattern that aren't equivalent to a trivial first-class function like a filter predicate or equivalent to a trivial plain-old-key-value-options-object, so the non-pattern version is stylistically preferred in the 99% case where it's not actually necessary.One way to look at the patterns book is that it communicated a bunch of software architectural patterns that a developer might learn over many years of reading code others had written, and writing their own code. Suddenly, a new programmer could recognize and use those patterns immediately.
Of course, at the time, it wasn't lost on the people who knew a bunch of OO analysis and design methodologies and programming languages, that there was heavy C++ bias to the exact patterns included. And we started to make comments like Norvig did here. But design patterns and the book were a good idea.
Also, I was just a kid developer at the time, but, when the book first came out, I recall one of the principal engineers was looking into how patterns might be used for documenting large, well-engineered OO systems.
Smalltalk is single inheritance, single dispatch, so it's going to need some of those patterns. I suspect that Visitor will have some considerable boiler-plate in it, compared to how it disappears in CLOS. (The boiler plate, that is, not the pattern overall; the concept of visitation is still there, just not in so many lines of code.)
Anyway, are those examples really the best Smalltalk solutions, or are they just there to show how the patterns look in Smalltalk?
For instance, the ability of an object to change type (or appear to do that somehow) will blow off those patterns that deal with simulating an object changing type as it changes state, like the State pattern.
Smalltalk has something called become which isn't exactly the same thing as Lisp's change-class, but it sounds like a reasonable facsimile thereof which could obviate the State pattern. Like if we have a widget that changes from an idle to a running state, we could just have a variable iw that is of type idle_widget, and then say "iw: become rw", where rw is a running_widget constructed from the properties in iw.
Does the book, by chance, have State done up in Smalltalk without mentioning the become operator?
I remember reading the Ruby book about design patterns. It was painful and the general motto of the book was "you don't need this and that static design pattern".
However, I think as a community we should be defining a collection of design patterns that are useful in dynamic languages. At the end of the day, the main idea behind Design Patterns was the definition of higher-level logic constructs that could be used to solve a problem when developing software.
It is like in the construction industry where bricks are the "code" and the 'best practices' (design patterns) of how to built houses with bricks do not apply when you are building a house using wood. Sure, brick design patterns do not work for wood, but that does not mean that wood building doesn't have their own patterns.
But then one could claim that monads are a palliative idiom for pain points in function-oriented languages, with at least as much justification.
Or one could think that we're bumping into some flavor of the expression problem: There is no language style that makes all things easy to write.
Arrays are a monad. I think some monads can be described that way, but monads as a whole run into the "tensor trouble" of being so damned general that nothing can really be said about them... except for useless generalities.
I laughed. There are real uses for dynamic programming though. It is sad that only the lucky get to work on those types of problems.
> This practice is not only common, but institutionalized. For example, in the OO world you hear a good deal about "patterns". I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work. When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough-- often that I'm generating by hand the expansions of some macro that I need to write.
I am currently listening to the Software-Engineer Radio Podcast from 2006/2007, and they talk heavily about patterns. Even though the POSA books patterns may not be applicable to dynamic languages like Ruby or JavaScript, I think the right idea is to define new patterns that are useful for these type of languages.
Maybe one reason why we don't have this is because nowadays to solve a more "specific" problem the only thing you need to do is to install some third party library from github that already does it? (like if I wanted to implement an undo-redo fucntionality I will use maybe this: https://www.npmjs.com/package/undo-redo )