The best explanation I heard of design patterns is, that they are not a template to slavishly follow when producing code, but a common language to talk about code. So you should be able to go and identify, look, this is an iterator, this is a command pattern, this is a monad, and you have a clear and concise way to reason about your code and talk to other people.
The second best explanation is that patterns are often a sign of shortcomings in the language. OP gives the example of iterators. Another example is the visitor pattern. Or async/yield as a replacement for explicit state machines.
A thing I'd really like to see in a language would be language level support for the command pattern (being able to capture arbitrary blocks of code, lift the execution to an object, and undo/redo it). Or to be able to include the state of an object in the type system - not like Rust does it with typestates, but to be able to say `Child` is a `Person` where `age < 18`, and if the compiler can't prove that the condition always holds, then it will force you to write the precondition checks or check it at runtime.
That’s great, but misses the point. Christopher Alexander’s big ideas involve the people who lives, works, and plays within the architecture. The pattern language was designed for them, so they can participate in the design process of their own living spaces.
The equivalent would be a pattern language that app users themselves can use for their apps. Instead of having the app developers drive design with A/B testing to gain user traction (with a societal risk of dark patterns), the users themselves put things together that would work with how they are doing things.
The implementation of the code would work from there. Something the end-users can change the code themselves.
Smalltalk was designed to allow that level of user participation ... but the legacy we ended up with is OOP and gang of four.
If anything, something like TCL/TK is closer to that vision than what we currently have. (What we currently have: mass lockin of consumers and end-users by a different Gang of Four — Facebook, Amazon, Apple, Google).
Alexander’s keynote to the ‘96 OOPSLA conference goes into detail about his ideas and how it can be applicable to software engineering. He was imploring software engineers not to make the same mistake that architects did with his pattern language ideas ... but we still made the same mistake anyways.
The best explanation I've ever seen for design patterns is that they are workarounds for weaknesses of the programming language. Usually Java and its contemporaries.
Factories, for example. They're essentially just constructors. So why not use the new keyword? Turns out new has limitations:
- Dependency on the constructed type at the ABI level
- Cannot return subtypes of the constructed type
- Special keyword, not orthogonal with the rest of the language
Singletons, for example. They're essentially classes with static methods and state. Why not use these language features instead of coming up with incredibly convoluted ways to ensure only a single instance of an object has been created? Turns out classes have limitations:
- Classes aren't objects
- Classes cannot be passed as parameters
- Classes cannot implement interfaces
The need for all of these patterns simply disappears in a better designed language. In Ruby for example everyone uses factory methods without even realizing it and classes are fully featured objects that can be used in any context.
Interestingly enough, the same phenomenon arises in languages with fewer features. In go, for example, there are no constructors, only functions that return structs. Singletons are just global variables referencing a struct, etc etc.
Singleton’s main feature is not that it is globally accessible, but in that it represents a state that cannot be naturally duplicated. The pattern itself lies in a controlled instantiation, where a method/constructor/factory returns a cached value on a second call. Globals are just that – globals.
Oops. That's not a singleton. That depends on nobody, ever, anywhere in the code creating another one. In contrast, a true singleton can enforce that there is only one, no matter what the callers do.
Globals like a and b are fields of the singleton, not instance of singleton(s). The global space is the singleton (or a juxtaposition of singletons, if we let aside the lack of visibility protection), and global variables and functions are the fields (members) and the methods of the singleton.
You can look at it that way, I suppose, though I consider it to be a fairly odd perspective. But it doesn't help at all with the problem of enforcing that there be only one ThingThereCanBeOnlyOneOf. Therefore globals are not a true solution to the problem that singletons are trying to solve.
Singletons solve several problems with static methods, namely that you can't change their behavior (e.g. do error logging to both the global error log and a per-request log, then at other times do it to a log buffer for testing, and NOT to anywhere else).
At least with a singleton you can create a bunch of "standard configurations" by calling them with a different constructor at startup time. So you can have a test DB during tests, different log targets, read from different filesystem (not the real one, but the one in the testdata/ directory) ...
Better yet is to have a "context" abstraction that you pass down the chain. Issue with that is, every method needs to have a first parameter that is the context ... so it requires some discipline.
Some frameworks (java @#$@#%@# servlet spec for example) make this parameter implicit and then use something akin to exception resolution to get this parameter (so when you do GetContext(), it unwinds the stack to give you the correct context). That makes things very complicated, and is an invisible LOT of state that gets passed down the stack. Still better than singletons or static methods, but good luck figuring out why a context is set to X.
In all cases you need to be very careful to USE the context. DO NOT use database except the one in the context, no caches except the one in the context, no filesystem reading, logging, ... except by redirecting through the context.
I can also get second instance with singleton. In reality singleton doesn't enforce anything. It's a only a convenient way to make global scope in inconvenient languages.
I would partially agree, although I don't know many implementations.
It's a state that cannot be naturally duplicated, alright, a "single source of truth". But lazy instantiation is nothing more than a very important and very common second. The pattern itself lies in preventing public-level instantiation (i.e. in Java it could translate to a class with a private constructor, private instantiation and access to the instance through a class-level/static getter, and also making it a final class).
Not quite - variables are references to objects, there's nothing that restricts global variables themselves to only reference a single _instance_ of an object.
That said, a global singleton (and global state in general) is usually an anti-pattern; having pretty much any code be able to depend on the state makes it very difficult to evaluate the impact of a change.
The question is, "I have some code that wants to make some different kinds of a thing in the same way, then use the different kinds in the same way, being unaware that they are different and not depending on any particular kind. How?" The answer is typically that you can pass a function to that code which accepts some stuff and returns the thing it is concerned with. You may say "Thats an Abstract Factory" but when we write like 4 LoC instead of 3 classes in different files we often don't feel a need to give it a name.
Edit: Also, depending on the circumstances, you can probably just pass the class or its constructor instead of passing a newly written function. That would get you down to ~0 LOC involved in replicating the functionality of this pattern.
I guess if we want to get really abstract, we can say that the Abstract Factory pattern is a shim from a kind of late binding that is implemented in the language ("object orientation" a.k.a. dynamic dispatch on the first argument to a function) to one that is not (late binding of classes, constructors returning null, etc.). This isn't the whole picture though, because sometimes late binding isn't even an important part of what we're getting from the Abstract Factory pattern! For many use cases, we could imagine implementing the function that consumes the Abstract Factory using C++ templates or Zig comptime, and our compiler would generate separate subroutines for each factory type and statically determine which one to use at each call site and we would still be doing the Abstract Factory thing.
Another pattern called the Visitor Pattern is similarly a shim from dynamic dispatch on one argument to dynamic dispatch on two arguments. You just really hope you don't need dynamic dispatch on five arguments one day.
I don't think the issue is "powerful enough". I think it's that something is hard to do cleanly in the language. For instance, you could view monads for sequence and IO as "design patterns" in Haskell, because it's hard to do those things in Haskell in a straightforward manner. This is just the nature of the language. It's not that Haskell isn't "powerful enough".
You can't give people the language to recognize and identify a pattern, and
then forbid them from using that as a tool to reproduce it.
Can you imagine?
"You can talk about patterns as a means of description, but don't consciously wield them as a means of production. Also, do not make statements such as 'the architect used this pattern'. Rather say, 'the pattern spontaneously emerged in the work, facilitated by the architect's intuition'."
First, please note that this is from 2002. Wish you could edit the title.
The last slide in the series notes that the talk gets heavily flamed on. It gets flamed on for good reason, IMHO.
From its intro:
>
Description
The "design patterns" movement in software claims to have been inspired by the works of architect Christopher Alexander. But an examination of Alexander's books reveals that he was actually talking about something much more interesting.
The presentation has two parts: a takedown of the Iterator (which kinda misses the point of iterator, it’s not purely a way to implement for-loops), and then a description of how Alexander had different goals than the GoF in their book.
Ok... the book isn’t Alexander. Though the patterns community was on the path to trying to achieve similar goals, just this happened to be a handbook of patterns that were more recently discovered. Software architecture is not as well-codified a field as physical architecture, needs a century or two to catch up.
The real complaint is that the book is not a “Pattern Language”, or the same as the famous Chris Alexander book. That’s not in the title of this talk. It’s also not really what the speaker spends much time on. Saying the C++ macro system blows goat dick doesn’t advance arguments about the difference between a handbook of patterns and anything else. Inspired by is absolutely true, inspiration has many effects and forms.
However, GoF is also about discovering and communicating the patterns you discover, and contains useful examples. GHJV spend energy describing how the patterns were identified, clarified and named, and they use this language in presenting the examples.
Meanwhile the author of these slides seems to thing it’s the copy side of a copy-paste command, which it definitely is not. There is no one true Iterator, nor Factory, Visitor, Facade, or any other pattern listed.
I don't know why you are getting down voted. For what its worth I appreciate the analysis.
I kind of feel like this post shouldn't exist without the author taking the time to explain his POV better than a few bullet points on a slide. The postscript kind of goes there but its not enough IMO. What we are left with here reduces whatever his point is to a few reductive statements that probably over simplify his arguments and leave the rest of us either nodding emphatically or shaking our heads in disgust because its just generalized enough to confirm any pre-existing bias we already have. In other words this wont change any minds.
I guess the one good thing to come out of reading this is that I'll pick up that "Pattern Language" book and give it a read. Perhaps this post will gain some value in retrospect with that context.
I love how you say "Here's the same guy..." like it was someone other than yourself.
I was going to point out that the beginning of the article says that this was a "five minute long talk" given at YAPC, and did not represent your complete thoughts on the matter.
I agree. I think it was brought up for thought and discussion, and the first comment was strongly critical. If there are other thoughts on it, hope they get shared too.
Alexander's works are wonderfully inspiring to read. I'm sure they can inspire many diverse interpretations useful for creating digital artifacts.
To the curious, note that what the patterns are is not explained in 'A Pattern Language' but instead in the companion book 'Timeless way of Building'. It's quite a philosophical exposition. It talks about evoking 'The quality without a name', that every human has the capacity to feel, but not necessary to name or dissect.
Here's a quote for the curious from 'Timeless way of Building' that I think captures somewhat what the post wishes more software designers thought about in relation to patterns:
(page 236-237, speaking about the specialisation of professions in which people's pattern languages gets lost through disconnection)
"... Of course, even now a town still gets its shape from pattern languages of a sort. The architects and planners and bankers have pattern languages which tell them to build gigantic steel and concrete buildings. The users have a few shattered patterns left in their vocabulary: a sheet of plastic to make a kitchen counter; huge plate glass windows for the living room; wall-to-wall carpet in the bathroom -- and they enthusiastically piece these patches together, whenever they have a free weekend.
But these remnants of our former languages are dead and empty. They are based mainly on the by-products of industry. People use plate glass windows, formica counters, wall-to-wall carpet, because industry makes them available, not because these patterns contain anything essential about life, or how to live it.
The time when a pattern language was a song, in which people could sing the whole of life, is gone. The pattern languages in society are dead. They are ashes and fragments in the people's hands"
I think there's a lot of utility in trying to achieve some conceptual consistency across a large codebase worked on by many people. Most organizations of even 12+ developers wind up with an internal informal "pattern language" that you learn while onboarding, and it can be wildly helpful if that's explicitly acknowledged as an area of knowledge to help new teammates acquire.
To me a lot of the tension comes from the "endless september" nature of software, that over the last 20 years we just keep absorbing more and more new-ish folks who come in with vastly varying levels of formal and informal education.
I'm tempted to describe one mindset as "catalogers" in contrast to other mindsets that might be called "explorers", "consensus builders", "hackers", "do-ers", etc. (not a complete list nor entirely disjoint categories -- i'm a lousy cataloger!)
I think part of this endless Design Patterns discussion is that some, myself included, would like to push back when "design patterns" starts to become "a standard and nearly exhaustive catalog that the whole field uses with uniform meanings."
I think "catalogers" as I'm thinking of them are by nature not quite pioneers, since the fundamental move of cataloging is to describe and categorize what already exists, but might often be settlers, in the sense that a good career move for a cataloger is to be the first to apply a new process to gain insight into new distinctions or categories. In that sense I would see GoF themselves acting as "settlers" in their Design Patterns book, which I tend to view as a catalog project.
However books like "Refactoring", and "Working effectively With Legacy Code" also turn into partial cataloging projects, but those might overlap more with "town planner" in that they're really leveraging some mature technologies and looking for system-level economic savings of readability/changeability/maintainability.
So I guess I'd continue to argue that it's a "mindset" as much as "a type of person"; "Working Effectively With Legacy Code" isn't _only_ a catalog, but there's parts of it that come from a catalog mindset.
Regardless, I hadn't seen the above mapping you linked and I appreciate it!
I think it's a reasonable critique of the concept of Pattern Language as adopted by IT. The interlocking nature of the patterns at various scales, the way that normal folk are expected to use the PL in situ to evoke and evolve design organically from an intrinsic understanding of their own needs and an informed intuition of the potentialities of the space, these are wholly omitted from GoF PL. Not, I think, because of any fault of them themselves, but because the very idea of applying Pattern Language thinking to computer system design was so novel at the time they proposed it.
Certainly CA is a genius and I think we would all benefit from at least skimming the original "Pattern Language". (His latter work, "Nature of Order", is sublime.)
It's worth reading CA's "A City Is Not a Tree" as well:
Each design pattern documents a weakness in the language or omission from the library, such that the pattern cannot be or has not been pulled into the library.
Weaker languages usually get a new feature when the pattern is recognized. Stronger languages get a new library component, if it can be expressed well enough, or sometimes a new feature.
Some languages have ossified, accepting neither new core features nor library components, and code in them is all-over patterns.
Amen! Java and C# are too "stiff" to handle many kinds of changes/expansions that say Smalltalk or Lisp would have no problem with. Lambda's and "annotations" are doing many things that objects should be doing so that special additions or inconsistent parts are not needed to plug the holes.
Make blocks of code just be blocks; and how they relate to other blocks be a library or code configuration instead of a block "type" or language construct because types don't handle combinations of traits very well: they like clean hierarchies to work well. But hierarchies are limiting. It's why RDBMS replaced IMS, for example. The same lessons apply to code blocks: hierarchies are too stiff for non-trivial change management.
The scope profile/ranges and "parent pointers" of each block should either be dynamic or configurable just before compiling[1]: "This block has traits X, Y, Z, etc.". A buffet instead of numbered dishes. The boundaries between "object", "class", "lambda", "function", "annotation", etc. should be blurred and mixable. Don't force hierarchical or stiff taxonomies unless you really have to. We've outgrown trees just as we outgrew IMS. Block "types" are an archaic concept that the future will laugh at like they do to go-to oriented code now.
(I'm currently experimenting with a "meta-language" that has TypeScript-like syntax but lets the libraries define how blocks behave instead of the language itself. You can make your own control structures and block types any way you want via just library changes...if things go to plan. Some say, "why not just use Lisp?", but too many find Lisp hard to read. This meta language thus borrows syntactical elements from the C family. Parameter blocks are visually different from code blocks, for example, giving the eyes more cues.)
[1] Or both. Perhaps have "locked" blocks and unlocked blocks that can change their scope/parent configuration during run-time if given permission to do so. But that's Phase II. Phase I should keep it simple until the idea gets road experience in compiled languages.
> How can you distribute responsibility for design through all levels of a large hierarchy, while still maintaining consistency and harmony of overall design?
This how the author summaries the intent of Christopher Alexander's work. I have not read "A Pattern Language" so it's difficult to say if this is accurate or not. However this is such an important issue in software engineering that I would welcome any ideas to reduce the problem.
I agree when the author that the GoF addressed a lower level problem. However, I'm also disappointed by these slides that provide not hints for a better high-level approach. The GoF patterns form a language for developers speaking to developpers. We also need a language across roles.
His blog post on the topic goes into more detail and examples [1]. I tend to agree with him, especially his conclusion that "Patterns are signs of weakness in programming languages."
Design patterns fill a similar niche as recipes. You have learned the fundamentals, control flow, data structures, algos, etc, but you are t sure how to put that all together.
After learning the fundamentals of cooking, you can start exploring different recipes. Most of them are instructional and assume a base level of knowledge like what golden brown or finely diced means. They let you use your skills to make something physical.
Design patterns fill a similar niche, somewhere between abstract concept and concrete code. What differs is that most recipes can be made without prior dependency. You can make chicken for dinner no matter what you made before. Large software projects aren’t like that. When deciding what to do you have to consider what you and your coworkers made for every previous meal. This makes a recipe much harder to choose, and often ends up as square peg/round hole.
On the flip side most people start with recipes and only after much trial and error so they learn how to cook.
I think the slides are great, I've just learned something new and I got interested on knowing more about Alexander's work. Also, I've got that the point is that we need to take a fresh look at Alexander.
But one thing I never really understood is the criticism on Design Patterns as being workarounds for languages weaknesses. Of course you have languages at different levels of sophistication, and there's nothing wrong on pointing out that pattern X isn't needed on language Y since it already natively provides a proper solution, but what demerit would there be in using the pattern on a language which doesnt provide a good solution by design?
Besides, GOF even speculate that some patterns could eventually become part of future languages, so I dont know, even if patterns can really be taken as "workarounds", it seems to me that it's everything much more about a gradual, natural evolution towards better languages.
I have read
Christopher Alexander’s bibliography and also had this impression that software people got it “wrong“. The patterns on GoF aren’t really at the same level - an “Iterator” is too low-level and not at all the level at which you would be discussing architecture with the end-users, which is the point of C.A. They focused on pattern “reuse” because that’s what the industry and OOP obsessed about - in the end reuse happens at package-level, so the industry missed the mark.
In fact, it surprises me the focus on “A Pattern Language” at all when the “Notes on the Synthesis of Form” is a much relevant book on the topic of gathering requirements, prototyping and designing solutions.
Anyway, I recommend going straight to the source and reading Christopher Alexander’s work as it’s very relevant for anyone designing solutions of any form.
The GoF design patterns are low level, as noted in earlier comments, with respect to the standard of using them to communicate between software designers and software users, but also sufficiently high level to be nontrivial techniques in a certain class of OOP languages (Smalltalk, old C++, Java).
They deserve an explanation, help the programmer to reason about architecture "from the bottom" and explain technical issues concisely, and serve as examples of more general good design principles. They have also proved to be a positive driving force in the evolution of programming languages and libraries.
More "important" design patterns, such as organizing an enterprise application around executing transactions against a database or stipulating whether a soft realtime application like a videogame should lag or skip frames when overloaded, are usually too abstract and complex to give universal advice about.
I think the book "Fundamentals of Software Architecture, an Engineering Approach" (Oreilly) is much closer to what most engineers need today than the GoF book. It covers topics such as layers, pipelines, microkernels, events, microservices, components, and how to put it all together into a coherent design.
GoF was great for it's time and context, but the world has moved on and even mid-level engineers need to be aware of software architecture and how to put it all together.
The way OP talks about what's Alexander's design pattern they look to me more like Domain Driven Design, that is, creating a common vocabulary to be used between developers(architects) and people who will use or needs the software(people who will live at/use the building).
this talk that christopher alexander did a number of years ago is quite interesting https://www.youtube.com/watch?v=98LdFA-_zfA one of the interesting things is that he had really moved on from "patterns" and was looking for something more intrinisic or "atomic" about design. Which actually is a much better guide to designing software.
I didn’t focus on the iterators at all and still didn’t get the point. What I got so far; an architect wrote a book with some definitions that allows people discuss a solution. Then the author says we should take that seriously. Which is fine, but how exactly? The author spends a lot of time on explaining why (for his POV) software design patterns are wrong, but no example of how to use what the book says in software. What am I missing?
How about: Design Patterns are like start- and end-games in Chess. They only apply in specific yet commonly recurring situations. You study them to be able to apply them when the situation seems ripe for their application
This is a useful post. The key idea I get from it is to mind the difference between dictating a solution and creating a vocabulary and set of models for discussing solutions.
Don't let vocabulary or lack of evidence distract you from the main point. Lack of either doesn't invalidate the argument it just invalidates your bias.
The burden remains on you to validate the argument and ignore your biases as obviously this author and the people who voted him up have their reasons for believing in what they believe.
The author claims that the C++ type system blows goats dick, the burden is on them to actually prove their point besides using middle school recess vocabulary.
> The author claims that the C++ type system blows goats dick
No, he doesn't. He claims that the Macro system does. And he's right, C macros are full of well documented pitfalls [1][2], especially when compared to other languages. This is not really a controversial claim, btw. At this point this is common knowledge. "Blows goats dick" is letting it off easy, even. It only implies low quality, or difficult to use. C Macros however can be dangerous, unsecure and misleading. Also, this is an informal talk. Sure, you might take issue with his language, but I would expect someone taking issue with the claim to at least know about the general consensus on the topic.
Nah you're right. No burden on you. I'm just saying logically, if he makes that claim and you know he's not an idiot and a lot of people vote him up, then there must be a compelling reason for why he made the claim.
The reasoning has the potential to change the way you think about his claim or it has the potential to be completely wrong. But the context of the situation makes it so that you cannot ignore the potential.
I found the presentation quite useful, and have a few thoughts on the points I found.
First, my thoughts on Design Patterns as defined by the GoF.
As recurring concepts which have been identified, named, and allow for higher-level discussion and solving of software architecture and design problems (I think this view of mine might be a bit short-sighted), they are great tools and vocabulary.
However, they are known to reflect shortcomings, specially in object-oriented languages as opposed to functional ones (haven't read much about them, and I don't know much about functional programming and haven't yet read my copy of SICP, so I probably lack some fundamentals on the subject).
I like the point about design patterns not being "patterny" enough, I think that was one point in the presentation.
Although design patterns sure aren't too be taken simply as implementation recipes (is it too far a stretch if I think of them as a kind of "framework" or "frameworks"? Not sure about the inversion of control aspect, though) and there is no fixed Observer, or name-your-pattern implementation, it certainly would be more useful if they could be implemented only once instead of repeatedly for each new project.
This is not "human", and that sounds fair enough to me.
Some are actually reusable, such as certain library implementations or language constructs (I'm thinking of Java's foreach, I'm not familiar with Perl).
I think that depends a lot on what constructs or building blocks the language provides. The first few pages of SICP make such a point about powerful languages.
So it would be great if design patterns could be provided and reasoned upon as powerful language constructs (i.e. which are provided by the syntax). The higher level we can reason upon and solve problems, the better.
So many things are patterns beyond the GoF ones. Paradigms, for one thing. Variables.
The other point I found is about how Christopher Alexander wanted the clients of the building to reason upon architectural issues at various levels and how this also applies to software development. This could map either to the developers or to the end-users in my opinion (not to mention the hardware designers). Either way, I think this emphasizes the importance/need of higher-level constructs (such as the concept of information hiding applied to higher-level building blocks) than we usually reason upon when developing software.
These were the useful points I could find.
I'm afraid, though, that I don't have enough conceptual building blocks myself to reason further upon it.
Finally, sorry about the lots of "reasoning upon".
>A design pattern systematically names, motivates, and explains a general design that addresses a recurring design problem in object-oriented systems. It describes the problem, the solution, when to apply the solution, and its consequences. It also gives implementation hints and examples. The solution is a general arrangement of objects and classes that solve the problem. The solution is customized and implemented to solve the problem in a particular context.
Interesting to note that the person defines a pattern as something exclusive to using Objects and classes or in other words OOP. So something like lenses or functors or programming techniques defined outside of OOP are not patterns.
When I talk to people they often define design patterns as a common language for various methods that are common to programming and not exclusive to OOP. Doesn't english and vocabulary fill this space? You don't find carpentry workers referring to domain specific vocabulary as design patterns. Why don't FP practitioners or mathematicians call their techniques "patterns"?
This may piss some people off and get me a load of downvotes, but honestly IMO I find design patterns to be just snobbery. Instead of saying someone is iterating through a list they say that someone is using the iterator pattern. It's really just prefixing the word "pattern" onto some vocabulary. I used the number pattern on the variable pattern and the addition pattern to get the sum of two numbers.
I would've just called the book "Programming Tricks for OOP" rather then "Design Patterns."
It feels like arguing about colors from the whole spectrum of the rainbow without saying which color we're arguing about.
The point of patterns is to recognise things that reoccur all the time, ie. DFS is a pattern, FIFO queue as well, so stack, parser combinator, microservice, optimistic locking, proxy, demux etc.
The whole point it to use common volabulary where you can drop this "pattern" suffix when discussing things.
It can be anything, GoF described an idea and couple of patterns in OO context, there are many other books "Analysis Patterns", "Enterprise Integration Patterns", "Patterns of Enterprise Application Architecture" etc.
> It feels like arguing about colors from the whole spectrum of the rainbow without saying which color we're arguing about.
Arguing about a rainbow or arguing about a color in the rainbow doesn't effect the validity of an argument, I'm not sure your analogy makes any fundamental sense here.
>The whole point it to use common vocabulary where you can drop this "pattern" suffix when discussing things.
Isn't this the purpose of the English language? The "Design Pattern" concept is a redundant concept existing recursively in English. English already provides a "common vocabulary" for "discussing things."
What does design patterns provide on top of that? Only additional complexity and redundancy.
That's why basically all fields outside of programming don't really use the word "design pattern" because it's not necessary. It's a bit of snobbish for a pilot to call a flight technique a "design pattern."
>It can be anything,
And that's why it's pointless. There are even design patterns in poetry if you follow this line of logic. The English language is pretty much the "language" designed to be "anything." For a concept within "English" to be useful it must focus on a smaller subset of "anything."
Rainbow analogy meant to mean that often arguments a) focus on narrow aspects and b) don't explicitly define context. Excel patterns will be different from patterns in x86 assembly or high level software architecture.
Sometimes patters are prose about arrangement, sometimes template can be provided and in some cases even fully functional, generic code can be provided.
I don't see anything wrong with calling them "design patterns", software is about "designing" systems and "pattern" reflects the fact that they re-occur, can be reused, can be applied to similar problems etc.
The value is in recognising similar structures, communicating them, reusing solutions to already thought through problems etc.
Poorly designed code can be recognised straight away with ad-hoc, incoherent spaghetti. On the other side there are many poorly applied "pattern" implementations with idiotic verbosity that should be called out as "anti-patterns" instead (just mere change of the language is enough to move a pattern to anti-pattern).
Just because it can describe about anything doesn't make it pointless, just like "best practices" section can be about anything, it doesn't mean it makes it pointless.
I don't think you understand my point. Programming techniques and giving names to these techniques is not pointless. What is pointless is pretentiously inflating these techniques and placing them into a pseudo academic field and calling it "design patterns."
>The value is in recognising similar structures, communicating them, reusing solutions to already thought through problems etc.
The English language already reuses concepts. You drive cars. You do not call it the "car driving pattern" and make is part of the concept of "design patterns" This is the pointlessness I am referring to.
>Anti-patterns are very useful concept as well.
Yeah in common English you call it "Bad techniques" or "ineffective methods". Everyone is already 100% aware of the concept of a technique that isn't "good" you don't need to teach people this concept. My argument here is that the name "anti-pattern" is pure snobbery. It's like calling standing still "anti-movement."
No new concept was introduced by the word "anti-pattern." Anti-pattern refers to a very simple concept that every single human understands. The pretentiousness is in the word and inflates the perception of this concept to the point where someone like you thinks "anti-pattern" is a completely new mind blowing concept (It's not).
It feels more like you had to deal with some idiot abusing word "pattern" than anything else; "pattern", "method", "solution" is "potato potato", what is important is recognising similarities, naming higher level concepts for good communication and implementing systems organised around sound abstractions as opposed to adhoc, shallow, not thought through mess holding on rolls of scotch tape.
> Isn't this what the English language is for? Doesn't every single person on the face of the earth recognize all of these concepts and deploy all of these concepts using the English language on fields more numerous than computer science alone?
You are welcome to explain the Abstract Factory every time you talk about it.
I prefer to just refer to the well known name of the pattern.
> What does design patterns provide on top of that? Only additional complexity and redundancy.
understanding each other would be impossible if we just said, e.g. strategy or command.
"we use a strategy" can mean a ton of stuff in the context of a chat between developers in a company. "we use the strategy pattern" will be clear to everyone.
Change the name strategy to something more clear. Kind of pretentious to use a common word "strategy" to describe a specific technique as if it's the most strategic pattern ever.
It's like if someone came up with the "Logic pattern" or "Intelligence pattern."
> Change the name strategy to something more clear. Kind of pretentious to use a common word "strategy" to describe a specific technique as if it's the most strategic pattern ever.
It really makes sense though. I sometimes gave OOP classes to beginner students by having them discover the patterns on their own. Not only they manage to do that easily most of the time, but some of them also manage to give them the correct name, without any prior exposure to the GoF book.
Design patterns aren't recipes, they're common applications of techniques. The use of gelatinized starch as a thickener for sauces (i.e. a roux) could be considered a "cooking pattern".
Every variable in a cooking recipe can be substituted and modified making a recipe a technique that is applicable to different sets of materials and conditions.
Whoa, this is not ok. Please don't post like this. HN is for curious, respectful conversation—if your curiosity or respect levels drop below basic minima, please don't post until they recover. Escalating into personal attack (as you did downthread: https://news.ycombinator.com/item?id=26382222) will get you banned here, so please don't do that either.
> This may piss some people off and get me a load of downvotes, but honestly IMO I find design patterns to be just snobbery
100%. I recently was interviewing so I decided to brush up on some design pattern terminology because plenty of job postings reference them and I didn't study them in school.
I was blown away by how much of it's just complex-sounding terms for simple concepts.
I was also surprised how poorly defined they really are.
Also note that school generally doesn't teach it because these patterns don't have any formal basis in theory. It's the complex vocabulary that gives these things more academic weight than they actually have. "Tricks of the trade" doesn't sound as rigorous as "Design Patterns" but really it's the same thing.
to me, "hip roof framing" or "trench shoring" definitely sounds like "applying a visitor" or "implementing an abstract factory" would sound to a non-software-engineer carpenter.
Yeah and a technique is part of the "English" language. Techniques exist everywhere.
But in computer science they had to basically make the same concept sound more snobbish. These aren't programming techniques, they are "design patterns."
I agree with you and the TFA. I also think that naming the book "Design Patterns" and calling the techniques "Patterns" is unfortunate and misleading.
But I think calling them like that is what made the book as famous and as is it. If the book were called "OOP Programming Techniques" it wouldn't have the same popularity. Of course that doesn't make it right.
As a book it has served its purpose at the time, but by portraying what are basically "band aids" to limited programming languages (Norvig 1996) as foundational CS knowledge, it ossified the development of OOP and CS itself by a few years IMO.
I share your distaste for cargo cult programming, but ... iterating over a list can be done in multiple ways, and doesn't necessarily mean one is using the iterator pattern. Using the jargon "iterator" to refer to an object or closure that tracks the state of iteration has benefit in making conversation more concise.
The iterator pattern is the use of an object or closure to encapsulate the state of the iteration. This is distinct from using a loop induction variable in the same scope as the loop block itself. In a language like C, which doesn't provide iterators by default, it seems reasonable to call that a design pattern.
It seems more reasonable to say you're iterating through a collection.
It also seems more reasonable to just leave it as a programming technique rather then give it artificial weight and call it some bloated unnecessary academic term "design pattern"
Ok, call it the iterator technique, but there's a difference between using the iterator technique and iterating, which you seem to be refusing to acknowledge.
No actually I'm not completely grasping your argument. You described iteration earlier but I don't see any distinction with any definition of iteration I know of.
I'm guessing your talking about how iteration is implemented versus the action of iteration. Both are one in the same.
Using a loop induction variable is a form of iteration over the elements of a sequence, but it is not using an iterator (technique, pattern, or whatever you want to call it).
Heck, originally, looping was performed by physically looping your instruction tape, and a break was pausing the machine to physically break the tape. Talk about a fragile design pattern!
The implementation matters. That's why people suggest using the iterator technique. It's not the best strategy for all cases, but it's generally better practice.
The index of a variable functions as an iterator for the iterator pattern. It still applies. There's not distinction here. But my point is also more general it doesn't apply to just iterators.
Scope matters. The purpose of the iterator is to encapsulate the state. An induction variable is not an iterator. A physical loop of tape is not an iterator. I'm starting to doubt your general point, because the specific isn't holding.
Take a look at the Wikipedia page for iterators, under the heading "contrasting with indexing". It's not explained super-well, but it covers a few topics.
If you say you are iterating through a collection using a while loop and not an iterator, then you are confusing people by using the wrong word for things.
Design patterns is a formalism behind common patterns in software, and part of that formalism is that they are named.
Obviously you don't need all that formalism every time you talk about patterns, the same way you don't talk about the laws of arithmetic every time you do math.
Exactly math doesn’t call informal but repeatable techniques “design patterns,” and publish a book about it. why should programmers make a misguided claim that these same techniques are also formal and give it a pretentious name.
Design patterns is a unique phenomenon in programming. No other field is pretentious enough to refer to domain specific vocabulary as design patterns.
Yes, and no. English doesn't by default fill the space of words that are shorthands for domain specific ideas. The practitioners coin the terms.
> You don't find carpentry workers referring to domain specific vocabulary as design patterns.
Every field has its conventions, shorthands, patterns, etc. They might not call them design patterns. Lawyers, for example, have tons and tons of terms that are shorthand for complex concepts, and you wouldn't understand them without first studying them, even if they are strictly made of otherwise mundane English words. For example, "strict scrutiny", or "reasonable person".
>English doesn't by default fill the space of words that are shorthands for domain specific ideas.
That was a rhetorical question. I beg to differ. English does fill the space of all kinds of of domain specific areas. Practitioners may invent new vocabulary to use within the English language but in the end they are still using English.
In fact even when you talk about "Design patterns" You are still using "English" it's inescapable. I'm saying the extra layer of "design patterns" as a "field" is not necessary. No other "domain" is snobbish enough to call their techniques "patterns" and group them as "design patterns" and fill the field with all this jargon like "strategy pattern." It's just programming techniques, carpentry techniques and the like.
I agree with 99% of what you said - I think a lot of simpler patterns aren't actually "patterns" in the first place, iterator probably being the best example. However, for things like factories and things more complicated than that, it is helpful to have a lot of context come along with just a word or two. If someone says "facade" or "memento" you know exactly what they mean.
Sure call it an iterator, call it facade. Naming things for the purpose of abstracting away complexity is one of the foundational functions of the English language.
But there's no need to group what is essentially just English Vocabulary into another sub category of "language" prefixed with "design" and then post-fix all internal concepts with "pattern."
But both those things are Monads. They follow the Monad laws, the conform to a certain Monad interface, they both have bind and return, they behave like Monads.
To me the problem with using "pattern" is that it suggests a relationship when there's none, other than all of them being techniques that were presented in the same book.
Prematurely naming them also prevented other people from finding better names. For example, other techniques that are in the same idea-space, such as "Inversion of Control" and "Dependency Injection" don't need the "pattern" suffix, for example, but are still understandable.
Naming stuff is ok. I understand this. It's done in every field.
But calling the "naming of things" a "design pattern" is pretentious. Nobody calls Monads the "Monad pattern" and categorizes it as a sub field of "design patterns."
It's just like how we abstract the concept of getting into a car and commanding the car under the word "driving." That's fine. What's wrong is if We called it the "driving pattern" and place it an area of study within the automobile field called "design patterns."
Imagine if some expert race driver publishes a driving book called "Design patterns" then with an analogy relates it to architecture. Why not just call the book "Driving techniques" and eschew the useless analogy?
I'll tell you why the GoF did this. Because "Design patterns" sounds more academic, and the catharsis of realizing the analogy between architecture and programming techniques inflates the perception of what these concepts actually are. In the end these are just programming tricks or techniques.
FP programmers call their patterns Typeclass Laws.
Mathematicians aren't building/designing things all day long so they don't need this word.
"A pattern language is an organized and coherent set of patterns, each of which describes a problem and the core of a solution that can be used in many ways within a specific field of expertise. The term was coined by architect Christopher Alexander and popularized by his 1977 book A Pattern Language." (Wikipedia on Pattern Language).
>Mathematicians aren't building/designing things all day long so they don't need this word.
Not true, they build proofs. Within proofs there are many many common techniques, aka "patterns."
Either way you seem to imply that "patterns" are for people who "build" things, which isn't emphasized in your definition below:
>"A pattern language is an organized and coherent set of patterns, each of which describes a problem and the core of a solution that can be used in many ways within a specific field of expertise. The term was coined by architect Christopher Alexander and popularized by his 1977 book A Pattern Language."
The problem with the above definition is that English vocabulary already communicates what a pattern does perfectly fine. What is the point coming up with an over complex name and postfixing all of these things with "pattern?" It's basically a redundant concept.
In fact, my communication with you at this very moment is employing many many common patterns. Check the pattern in the previous sentence "many many." I call it the double emphasis pattern and I've used that pattern twice in this reply. I'll write more about it in my book on Design patterns for English communication.
I think the simplest response I can give to this is the "above defition" is of a pattern language, not a pattern.
A pattern language is an organized and coherent set of patterns. They are developed holistically to work in relation with each other. They're designed to be combined together - as sequences, in parallel, as contrasts - and also to be as "platform-agnostic" as possible.
For example, Alexander's book helpfully includes a ton of points on how to combine the various patterns in the book, and a healthy "see also:" section to get alternative ideas or just areas of overlap between them all.
And the patterns in the book are about the physical, environmental, and social needs of humans (the problems) and how they can be met trough architecture and infrastructure.
It's very distinct from just "a list of patterns." They're always described in service to the whole, in relation to the others.
For the English language, I would say Aristotle's Rhetoric is closest in spirit; whereas Elements of Style is clearly more a "list of patterns"
Other "pattern language"-style books I can think of are The Prince by Machiavelli; Capital by Marx; 22 Immutable Laws of Marketing by Ries and Trout; Diffusion of Innovations by Rogers; and High Output Management by Andrew Grove.
I would also say the original C2 Wiki comes closest to creating a "bottoms-up" pattern language. Here's the entry on A Pattern Language - https://wiki.c2.com/?PatternLanguage
But these books aren't explicitly set up as pattern language books - nor are many others. Very few books (not even the GoF) are put together so well and as comprehensively as A Pattern Language. It's truly a masterpiece.
I think that's where your bias lies. If you think a book is a masterpiece no amount of evidence can flip that bias.
You post basically declares every scientific or academic or professional field as "pattern languages."
Then you conclude to say.that there are books much more well put together then the gof book. I agree, like pretty much every axiomatic math book that proves each theorem starting from base axioms is more elegantly put together than GoF.
And none of these books have the pretentiousness to call what they're doing a "pattern language." The concept is unecessary and is only used by books that are actually very informal. The Gof book is essentially just "oop programming tricks" retitled to "design patterns" to sound more academic when in fact its so far from academia, most schools don't teach it as part of foundational computer science.
Also all the books you defined are informal and opinionated. Especially capital by marx. None of those books come close to the rigor of "pattern languages" established by even a basic math book on number theory.
Design patterns appear in languages without enough syntax sugar.
But having too much syntax sugar can be a problem, too. At least, design patterns translate between languages/systems, it's a common language. Syntax sugar isn't.
The second best explanation is that patterns are often a sign of shortcomings in the language. OP gives the example of iterators. Another example is the visitor pattern. Or async/yield as a replacement for explicit state machines.
A thing I'd really like to see in a language would be language level support for the command pattern (being able to capture arbitrary blocks of code, lift the execution to an object, and undo/redo it). Or to be able to include the state of an object in the type system - not like Rust does it with typestates, but to be able to say `Child` is a `Person` where `age < 18`, and if the compiler can't prove that the condition always holds, then it will force you to write the precondition checks or check it at runtime.