📜 ⬆️ ⬇️

Design patterns in modern JavaScript development

The author of the material, the translation of which we publish, says that in the world of software development, “architectural design” can be called the process of constructing an application, during which it is sought to be made high-quality, reliable and well-supported. At the same time, design patterns (templates) allow you to operate with concepts that represent approaches to solving common problems. These solutions can range from abstract, conceptual, to very specific. Their knowledge allows developers to communicate effectively with each other.

If at least two developers in a team understand patterns, the conversation about solving problems facing a team becomes very productive. If only one member of the team knows about the patterns, it is usually just to explain what he knows to the other members of the team.

image
')
The purpose of this article is to interest readers in something like a formal presentation of knowledge in the field of software development, demonstrating to them the idea of ​​design patterns and describing several patterns that are interesting because they have found application in modern JavaScript-Development.

Pattern "Singleton"


▍General information


The singleton design pattern, which is also called the “loner”, cannot be called one of the most widely used patterns, but we start the conversation with it, since it is relatively easy to understand.

This pattern arises from the mathematical concept of a singleton - a one-element set, that is, a set containing only one element. For example, the set {null} is singleton.

In the field of software development, the meaning of the “singleton” pattern is that we limit the number of possible instances of a certain class to one object. When you first try to create an object based on the class that implements this pattern, such an object is actually created. All subsequent attempts to create an instance of the class result in the return of the object created during the first attempt to obtain an instance of the class.


Why another superhero when we have Batman?

Above is an example of a class that implements the singleton pattern.

▍Why is it needed?


It is clear that this pattern allows us to restrict ourselves to only one “superhero” (this is obviously Batman). But why else would he need it?

Although this pattern is not devoid of its own problems (it used to be called evil, considering that singletons were called pathological liars ), it can be very useful in some situations. One of these situations is to initialize configuration objects. In a typical application, it makes sense to keep only one instance of such an object, unless, in accordance with the features of the project, it does not use several such objects.

▍Where is it used?


The main example of using the “singleton” pattern in large popular frameworks is Angular services. The Angular documentation has a separate page explaining how to make a service a singleton.

Making services in the form of singletons has a deep meaning, as services are used as state storage, configuration, and allow you to organize the interaction between components. All this leads to the fact that the developer needs that in his application there would not be several instances of the same service.

Consider an example. Suppose we have a simple application that is used to calculate the number of button presses.


Each click on any of the buttons updates the counter.

The number of clicks on the buttons must be stored in one object, which implements the following features:


If such an object would not be a singleton (and each button would have its own instance of such an object associated), then the program would incorrectly count the number of button presses. In addition, with this approach it is necessary to solve the following problem: “From which object, which is responsible for counting clicks, will the data displayed on the screen be taken?”.

The Observer Pattern


▍General information


The observer pattern is a design pattern in which an object called a “subject” (subject) maintains a list of dependent objects called observers and automatically notifies them when their state changes, usually by calling one of their methods. .

Understanding this pattern is not difficult if you find its analogy in the real world. Namely, we are talking about newspaper subscriptions.

Suppose you usually buy newspapers at a kiosk. You go there, ask if there is a fresh issue of your favorite newspaper. If you don’t have what you need in the kiosk, then you go home, having wasted time, and then again go to the kiosk. If we consider this situation in the application to JavaScript, then it would be similar to the cyclical polling of some entity, performed until the necessary data is obtained from it.

After you finally get the newspaper you need, you can proceed to what you have been striving for all this time - take a cup of coffee and unwrap the newspaper. In JavaScript, this would be equivalent to calling a callback, which we were going to call after getting the desired result.


Finally you can read the newspaper.

It would be much more reasonable to do this: subscribe to a newspaper and receive a fresh issue every day. With this approach, the publisher will let you know that the latest issue of the newspaper has been published, and will deliver it to you. You do not have to go to the kiosk anymore. No more wasting time.

If you go back to JavaScript again, this means that you will no longer have to wait in the loop for some result, and, having received it, call some function. Instead, you tell the subject that you are interested in certain events (messages), and you give him a callback function, which should be called when the data you are interested in is ready. You then become an observer.


Now you will never miss your favorite morning paper.

The pattern in question has one nice feature: you do not have to be the only observer. If you can't get your favorite newspaper, it will upset you. But the same thing will happen with other people who can not buy it. That is why several observers can subscribe to one subject.

▍Why is it needed?


The “observer” pattern is used in many situations, but usually it should be used when you want to create a one-to-many relationship between objects, and at the same time such objects should not be tightly coupled. In addition, the created system should be able to notify an unlimited number of objects about certain changes.

