This is probably the most important part. In the last addendum on the last page:
Since most of these people haven’t read the Alexander book, they can’t possibly argue with my point. But they know about iterators, so they argue with me about that. To date, nobody has written to me to say that I misunderstood what Alexander was saying; just loads of stuff about how I don’t understand iterators. But the iterators are irrelevant. Just ignore that part of the talk if it bugs you. It’s not important.
Apart from the main point, promoting interest in Alexander’s book A Pattern Language (which I just ordered), I was surprised to finally find the original raison d’etre of Design Patterns: to paste in bits of code that overcame the lack of convenience mechanisms in earlier versions of C++ and Java.
I realize now that I had never placed the GOF book in it’s original context, especially it’s time. Back then, this made a lot of sense. As much sense as the magazines with printed program code before the internet. It might even have made sense to call these bits of code ‘patterns’.
But this also points out very clearly that clinging to these patterns today is absurd. Believing they hold some sort of fundamental truth about programming is a big fallacy. In fact, claiming that any aspect of structuring a program relies on recurring patterns makes no sense. Common terminology can be very useful, yes, but recurring design structures, no. Every programming scenario and thus every design is different almost by definition: if a problem occurred before, it will already be solved so you don’t need to do so again.
In other words: it’s finally time to decisively ditch the religious status of the GOF book and develop new ideas about structuring code that fits our current times.
I think it was a great disservice to the industry as a whole, and to their students, when instructors started teaching design patterns as if they were first principles of programming. If you read the GoF book it is pretty clear that even in the context of working around C++ shortcomings, the patterns are primarily descriptive, not prescriptive: “We see that a common thing people already do when confronted with a problem shaped like X is to use a solution shaped like Y. Here’s a name for Y so we can have conversations about it and not have to explain what we’re talking about every single time.” I never got the sense from the GoF book that the authors intended it to be a rulebook.
I was super frustrated when I was being asked to be able to cite and explain GoF design patterns when interviewed for a (senior) Go SE position. I mean, ok, a few of them kinda maybe still carry over, and thus could be used in speaking when mentoring juniors, but the majority are not relevant at all in Go! Basically, just use a closure, most of the time… Fortunately, I’ve recently learnt, that for other reasons as well, it’s probably good for me that they didn’t want to hire me in the end.
I really don’t think Design Patterns were “to paste in bits of code that overcame the lack of convenience mechanisms in earlier versions of C++ and Java”. First, they’re not language specific — when the book came out, I recognized a lot of them from Smalltalk-80. Second, they’re not as simple as copy/paste. Third, good frameworks incorporate the appropriate patterns for you so you don’t have to re-implement them.
The author really seems to misunderstand some of this stuff. His statement that (paraphrasing) “the Iterator pattern is for sucky languages” misses the point that the reason iterating is so easy in higher level languages is because their collections already have iteration baked in. If you implemented a custom collection like, say, a b-tree in Perl, you’d need to do some work to be able to iterate it simply. And that work would probably look just like the Iterator pattern.
Maybe you want to read it again. Especially the Postscript although I’ll warn there are spoilers in there.
You’re arguing with something the author isn’t saying. I agree that a book about designing a town is more useful (and less harmful) to programmers than the book about iterators.
If you implemented a custom collection like, say, a b-tree in Perl, you’d need to do some work to be able to iterate it simply.
So don’t do that? One important part of Alexander’s patterns is (paraphrasing) that the implementation serves needs instead of the other way around. Most problems don’t need a b-tree (and most people that use them could choose something better) and even those that do have a b-tree don’t need (or even should) iterate.
Most software design needs good data structures, they’re critical for efficiency and they also frame how you think about the problem. A language that makes designing a new data structure difficult is a problem.
That said, although I like the core idea overall, I think the author picked a terrible example in iterators. As he says, Alexander’s design patterns were about delegating aspects of design[1]. Iterators do exactly that: they exist to allow someone who is an expert in designing an efficient data structure build something that can then be used by someone who is focusing on high-level application design. That’s exactly the same idea that Alexander has in, for example, his nook or niche patterns: allowing someone with fine-grained local knowledge to design a space, without needing the person laying out the floor to understand that.
There’s a lot more to Alexander’s ideas, particularly in how to build cohesive overall structures, but I don’t think it’s fair to say that GoF-style patterns are something completely different, they’re just a subset of Alexander’s vision. And, to be fair to the software engineering community, they’ve done better than architects by embracing even part of Alexander’s vision. I’ve never worked in a building that wouldn’t have been improved by first hitting the architect repeatedly with The Timeless Way of Building and then making them read A Pattern Language.
[1] I’d thoroughly recommend reading everything he wrote, but if you don’t have time and want to learn something directly relevant to your day-to-day job, the chapter in Peopleware on office design cites Alexander and gives one of the best one-page summaries I’ve ever read of his core ideas.
Most software design needs good data structures, they’re critical for efficiency …
I have heard this before, but I think it’s a myth; It’s repeated so often people believe it to be true without people ever evaluating it for themselves, and that’s a shame. Spend a few years in an Iverson language and you will be convinced otherwise: All you need are arrays and good tools for operating on arrays.
Instead of a b-tree, use an array and binary search
Instead of a hash-table, use two-arrays of the same length, and order them by the hash-position of the value in the first.
Instead of an ordered hash-table, keep the hash-positions as a permutation index in a third array.
Instead of a bloom-filter, just use one-array and the same hash-position function you used for the hash table.
Instead of an lsm-tree, use a array-of-arrays, and an array-of-lengths.
And so on.
Arrays work better than anything else for performance. Operating systems have excellent support for mapping arrays to permanent storage. CPUs have special logic and operators for dealing with arrays. The highest-performing fastest databases in the world don’t use anything more exotic than arrays.
… and they also frame how you think about the problem.
I think you should take a look at notation as a tool of thought. I believe so strongly that this is a better way to think about the problem than “data structures” that I would prefer them even if they weren’t faster.
Thankfully I don’t have to choose.
There’s a lot more to Alexander’s ideas, … I don’t think it’s fair to say that GoF-style patterns are something completely different
I think we must’ve read different books. I enjoy a humanist and organic design philosophy, and I can’t agree that “design patterns” is it. I’m also not sure Christopher Alexander would agree with you:
When I look at the object-oriented work on patterns that I’ve seen, I see the format of a pattern (context, problem, solution, and so forth). It is a nice and useful format. It allows you to write down good ideas about software design in a way that can be discussed, shared, modified, and so forth. So, it is a really useful vehicle of communication. And, I think that insofar as patterns have become useful tools in the design of software, it helps the task of programming in that way. It is a nice, neat format and that is fine.
However, that is not all that pattern languages are supposed to do. The pattern language that we began creating in the 1970s had other essential features. First, it has a moral component. Second, it has the aim of creating coherence, morphological coherence in the things which are made with it. And third, it is generative: it allows people to create coherence, morally sound objects, and encourages and enables this process because of its emphasis on the coherence of the created whole.
Spend a few years in an Iverson language and you will be convinced otherwise: All you need are arrays and good tools for operating on arrays.
I think you’re disagreeing with people because you use words to mean different things. All of the things you say you can use instead of data structures are implementations of those data structures.
All of the things you say you can use instead of data structures are implementations of those data structures.
I’m not sure I’ve ever heard anyone suggest that a b-tree is the same as a sorted array. The performance difference is striking.
In any event, they’re definitely different in the critical way: They all use the same “iterator” which should prove that an iterator isn’t a pattern, but a single operator.
I think you’re disagreeing with people because you use words to mean different things.
I’m agreeing with the author of the linked post. I’m disagreeing with you. I also think abuse is a poor form of debate.
Arrays work better than anything else for performance.
But the ways APL uses arrays are terrible for performance. A lot of common idioms do huge amounts of work on large intermediate arrays to produce a particular transformation, kind of like those Rubik’s Cube macros where you flip six or seven edges to rotate one pair of corners.
My college compilers class was taught by Jim Kajiya, who had worked on an APL compiler. During the discussion of APL he told us how getting good performance from the language was terribly difficult — it relied on a lot of knowledge of those idioms used in the language, using pattern recognition to optimize those into a more efficient direct implementation of their effect. And such a compiler is only as good as its library of idioms, so I imagine that if you use one it doesn’t know, or use one with slightly different syntax, your performance plummets.
There is also Alexander’s OOPSLA keynote. Here is a quote which shows that he aspire to a lot more than GoF:
I understand that the software patterns, insofar as they refer to objects and programs and so on, can make a program better. That isn’t the same thing, because in that sentence “better” could mean merely technically efficient, not actually “good.” Again, if I’m translating from my experience, I would ask that the use of pattern language in software has the tendency to make the program or the thing that is being created is morally profound—actually has the capacity to play a more significant role in human life. A deeper role in human life. Will it actually make human life better as a result of its injection into a software system?
Which GoF patterns can’t be reasonably implemented as a library of abstract classes (or language equivalent), distributed with a language’s package manager? After reading these slides I went back over the GoF patterns and realized that pretty much all of them could. Distributing them in a book — it even came with “sample” implementations in C++ and Smalltalk! — and calling them “patterns” made sense in the 90s, before any reasonably-modern package managers existed (and when the Internet barely existed), but it doesn’t feel like it still makes much sense today.
Plenty of the “patterns” are fairly… dated, as well. Memento for undo, for example, rather than a lens-like approach of collapsing an immutable series of state updates into the current state (and undo is simply popping off the last state update). GoF feels more like a 1994-era utility library that got some things right — and thus those parts got ported to other languages — and plenty of things wrong, too.
So one implementation of a pattern in one language makes the book unnecessary? That makes no sense to me. The next language implementor has to just copy the existing implementation and translate it to their language, even if the languages are wholly different? This is kind of like saying we don’t need texts on, say, B-trees because you can just go get a B-tree class from a library.
Maybe the patterns in the book seem so obvious to you that descriptions and explanations are unnecessary? I’d say that’s more a result of the book (and other usage of those patterns) having done its job well.
A fun fact: Richard P. Gabriel (the Worse is Better guy) wrote a book called Patterns of Software (available from the author’s website in PDF), and the foreword was written by Christopher Alexander, where he tries to understand how his ideas about building architecture could possibly be relevant to software-engineering.
Was there ever a followup where he actually did take a fresh look at Christopher Alexander?
Judging from the few tidbits in those slides, maybe the Domain-Driven Design approach is closer to Christopher Alexander than GoF? The “ubiquitous language” could map to “pattern languages”? The physics professors would be the domain experts who need to share a language with architect/developer.
Through Wikipedia’s comparison of Alexander’s work with Chomskys generative grammar, I stumbled upon this interesting exploration of this synthesis: A Synthesis of Grammar and Life
Apparently, Alexander didn’t like Chomsky, but this guy, Greg Bryant, built “Grogix” anyways.
To be honest, I’m not sure if I’m looking at genius or madness here.
I love A Pattern Language, but I think it would apply much more directly to software user experience design. The connection to programming was always a stretch.
Something that strikes me now, but didn’t when I was much younger and first read the GoF Design Patterns book, is that much of the book wouldn’t exist if C++ and/or Java at the time had modern-style package managers like npm or cargo. Even very early package managers like gem would’ve obviated most of the need for the “patterns”: in many cases they were just micro-libraries of abstract classes, too small to be bothered with in the era of zipfiles, ftp, and convoluted build scripts, and so they were collected into a book for you to manually type out yourself.
I guess the central point of this talk is: ‘The “Design Patterns” solution is to turn the programmer into a fancy macro processor’ but that is not necessary in higher level languages, where building blocks (such as iteration) are built into the language.
I wasn’t aware of this talk, but I wrote a short blog post making a similar point many years later: https://mike.place/2018/patterns/. I was coming from a different direction: I learned higher level languages first, and simply could not see the point of these patterns, which seemed like hugely over-abstracted one-liners.
It was particularly cool to hear Rebecca Wirfs-Brock and Ward Cunningham talk about how patterns came out of hanging out in the woods and applying Alexander’s ideas. Also interesting to hear how the wiki concept was borne out of wanting to share and collaborate on patterns.
This is probably the most important part. In the last addendum on the last page:
Brilliant, thanks for posting!
Apart from the main point, promoting interest in Alexander’s book A Pattern Language (which I just ordered), I was surprised to finally find the original raison d’etre of Design Patterns: to paste in bits of code that overcame the lack of convenience mechanisms in earlier versions of C++ and Java.
I realize now that I had never placed the GOF book in it’s original context, especially it’s time. Back then, this made a lot of sense. As much sense as the magazines with printed program code before the internet. It might even have made sense to call these bits of code ‘patterns’.
But this also points out very clearly that clinging to these patterns today is absurd. Believing they hold some sort of fundamental truth about programming is a big fallacy. In fact, claiming that any aspect of structuring a program relies on recurring patterns makes no sense. Common terminology can be very useful, yes, but recurring design structures, no. Every programming scenario and thus every design is different almost by definition: if a problem occurred before, it will already be solved so you don’t need to do so again.
In other words: it’s finally time to decisively ditch the religious status of the GOF book and develop new ideas about structuring code that fits our current times.
I think it was a great disservice to the industry as a whole, and to their students, when instructors started teaching design patterns as if they were first principles of programming. If you read the GoF book it is pretty clear that even in the context of working around C++ shortcomings, the patterns are primarily descriptive, not prescriptive: “We see that a common thing people already do when confronted with a problem shaped like X is to use a solution shaped like Y. Here’s a name for Y so we can have conversations about it and not have to explain what we’re talking about every single time.” I never got the sense from the GoF book that the authors intended it to be a rulebook.
I was super frustrated when I was being asked to be able to cite and explain GoF design patterns when interviewed for a (senior) Go SE position. I mean, ok, a few of them kinda maybe still carry over, and thus could be used in speaking when mentoring juniors, but the majority are not relevant at all in Go! Basically, just use a closure, most of the time… Fortunately, I’ve recently learnt, that for other reasons as well, it’s probably good for me that they didn’t want to hire me in the end.
I always feel that I learn more about the company by the questions they ask, then they learn about me by my answer. That’s good for me, though :)
I really don’t think Design Patterns were “to paste in bits of code that overcame the lack of convenience mechanisms in earlier versions of C++ and Java”. First, they’re not language specific — when the book came out, I recognized a lot of them from Smalltalk-80. Second, they’re not as simple as copy/paste. Third, good frameworks incorporate the appropriate patterns for you so you don’t have to re-implement them.
The author really seems to misunderstand some of this stuff. His statement that (paraphrasing) “the Iterator pattern is for sucky languages” misses the point that the reason iterating is so easy in higher level languages is because their collections already have iteration baked in. If you implemented a custom collection like, say, a b-tree in Perl, you’d need to do some work to be able to iterate it simply. And that work would probably look just like the Iterator pattern.
Maybe you want to read it again. Especially the Postscript although I’ll warn there are spoilers in there.
You’re arguing with something the author isn’t saying. I agree that a book about designing a town is more useful (and less harmful) to programmers than the book about iterators.
So don’t do that? One important part of Alexander’s patterns is (paraphrasing) that the implementation serves needs instead of the other way around. Most problems don’t need a b-tree (and most people that use them could choose something better) and even those that do have a b-tree don’t need (or even should) iterate.
Most software design needs good data structures, they’re critical for efficiency and they also frame how you think about the problem. A language that makes designing a new data structure difficult is a problem.
That said, although I like the core idea overall, I think the author picked a terrible example in iterators. As he says, Alexander’s design patterns were about delegating aspects of design[1]. Iterators do exactly that: they exist to allow someone who is an expert in designing an efficient data structure build something that can then be used by someone who is focusing on high-level application design. That’s exactly the same idea that Alexander has in, for example, his nook or niche patterns: allowing someone with fine-grained local knowledge to design a space, without needing the person laying out the floor to understand that.
There’s a lot more to Alexander’s ideas, particularly in how to build cohesive overall structures, but I don’t think it’s fair to say that GoF-style patterns are something completely different, they’re just a subset of Alexander’s vision. And, to be fair to the software engineering community, they’ve done better than architects by embracing even part of Alexander’s vision. I’ve never worked in a building that wouldn’t have been improved by first hitting the architect repeatedly with The Timeless Way of Building and then making them read A Pattern Language.
[1] I’d thoroughly recommend reading everything he wrote, but if you don’t have time and want to learn something directly relevant to your day-to-day job, the chapter in Peopleware on office design cites Alexander and gives one of the best one-page summaries I’ve ever read of his core ideas.
I have heard this before, but I think it’s a myth; It’s repeated so often people believe it to be true without people ever evaluating it for themselves, and that’s a shame. Spend a few years in an Iverson language and you will be convinced otherwise: All you need are arrays and good tools for operating on arrays.
Instead of a b-tree, use an array and binary search
Instead of a hash-table, use two-arrays of the same length, and order them by the hash-position of the value in the first.
Instead of an ordered hash-table, keep the hash-positions as a permutation index in a third array.
Instead of a bloom-filter, just use one-array and the same hash-position function you used for the hash table.
Instead of an lsm-tree, use a array-of-arrays, and an array-of-lengths.
And so on.
Arrays work better than anything else for performance. Operating systems have excellent support for mapping arrays to permanent storage. CPUs have special logic and operators for dealing with arrays. The highest-performing fastest databases in the world don’t use anything more exotic than arrays.
I think you should take a look at notation as a tool of thought. I believe so strongly that this is a better way to think about the problem than “data structures” that I would prefer them even if they weren’t faster.
Thankfully I don’t have to choose.
I think we must’ve read different books. I enjoy a humanist and organic design philosophy, and I can’t agree that “design patterns” is it. I’m also not sure Christopher Alexander would agree with you:
When I look at the object-oriented work on patterns that I’ve seen, I see the format of a pattern (context, problem, solution, and so forth). It is a nice and useful format. It allows you to write down good ideas about software design in a way that can be discussed, shared, modified, and so forth. So, it is a really useful vehicle of communication. And, I think that insofar as patterns have become useful tools in the design of software, it helps the task of programming in that way. It is a nice, neat format and that is fine.
However, that is not all that pattern languages are supposed to do. The pattern language that we began creating in the 1970s had other essential features. First, it has a moral component. Second, it has the aim of creating coherence, morphological coherence in the things which are made with it. And third, it is generative: it allows people to create coherence, morally sound objects, and encourages and enables this process because of its emphasis on the coherence of the created whole.
I think you’re disagreeing with people because you use words to mean different things. All of the things you say you can use instead of data structures are implementations of those data structures.
I’m not sure I’ve ever heard anyone suggest that a b-tree is the same as a sorted array. The performance difference is striking.
In any event, they’re definitely different in the critical way: They all use the same “iterator” which should prove that an iterator isn’t a pattern, but a single operator.
I’m agreeing with the author of the linked post. I’m disagreeing with you. I also think abuse is a poor form of debate.
But the ways APL uses arrays are terrible for performance. A lot of common idioms do huge amounts of work on large intermediate arrays to produce a particular transformation, kind of like those Rubik’s Cube macros where you flip six or seven edges to rotate one pair of corners.
My college compilers class was taught by Jim Kajiya, who had worked on an APL compiler. During the discussion of APL he told us how getting good performance from the language was terribly difficult — it relied on a lot of knowledge of those idioms used in the language, using pattern recognition to optimize those into a more efficient direct implementation of their effect. And such a compiler is only as good as its library of idioms, so I imagine that if you use one it doesn’t know, or use one with slightly different syntax, your performance plummets.
There is also Alexander’s OOPSLA keynote. Here is a quote which shows that he aspire to a lot more than GoF:
Which GoF patterns can’t be reasonably implemented as a library of abstract classes (or language equivalent), distributed with a language’s package manager? After reading these slides I went back over the GoF patterns and realized that pretty much all of them could. Distributing them in a book — it even came with “sample” implementations in C++ and Smalltalk! — and calling them “patterns” made sense in the 90s, before any reasonably-modern package managers existed (and when the Internet barely existed), but it doesn’t feel like it still makes much sense today.
Plenty of the “patterns” are fairly… dated, as well. Memento for undo, for example, rather than a lens-like approach of collapsing an immutable series of state updates into the current state (and undo is simply popping off the last state update). GoF feels more like a 1994-era utility library that got some things right — and thus those parts got ported to other languages — and plenty of things wrong, too.
So one implementation of a pattern in one language makes the book unnecessary? That makes no sense to me. The next language implementor has to just copy the existing implementation and translate it to their language, even if the languages are wholly different? This is kind of like saying we don’t need texts on, say, B-trees because you can just go get a B-tree class from a library.
Maybe the patterns in the book seem so obvious to you that descriptions and explanations are unnecessary? I’d say that’s more a result of the book (and other usage of those patterns) having done its job well.
A fun fact: Richard P. Gabriel (the Worse is Better guy) wrote a book called Patterns of Software (available from the author’s website in PDF), and the foreword was written by Christopher Alexander, where he tries to understand how his ideas about building architecture could possibly be relevant to software-engineering.
Was there ever a followup where he actually did take a fresh look at Christopher Alexander?
Judging from the few tidbits in those slides, maybe the Domain-Driven Design approach is closer to Christopher Alexander than GoF? The “ubiquitous language” could map to “pattern languages”? The physics professors would be the domain experts who need to share a language with architect/developer.
Through Wikipedia’s comparison of Alexander’s work with Chomskys generative grammar, I stumbled upon this interesting exploration of this synthesis: A Synthesis of Grammar and Life
Apparently, Alexander didn’t like Chomsky, but this guy, Greg Bryant, built “Grogix” anyways.
To be honest, I’m not sure if I’m looking at genius or madness here.
I love A Pattern Language, but I think it would apply much more directly to software user experience design. The connection to programming was always a stretch.
Something that strikes me now, but didn’t when I was much younger and first read the GoF Design Patterns book, is that much of the book wouldn’t exist if C++ and/or Java at the time had modern-style package managers like
npm
orcargo
. Even very early package managers likegem
would’ve obviated most of the need for the “patterns”: in many cases they were just micro-libraries of abstract classes, too small to be bothered with in the era of zipfiles, ftp, and convoluted build scripts, and so they were collected into a book for you to manually type out yourself.I guess the central point of this talk is: ‘The “Design Patterns” solution is to turn the programmer into a fancy macro processor’ but that is not necessary in higher level languages, where building blocks (such as iteration) are built into the language.
I wasn’t aware of this talk, but I wrote a short blog post making a similar point many years later: https://mike.place/2018/patterns/. I was coming from a different direction: I learned higher level languages first, and simply could not see the point of these patterns, which seemed like hugely over-abstracted one-liners.
If you get a chance, I would highly recommend this talk https://www.deconstructconf.com/2017/brian-marick-patterns-failed-why-should-we-care.
Here’s a recent panel by organizers of the Software Patterns movement that offers their own perspective on how patterns were intended as heuristics to guide developers: https://www.hillside.net/home/news/327-patterns-principles-and-agile-connections?fontstyle=f-smaller
Recorded video is at https://www.hillside.net/videos/PatternsPrinciplesAndAgileConnections.mp4
It was particularly cool to hear Rebecca Wirfs-Brock and Ward Cunningham talk about how patterns came out of hanging out in the woods and applying Alexander’s ideas. Also interesting to hear how the wiki concept was borne out of wanting to share and collaborate on patterns.