A pattern is a reusable solution that can be applied to commonly occurring problems in software design - in our case - in writing JavaScript web applications. Another way of looking at patterns are as templates for how we solve problems - ones which can be used in quite a few different situations.
So, why is it important to understand patterns and be familiar with them? Design patterns have three main benefits:
1. Patterns are proven solutions: They provide solid approaches to solving issues in software development using proven techniques that reflect the experience and insights the developers that helped define them bring to the pattern.
2. Patterns can be easily reused: A pattern usually reflects an out of the box solution that can be adapted to suit our own needs. This feature makes them quite robust.
3. Patterns can be expressive: When we look at a pattern there's generally a set structure and vocabulary to the solution presented that can help express rather large solutions quite elegantly.
Patterns are not an exact solution. It's important that we remember the role of a pattern is merely to provide us with a solution scheme. Patterns don't solve all design problems nor do they replace good software designers, however, they do support them. Next we'll take a look at some of the other advantages patterns have to offer.
• Reusing patterns assists in preventing minor issues that can cause major problems in the application development process. What this means is when code is built on proven patterns, we can afford to spend less time worrying about the structure of our code and more time focusing on the quality of our overall solution. This is because patterns can encourage us to code in a more structured and organized fashion avoiding the need to refactor it for cleanliness purposes in the future.
• Patterns can provide generalized solutions which are documented in a fashion that doesn't require them to be tied to a specific problem. This generalized approach means that regardless of the application (and in many cases the programming language) we are working with, design patterns can be applied to improve the structure of our code.
• Certain patterns can actually decrease the overall file-size footprint of our code by avoiding repetition. By encouraging developers to look more closely at their solutions for areas where instant reductions in repetition can be made, e.g. reducing the number of functions performing similar processes in favor of a single generalized function, the overall size of our codebase can be decreased. This is also known as making code more DRY.
• Patterns add to a developer's vocabulary, which makes communication faster.
• Patterns that are frequently used can be improved over time by harnessing the collective experiences other developers using those patterns contribute back to the design pattern community. In some cases this leads to the creation of entirely new design patterns whilst in others it can lead to the provision of improved guidelines on how specific patterns can be best used. This can ensure that pattern-based solutions continue to become more robust than ad-hoc solutions may be.
We already use patterns everyday
To understand how useful patterns can be, let's review a very simple element selection problem that the jQuery library solves for us.
Imagine that we have a script where for each DOM element found on a page with class "foo" we wish to increment a counter. What's the most efficient way to query for this collection of elements? Well, there are a few different ways this problem could be tackled:
1. Select all of the elements in the page and then store references to them. Next, filter this collection and use regular expressions (or another means) to only store those with the class "foo".
2. Use a modern native browser feature such as querySelectorAll() to select all of the elements with the class "foo".
3. Use a native feature such as getElementsByClassName() to similarly get back the desired collection.
So, which of these options is the fastest? It's actually option 3. by a factor of 8-10 times the alternatives. In a real-world application however, 3. will not work in versions of Internet Explorer below 9 and thus it's necessary to use 1. where both 2. and 3. aren't supported.
Developers using jQuery don't have to worry about this problem however, as it's luckily abstracted away for us using the Facade pattern. As we'll review in more detail later, this pattern provides a simple set of abstracted interfaces (e.g $el.css(), $el.animate()) to several more complex underlying bodies of code. As we've seen, this means less time having to be concerned about implementation level details.
Behind the scenes, the library simply opts for the most optimal approach to selecting elements depending on what our current browser supports and we just consume the abstraction layer.
We're probably all also familiar with jQuery's $("selector"). This is significantly more easy to use for selecting HTML elements on a page versus having to manually opt for getElementById(), getElementsByClassName(), getElementsByTagName() and so on.
Although we know that querySelectorAll() attempts to solve this problem, compare the effort involved in using jQuery's Facade interfaces vs. selecting the most optimal selection paths ourselves. There's no contest! Abstractions using patterns can offer real-world value.
"Pattern"-ity Testing, Proto-Patterns and The Rule Of Three
Remember that not every algorithm, best practice or solution represents what might be considered a complete pattern. There may be a few key ingredients here that are missing and the pattern community is generally wary of something claiming to be one unless it has been heavily vetted. Even if something is presented to us which appears to meet the criteria for a pattern, it should not be considered one until it has undergone suitable periods of scrutiny and testing by others.
Looking back upon the work by Alexander once more, he claims that a pattern should both be a process and a "thing". This definition is obtuse on purpose as he follows by saying that it is the process which should create the "thing". This is a reason why patterns generally focus on addressing a visually identifiable structure i.e we should be able to visually depict (or draw) a picture representing the structure that placing the pattern into practice results in.
In studying design patterns, it's not irregular to come across the term "proto-pattern". What is this? Well, a pattern that has not yet been known to pass the "pattern"-ity tests is usually referred to as a proto-pattern. Proto-patterns may result from the work of someone that has established a particular solution that is worthy of sharing with the community, but may not have yet had the opportunity to have been vetted heavily due to its very young age.
Alternatively, the individual(s) sharing the pattern may not have the time or interest of going through the "pattern"-ity process and might release a short description of their proto-pattern instead. Brief descriptions or snippets of this type of pattern are known as patlets.
The work involved in fully documenting a qualified pattern can be quite daunting. Looking back at some of the earliest work in the field of design patterns, a pattern may be considered "good" if it does the following:
• Solves a particular problem: Patterns are not supposed to just capture principles or strategies. They need to capture solutions. This is one of the most essential ingredients for a good pattern.
• The solution to this problem cannot be obvious: We can find that problem-solving techniques often attempt to derive from well-known first principles. The best design patterns usually provide solutions to problems indirectly - this is considered a necessary approach for the most challenging problems related to design.
• The concept described must have been proven: Design patterns require proof that they function as described and without this proof the design cannot be seriously considered. If a pattern is highly speculative in nature, only the brave may attempt to use it.
• It must describe a relationship: In some cases it may appear that a pattern describes a type of module. Although an implementation may appear this way, the official description of the pattern must describe much deeper system structures and mechanisms that explain its relationship to code.
We would be forgiven for thinking that a proto-pattern which fails to meet guidelines isn't worth learning from, however, this is far from the truth. Many proto-patterns are actually quite good. I'm not saying that all proto-patterns are worth looking at, but there are quite a few useful ones in the wild that could assist us with future projects. Use best judgment with the above list in mind and you'll be fine in your selection process.
One of the additional requirements for a pattern to be valid is that they display some recurring phenomenon. This is often something that can be qualified in at least three key areas, referred to as the rule of three. To show recurrence using this rule, one must demonstrate:
1. • Fitness of purpose - how is the pattern considered successful?
2. • Usefulness - why is the pattern considered successful?
3. • Applicability - is the design worthy of being a pattern because it has wider applicability? If so, this needs to be explained. When reviewing or defining a pattern, it is important to keep the above in mind.
About the Author
Addy Osmani is a Developer Programs Engineer at Google, working on tools for improving how developers create applications. He's also a member of the jQuery team where he assists with documentation and our learning site project. Some of his other OS work has included contributions to Modernizr and other similar projects. Personal projects include TodoMVC, which helps developers compare JavaScript MVC frameworks and jQuery UI Bootstrap. He also wrote 'Developing Backbone.js Applications' and 'Learning JavaScript Design Patterns' and occasionally tech review books like 'JavaScript Web Applications'. His personal blog is addyosmani.com/blog/.
Reader JRamer says," Addy does a great job of introducing a variety of design patterns and provides nice examples for each. I'm a pretty new developer so some of the concepts were a bit over my head, but I still got a lot out of this book. I definitely recommend it to any developer regardless of experience level."
Reader H. Paul Robertson says," I got this book hoping to learn some good ways to structure my JavaScript code. This book helped me tremendously with that, and also with other needs that have arisen as my JS coding has become progressively more complex.
The sections that were particularly valuable to me include:
- Module patterns
- the MV* comparisons
- "Modern" modular patterns (AMD and CommonJS)
Before I started reading this book I was concerned that it would be another "here's the list of GOF 'Design Patterns' translated to [language XYZ]" but it's not that at all. This book is JavaScript first, "design patterns" second. Obviously the content of the book is design patterns. However, the selection of the patterns and the explanations for how to use them are driven by the language and the tasks that are common for JavaScript programming, not just by a list of patterns that are "famous" or are used in other books.
My only complaint about this book is that in some cases the information is specific to particular frameworks or libraries, to a fault. For example, in the section on Module patterns, it covers implementations in several frameworks -- YUI, MooTools, Dojo, etc. But of course frameworks come and go all the time, so I'd rather not have to read them and make a judgement about whether to learn the approach in one or the other framework. In another case, in the PubSub implementation section, the most coverage is given to a specific implementation (Ben Alman's PubSub) but I would have preferred to get more discussion about general implementation approaches (e.g. with a generic, basic implementation) rather than skipping straight into "here's a version with all the bells and whistles" without enough detail about why a particular feature is useful.
Overall it's a great book, one that I've returned to again and again. In fact, as I write this I realized that I'm facing another case of "what's a good way to design my code to do XYZ in JavaScript" and I'm realizing I ought to look and see if it's covered in this book, in which case I'll probably find a good answer!"
More Java Script Code:
• Regular Expressions Boundaries
• Working With the Keyboard in Java Script
• JavaScript to Add and Remove Rows and Cells from a Table
• Creating Java Script Dynamic or anonymous Functions at Runtime
• Java Script Message Boxes
• Easy Java Script Form Validation
• Easy Expanding Banner Code
• Replace Drop-down with Drag-and-drop
• How to Place Image on HTML5 Canvas
• Java Script to Get Selected Item from Select List Option Group