JavaScript applications are a great place to apply the “observer” pattern, since everything here is controlled by events, and instead of constantly turning to an entity, knowing whether an event of interest has occurred, it would be much better to give it the opportunity to notify you when the occurrence of this event (it looks like the old saying: "We don’t need to call. When we need to, we will call you ourselves").

It is likely that you have already used structures that resemble the "observer" pattern. For example, it is addEventListener . Adding an event listener to an item has all the hallmarks of using a “watcher” pattern:


It is useful to be aware of the existence of the “observer” pattern in the sense that this knowledge allows you to realize your own subject, or much faster than before, to deal with an existing solution using this pattern.

▍Where is it used?


The basic implementation of this pattern does not have to be particularly difficult, but there are excellent libraries that implement it and are used in many projects. This is a ReactiveX project, and its JavaScript version of RxJS .

The RxJS library allows you not only to subscribe to subjects, but also gives the programmer the ability to transform data in a variety of ways, allows you to combine multiple subscriptions, and improves the ability to manage asynchronous operations. In addition, its capabilities are not limited to this. If you have ever wanted to raise the capabilities of their programs for processing and converting data to a higher level, then you can recommend to explore the RxJS library.

In addition to the “observer” pattern, the ReactiveX project can be proud of the implementation of the “iterator” pattern (iterator), which enables the subject to inform subscribers about the completion of the subscription, in fact, allowing the subject to be canceled at the initiative of the subject. In this article, I'm not going to talk about the “iterator” pattern, but I can say that if you are just starting to study design patterns, studying this pattern and thinking about how it is combined with the “observer” pattern can be good exercises.

Pattern "facade"


▍General information


The facade pattern got its name from architecture. In architecture, the facade is usually one of the outer sides of the building, as a rule - the front side. English borrowed the word "facade" from French. We are talking about the word "façade", which, among other things, translates as "the front side of the building."

The facade of a building in architecture is the outer part of the building that hides what is inside. Similar properties can be noted in the “facade” pattern, as it aims to hide complex internal mechanisms behind some external interface. Its use allows the developer to work with an external API, arranged fairly simply, and, at the same time, provides the ability to change the internal mechanisms hidden behind the facade, without disturbing the performance of the system.

▍Why is it needed?


The “facade” pattern can be used in a huge number of situations, among which it is possible to highlight those of them when they try to make the code simpler to understand (that is, they hide complex mechanisms behind simple APIs), and those when fragments of systems tend to make weaker related to each other.


These objects need something from the dragon's lair

It is easy to see that an object facade (or a layer with several objects) is a very useful abstraction. Hardly anyone wants to face the dragon in the event that this can be avoided. The object-facade is needed in order to provide other objects with a convenient API, and with all the dragon tricks this object will manage on its own.

Another useful feature of the “facade” pattern is that you can “redo” the dragon as you like, but this will not affect other parts of the application. Suppose you want to replace the dragon with a kitten. A kitten, like a dragon, has claws, but it is easier to feed him. To change a dragon for a kitten - this means - to rewrite the code of the facade object without making changes to the dependent objects.

▍Where is it used?


Pattern "facade" can often be found in Angular. There, services are used as tools to simplify some kind of basic logic. But this pattern is applicable not only in Angular, below you can see this.

Suppose we need to add a state management system to the application. To solve this problem, you can use different tools, among them - Redux, NgRx, Akita, MobX, Apollo, as well as constantly emerging new tools. Why not try them all?
What is the main functionality that a state library should provide? These are probably the following options:


It looks all not so bad.

Now, armed with the “facade” pattern, you can write facades for working with different parts of the state, providing convenient APIs that can be used in the program. For example, something like facade.startSpinner() , facade.stopSpinner() and facade.getSpinnerState() . Such methods are simple to understand, they can easily be referred to in a conversation about the program.

After that, you can work with objects that implement the “facade” pattern and write code that will transform your code so that it can work with Apollo (state management using GraphQL is a hot topic). It is possible that during the tests you will find that Apollo is not suitable for you, or that it is inconvenient for you to write unit tests for this state management system. No problem - write a new façade designed for MobX support and test the system again.


Different systems for managing the state of the application, which is accessed through a single facade, can also be dragons ...

Results


You probably noticed that when talking about design patterns, we didn’t look at code samples. The fact is that a deep analysis of each pattern draws at least a separate chapter in a book that is far from being the thinnest. By the way, since we started talking about books, here and now - interesting publications that can be looked at by those who want to delve into the study of patterns.

In the end, I want to say that in mastering patterns, nothing compares to searching on the Internet, reading and independent testing of various ideas. Even if it turns out that you will never use the patterns, you will learn something new and grow into areas unexpected for yourself.

Dear readers! What design patterns do you use?

Source: https://habr.com/ru/post/450318/


All Articles