"less popular" JavaScript design patterns
In this article, we're considering some of the less well-known but potentially useful JS patterns that include command, builder, and special case, as well as looking at real examples from our production experience.
Introduction
As software engineers, we strive to write maintainable, reusable, and eloquent code that might live forever in large applications. The code we create must solve real problems. We are certainly not trying to create redundant, unnecessary, or “just for fun” code. At the same time, we frequently face problems that already have well-known solutions that have been defined and discussed by the Global community or even by our own teams millions of times. Those solutions for such problems are called “Design patterns”.
Design patterns in JavaScript
There are a number of existing design patterns in software design, some of them are used more often, some of them less frequently. Examples of popular JavaScript design patterns include factory, singleton, strategy, decorator, and observer patterns. In this article, we’re not going to cover all of the design patterns in JavaScript. Instead, let’s consider some of the less well-known but potentially useful JS patterns such as command, builder, and special case, as well as real examples from our production experience.
Command pattern
Just imagine there’s a TV in your flat, and you have a remote control for it. When you (“client”) press any button (for instance, “Volume Up”) on the remote control (“invoker”), it sends a signal to your TV (“receiver”) and the command executes with a particular result. That’s basically how command pattern is used in action.
In our real-world case, this design pattern in JavaScript was useful for processing messages from a message broker. It helped considerably with decoupling the execution logic for each message, and made it easier to add new commands if necessary.
The implementation was approximately the following:
In some implementations, command pattern might include a rollback method and journaling of each executed command.
Builder pattern
Have you ever ordered something from McDonald’s? Generally speaking, after you place a complex order, your order will be built from several components, for instance, a drink, a burger, and French fries, step-by-step. You don’t know how it was built or cooked, you just wait for your ready-to-go meal. Similarly, a builder encapsulates an entire process.
The real-case scenario was building a report. The report had several major components, from various sources, and after all the data was built, the report was to be sent to a reporting service.
The high-level implementation of the described JS pattern:
This pattern helped achieve a clear separation between the construction and representation of an object, and better control over the construction process itself.
Special case pattern
From time to time, while defining classes and objects that will handle some data, we do not want to change the behavior of the code if something goes wrong. Instead, we will manage that unique situation safely to avoid immediate failure or error. This is when Martin Fowler’s Special case JavaScript pattern comes in.
The Special Case pattern is a refinement of the strategy pattern. Generally speaking, it’s a default strategy with the same interface as it’s siblings and is what the caller expects.
As an example, we had several types of content on our application, some of them should have been processed, some of them not. The processor was defined by the strategy based on content type and, by default, it returned a nullable/default processor.
Let’s have a look at a code sample of this JavaScript pattern
The pattern helped us not be afraid of getting the wrong input, and enabled us to use the processor’s public interface safely without any kind of null exceptions or unnecessary checks.
Closing thoughts
Plenty of JavaScript design patterns are well-defined and explained in articles like this one. However, please avoid any tendency toward overuse. As they say, “If all you have is a hammer, everything looks like a nail.” You don’t want to fall into the trap of overuse, so use these JS patterns only when necessary, and when it might solve a real problem in your code.
Thanks for reading!