Hey guys - Addy (author of this mini-book here). Although the current edition is very much targeted at beginners, I'm working on a significantly more detailed version this summer which will also be released for free.
To those who have mentioned some patterns are indeed better suited to 'classical' programming languages, I completely agree with you - the reason I've included a mention of them is so that developers who may not have read the book by GoF get a little historic exposure to why those patterns were defined and where they fit in.
There will be a lot more JavaScript-centric content in the next version with a little less focus on the traditional patterns.
Could you link up every item in the table of contents and have more cross links in the text. I like reading things like this on my kindle (using the Readability chrome extension) and anything that makes it easier to navigate would be appreciated.
The idea that removing duplication is a design pattern (the "DRY Pattern") seems silly to me. Why not the "Function Pattern"? How about the "Line of Code Pattern"? That one sure pops up a lot.
The trouble with design patterns is that they're at the wrong level of abstraction. They're fine-grained enough to be described in a few pages and meaty enough to make the reader feel they've really learned something. But they're too coarse-grained and rigid to work the promised way, which is as primitives for software problem-solving. Treating these technical blobs as primitives leads to no end of trouble. People naively inline them into their programs because they have been told this is how it is done -- the OP says they are "proven solutions" (to what?) that can be "easily re-used" (how? ever notice they never show you that?) -- and the effect is like releasing a foreign species into an ecosystem. You end up doing the worst thing you can do to code, which is take it further away from the problem it is trying to solve. The gap between abstraction that precisely fits the problem and abstraction that sort of fits the problem is massive: it is the whole game. Out of that gap, complexity grows exponentially.
Patternistas say, "But they're not supposed to be inlined naively. They're supposed to be adapted to the problem." But if you're already good at that, you don't need patterns. The point of patterns is to be a body of knowledge about how to make programs. If that's true, patterns should make naive programmers better. If their effect is to make naive programs worse, then they aren't really a body of knowledge at all.
Mathematics, like software, is filled with recurring patterns and tricks that pop up in diverse contexts. Why doesn't math have "design patterns"? Because math culture understands that the only way to get good at math is to read theorems and solve problems. If a trick you've seen before is useful, use it; if not, drop it. The focus is always on the problem. Over time, you notice patterns, sure. But "patterns" are not the basis of teaching math, classical results are. I believe that software is like math this way. But the mathematicians have a luxury we do not: they don't need to grow their community by orders of magnitude in order to satisfy industrial demand. If you like math and have aptitude for it, the door is open; if not, see ya. Software, on the other hand, requires a massive work force, which raises the question of how to train it. Design patterns are a failed attempt to address that problem, which may not be solvable. Unfortunately, they confuse and delay the development of some good programmers in the process.
I agree with your first part entirely. As for the comments about math I look at it this way. Math can usefully be described as a nothing but a bunch of design patterns, discovered and built in just the way you say. Look at the way addition and multiplication morph into a ring, once you learn a little math. Dynamic programming algorithms then work for any ring.
The frustrating thing for programmers is that these patterns don't often seem to be directly useful in computer science. Oops, I mean programming.
I think that is changing thanks to functional languages. One of the most mind blowing CS lessons I learned in the past few years was how to calculate the derivative of a data structure and what to use it for, using plain old calculus rules. Now that might seems useless or crazy if you haven't studied algebraic data types. But these are readily seen to be useful once you learn a little math (and Haskell). In a few years I believe that FP will be credited for the wholesale import of mathematical design patterns into everyday programming. The Haskell and related communities are still small enough that they have only scratched the surface.
> Math can usefully be described as a nothing but a bunch of design patterns, discovered and built in just the way you say.
Well, kinda-sorta. It depends on how you define a design pattern, and how you generalize that definition to mathematics. The way that I define design patterns, I would disagree.
I define design patterns as "an abstracted, re-usable piece of functionality that cannot be made into a library." I think that the non-libraribility is the defining feature of design patterns: it's why you have to learn to implement them, instead of just linking to them like most other forms of re-usable functionality[1]. As soon as you can figure out how to factor that functionality into a library (or template or inheritable class or interface or whatever), it's no longer a design pattern.
When I look at mathematics, I would consider that to be mostly a collection of libraries rather than design patterns. Theorems, obviously, are more like libraries because you can simply plug in the antecedents and get out the sequents without looking at the proof. There are also things like design patterns, techniques that you can apply in related domains. However, mathematicians have a pathological urge to turn these techniques into theorems by proving properties about what they will do and when they can be applied. The result is that math tends to have many libraries but few surviving design patterns at any point.
[1] Note that this definition is language-dependent. It also dovetails somewhat with the "design patterns are evidence of an underpowered language" line of thought, but is distinct because it deals with extensible functionality rather than built-in functionality.
Besides many theorems math does have design patterns; Tim Gowers in his essay "The two cultures in mathematics" argues that part of the reason mathematicians in other fields sometimes think there's not much to combinatorics is that they ate used to having widely applicable insights implemented as theorems whereas combinatorics tends to have them as design patterns.
Your definition of a design pattern is more precise than mine for sure. In FP its not "an abstracted, re-usable piece of functionality" unless it can be made into a library, as far as I know.
But it seems to me that FP forces you to look at programming in terms of what you are doing to transform data. In that case I can't see why having enough libraries won't do the job.
The equivalent to a mathematical result in programming is not a design pattern, it's a program, algorithm, or data structure. Design patterns a la GoF (and the OP) are pseudo-formalisms. They're not well-defined enough to be comparable to math; not even close.
Derivative of a data structure? I never heard of that before, though I'm familiar with derivatives in calculus. How do you calculate the derivative of a data structure? I'm guessing that you start by eliminating values that are constant with respect to some variable, but I'm not sure how you'd reduce the rest. How common is it to have values in a data structure that are non-linearly related to a variable?
You are one the wrong track. You'll be surprised. Look up algebraic data structures and zippers. The partial derivative of an algebraic data structure is its zipper.
Very true, there seems to be a cargo-cult mentality that the mere presence of "design patterns" improves the quality of your code automatically.
As I see it, the main benefit of design patterns is that they give developers a common vocabulary for different types of object composition. This can save time when reading code if an object's name or comments reference the design pattern(s) used.
> The point of patterns is to be a body of knowledge about how to make programs.
No, the point of patterns is to standardize the language about what everyone already does so programmers can actually discuss what they do with each other in a meaningful way.
People always say this, but it's not true in practice. Any of these terms that are meaningful can easily be defined in a simple phrase. "Singleton" is an object with only one instance. "Observer" is code that gets called when something changes. (Actually, I think most people who haven't been influenced by GoF say "publish/subscribe" or "handle an event".) Moreover, this is a problem in search of a solution. I don't see programmers having difficulty communicating with each other because of a lack of standard technical vocabulary. If there isn't a term for something, you just make one and say what you mean by it. That's what we've always done and it's what programmers not under the influence of "design patterns" always still do.
No, design patterns come with considerably greater baggage than that. They invariably come with template code and a lot of language about when and how to apply the pattern. They're not trying to be a glossary, but a cookbook. Basically, the failed OO mantra of "reuse" took refuge at the meta level where it's impossible to disprove.
> People always say this, but it's not true in practice.
It is true in practice, try talking to programmers who don't know about design patterns and you'll find communication about architecture difficult. Maybe you haven't met enough of these programmers, but there's a shit ton of them in the corporate world.
> If there isn't a term for something, you just make one and say what you mean by it. That's what we've always done and it's what programmers not under the influence of "design patterns" always still do.
Yes, and it doesn't work well when you don't have a common vocabulary; you spend all your time trying to grok their little custom names for everything.
Everything else you said is what happens when people mis-apply patterns and think they're code templates, they're not and were never intended to be.
This is why I think a book like "Refactoring" is actually more important than the GoF book, because it beats "Design Patterns" at its own game. When someone reads about software design patterns they learn a lot of cool things but ultimately they are still left in a muddle, and as often as not they don't have the slightest clue when and where to use, or not use, which patterns. Worse yet, they can't even use the concepts to talk about real software since so much real software uses undocumented patterns.
I think much of this is because "Design Patterns" itself is too raw and too language-centric and too sterile. It's too much of a catalog and not enough advice on why you'd want to use a design pattern and where, and the tradeoffs of doing so.
In contrast, "Refactoring" builds up a robust, pragmatic, and practical set of models and terminology for software design and construction, and for making changes to such. It also provides a lot of good rules of thumb and general guidelines for when to know whether a particular refactoring is worthwhile or not. It's very much the level of glue that is missing between the airy almost architecture astronaut level of patterns and the muddy, ugly trenches where real code gets written and re-written.
On the whole, someone who's read both "Refactoring" and the GoF patterns book is much more likely to have stepped up their level of coding and increased the sophistication of their models and vocabulary for talking about, reasoning about, designing, and constructing code, whereas someone who has only read about patterns is as likely to be a danger to the codebase as a help.
This is pretty fantastic. The author is not presenting a lot of new information, but he is bringing together a ton of information from great sources, and he presents the patterns in a clear and concise way. This is an essential read for any developer that is trying to get into javascript in a more serious way, but they kind of have the feeling that they're in the "deep end".
Theres really no point in using the classical singleton pattern in JS since most applications have a top-level namespace object. The module pattern is actually a superior singleton pattern as you have written it.
SingletonTest.getInstance() assumes SingletonTest is globally visible (or at least in the scope you care about), so therefore to call some method you do SingletonTest.getInstance().someMethod(). This is polluting the global namespace. Instead you can use the module pattern and use a global top-level namespace object: App.moduleObject.someMethod(). This is cleaner, requires less code and won't pollute the global namespace.
just say no to classical patterns in js
I really think the module pattern is an anti-pattern. The positive benefits of public/private methods, are more than offset by the performance penalty of having each instance of the an object have it's own methods, rather than sharing through the prototype.
My understanding (and the article reflects this) is that the "module pattern" generally refers to a function that is executed immediately after definition; ie: var module = (function() { ... })().
I'm guessing you're referring to Crockford's pattern (IIRC he calls it a "functional constructor" in JS:tGP), which is generally the same, but the function is instead executed when an object is instantiated with it.
It's a small distinction, but your drawbacks don't apply to the module pattern as I understand it, since the function is only executed once.
thats really application specific. In fact JS engines are so fast and browsers have so much memory nowadays that in the vast majority of JS applications, this is a non-issue.
Lately, instead of using the module pattern by invoking a function immediately and returning an object, I've taken to just using an anonymous function/constructor with the new operator -- properties defined under "this" will be public and any other variables will be private (obviously). I prefer it over the typical "module pattern" because I believe it looks just a tad bit cleaner compared to the explicit object definition.
This is really awesome, even though i never bothered to follow any official design pattern yet still survived, and my code was efficient and easy to read. Memorizing 13 design patterns looks like an over kill unless you are developing the next OS and working in a 5000 developers team.
To those who have mentioned some patterns are indeed better suited to 'classical' programming languages, I completely agree with you - the reason I've included a mention of them is so that developers who may not have read the book by GoF get a little historic exposure to why those patterns were defined and where they fit in.
There will be a lot more JavaScript-centric content in the next version with a little less focus on the traditional patterns.