Upper-level architecture frontend. Yandex lecture

    Choosing the right architecture is a key part of building a service frontend. Developer Anna Karpelevich told the students of the Interface Development School what architecture is, what functions it performs and what problems it solves. From the lecture you can learn about the most popular architectural approaches in the frontend: Model-View- * and Flux.


    - Good evening. My name is Anya Karpelevich. Today we will talk about the architecture of the frontend of the upper level.

    I work in Direct. We make interfaces for advertisers. They serve ads, customize them. This is a very complex, interesting system, there are many interrelated components in it, they grow into each other, they have common and their own functionalities. "Pants turn into elegant shorts." All this has to be very carefully controlled. And the architecture in our applications is very complex. This is one of the reasons why I am reading this lecture today. I really love this topic.

    What is architecture? The fact is that the answer to this question probably is not. Or there is, but everyone has his own. This is a very controversial topic. It causes a lot of controversy, a lot of holivars. And a lot of what I’m going to tell today is my opinion. Partly it is supported by my working group, partly - not very. And everyone, when he writes the architecture of his application, decides for himself how and what to do.

    That is why architecture is one of the most probably creative places in the work of a programmer. And therefore, our presentation today will also begin with creativity.



    Let's look at the left picture. I will be very happy if someone recognizes the building that is depicted on it. This is the church of Saint-Sulpice in Paris. Pay attention to the turrets, for the sake of them this church was set here. I hope, it is clear that they are different. Pretty much different, and there is an interesting reason. Between them 130 years of difference. Then the left tower was demolished and rebuilt during the Franco-Prussian war.

    Why is she here? Look at this picture. The towers have the same architecture, and the whole environment, these vignettes, trinkets, arched structures are different. Why is that? Because the purpose of these towers is the same. None of them, for example, was a bell tower. These are just towers. Something was stored in them, and everything else is different. Why? Because the architecture of these towers is the same. Both have a vault, only one window, and it is pointed. The height of the windows is about the same. And the idea is that architecture, both buildings and applications, is a support structure. This is not a vignette, not a trill, not a realization. This is what stands. And this basis, as a rule, depends on the environment, on the soil, if we are talking about a building, on the goal that the architect sets himself, but almost never depends on designer delights.

    The building example for the architecture theme is fairly obvious. But the right picture is more interesting. "Architecture is numb music." “Architektur ist gefrorene Musik,” said Johann Wolfgang Goethe in the 18th century. Goethe most likely did not know anything about the architecture of the buildings, he was a poet. And he guaranteed nothing knew about the application architecture. But he expressed a very valuable and interesting idea.

    Music exists in dynamics. This is not something static. This is a process. And in the same way, an application is a process. He has a moment of launch, he has a moment of development, when we do something with him, we work. And he finally has a moment of completion. The architecture of the application is its slice at any particular time. At any moment, our application, as a musical theme, must be clear, clear, understandable, predictable, etc. Otherwise, everything will fall apart.

    With this we will end with a creative introduction, go to things more mundane, closer to the practice of building applications.

    What is architecture and why is it needed?



    First, we have the organization of a large amount of codes, something with which we are in Yandex.Direct, and not only in Yandex.Direct, we constantly come across. Code so much that it can be lost. We do not want to get lost in the code.

    Secondly, duplication of functionality. This is also an eternal problem that you will always meet, and today this topic about duplication will go straight through the red line through the entire lecture. We may need the same functionality in several places in the interface. If it is needed in several places, then it must be physically the same code that is used in several places, not copies. Why? We will talk about this further. But the architecture should help us to avoid copy-paste.

    The third is support. It is quite obvious that if we have an application, then it needs to be somehow supported, and it is desirable that all the resources of the team are not spent on it.

    Change the composition of the team. The same thing that we meet in real life more often than we would like. Someone comes, someone leaves, and if a person spends half a year to enter the code, this is bad. If the knowledge about the code is stored only in one head, and it will transfer this knowledge for half a year in case of leaving, it is even worse. In general, here the architecture also helps us to make all this more understandable and to maintain the sharing of knowledge.

    Adding and expanding functionality. Too obvious enough thing. The manager comes running to us and says that this is an urgent need. And if in order to do this urgently, you have to spend a lot of time and effort, then this is a bad architectural decision. And we need good.

    And finally, mistakes. The clearer and more predictable our architecture is, the easier it is to find errors, the fewer bugs.

    How can you call all this? All this can be called - the problems of a complex system. An application is a complex system, the architecture helps us solve a problem.



    In short, something like that. Here is a picture of noodles on my right, and this is what happens if architecture is not followed, if it is not built, thought out and not designed. And the second picture is what happens if you think about the architecture somehow. This is not Saint-Sulpice, but at least the children's designer, he stands firmly and does not fall apart. In the constructor today we will also play a lot.



    Formally about all this. Architecture is a way to solve problems of a complex system by abstraction of implementation from an interface and delimitation of authority between blocks of code. Below we will analyze this long phrase in detail.

    What are the features of the application architecture as a field of knowledge? She has a specific area that we work with. That is, it is not something abstract, it is a very specific thing. Here is the task, we select the architecture for it, but not so that, uh, an interesting architectural approach should be tried. So, no. You can try on something small, but for a serious project the architecture is chosen, sometimes it is composed for a specific project.

    The history of the question when, in general, this idea arose that the need to do architecture. In 1968, Edsger Dijkstra, a remarkable programmer, expressed this very unusual thought. He is more likely known as the author of the Dijkstra algorithm, searching for the shortest path in the graph. But he has plenty, in fact, breakthrough ideas for his time. And one of them is an article, I will give you a reference to the materials later, you can read, there are only two pages, a short essay. It sounds like “Operator GOTO is considered harmful,” translated as “Operator GOTO - an unconditional transfer operator - evil.” It was the first thought that let's officially say that we need to write architecture, and not noodles.

    In the 70s, this idea was already developed by Dijkstra in collaboration with Parnassus, and by themselves, separately. The first detailed book on application architecture as a whole was written in 1996 by Mary Shaw and David Garland. After that, in fact, such detailed books about software architecture were not written precisely because of the field of application that each field of knowledge has its own architectural approaches, somewhere, somewhere else more, something, in general , not applicable in any places. And since architecture is a creative process, you will not find any specific books about how to write architecture. Maybe after 1996 there was nothing particularly detailed on this subject.

    What are the requirements for the project architecture now. First, and most importantly, what is required of him is, in fact, extensibility, because if your project is not expanding, it is dead.

    Reuse code. This is about the very copy-paste. If you have two blocks that are used in two different places, you need the same functionality, then you need to reuse the same code, and the architecture should be such that any piece of code can be taken and reused as soon as it is needed. .

    The separation of powers between code modules. We will also talk about this in more detail today why this is necessary. The idea is this: each module, each block, each piece of code must perform one specific action, carry exactly one function. And this function should be placed in the header of this method, class, whatever it is, module. One module - one function.

    And finally, the quality of applications. There are a lot of things that I would like to do - reliability and backward compatibility. In reality, again, selected by the task. Somewhere backward compatibility is needed so that in no way does anything move away. Somewhere you need reliability so that, God forbid, passwords, PIN codes of cards or CVV will not go away anywhere. Somewhere it is necessary that it be trouble-free, if it is a satellite or something else. In general, choose any few. The more you want to support, the more complexity you will most likely encounter in architecture.

    Further we will talk with you about some definitions, such encyclopedic things. Why is it important? Because the terminology in architecture is very important, and we need to speak the same language with you. The definitions for the most part are taken from the programming paradigm called OOP. But in fact, they have sprouted into other paradigms, with the terms “class, object, interface” operate not only within the framework of the PLO. However, these definitions and understanding are taken precisely from the world of the PLO.



    The simplest thing is class. What is a class? This is a pattern, this is a sample. For example, Snake class - class Snake. In her, we identified three private fields, that is, a field that is inaccessible to anyone other than the methods of the class itself - the number of heads, the number of tails and the length in parrots. We defined a constructor in which we put these very heads, tails and length in parrots. Got a Snake class. It's simple.



    We go further. An object. And the object is an instance of a specific structure. And, besides in classical OOP it is meant that the object is an object of a class. In the modern world of JavaScript, which was not always the OOP language, and even now it is not always and not everywhere OOP, we know that there may be abstract objects. That is, we can create an object, a literal, which is not an object of a class. But here is an example of how we create an object of the Snake class. Here we have a two-tailed snake with a length of 38 parrots, a boa.



    Module. A module is a semantic unit. It is not always a class. This may be a set of classes, a set of objects, a set of methods that are not combined into classes. Usually, we can assume that the module is what you have written into one file. But, in principle, the module is the folder in which they are located, for example, the file and the tests for this module are also a module. It is important here that the module is what you called the module, what you consider the unit of semantics. In this case, the module is about how we eat snakes. The result of this module is the last method, eatSnake, as we ate snakes. I do not know why we eat snakes, but we can do this because we wrote this module.



    It was trivial, a little more interesting thing will start next. Class interface The interface of a class is, more simply, its public methods, what it sticks out, what we can get from an object of this class from an object from the outside. This class implements the getSnakeLength interface. He can give us the length of the snake. Please note that there is no access to private fields from the outside. Access from the outside is only to the public method getSnakeLength.



    But then a very interesting thing. We argued for a long time about how to call this thing, because I thought up the term “abstract interface” when I created this lecture. And, frankly, I have never seen the normal definition of this approach and method. Nevertheless, many programming languages ​​allow you to create abstract interfaces, and call them, as soon as they are not abstract classes, and abstract interfaces, too, just interfaces. It turns out the homonym with the class interface. The idea is that an abstract interface is a collection of methods that do something. When we create a class, we go from the question “what is it?” This is a snake and it knows how to do something, or does not know how. She can simply give her length.

    And when we create an interface, we go from what it does, what it should be able to do. And it turns out to be a very powerful way to extend classes. We can attribute some possibilities to classes, expanding it with the help of interfaces. For example, the I-BEM framework can do such a thing, such a story with abstract interfaces is built into the framework. Many frameworks, unfortunately, do not know how, but a powerful thing.

    Here, as an example, we created an audiable interface, something that can sound. And its definition is an abstract empty getNoise method. We expanded our snake with the audiable class, implemented its getNoise method, and our snake hissed. The inspiration for this set of examples was given to me by the wonderful book of Eric Freeman and the company “Design Patterns”.

    Now we will try to look at these examples a little more specifically.



    But first, let's talk about why these examples were needed. And they were needed for this big slide. What is written here is so important that I even carried it to the yellow title. It can be said mantra. This is a very important principle that you should always think about when you are designing an architecture. High cohesity, low coupling - strong grip, weak connectivity. There is some problem with the fact that the word cohesity and the word coupling in Russian and so, and so translated "connectedness", specifically for this principle came up with the word grip.

    The idea is this. Your blocks should be very compact, very tightly coupled. They must implement exactly one function. And among themselves they must be connected very easily, so that they can be easily combined, assembled as a designer. And then your architecture will be quite flexible and fairly reliable. And easy to test.

    Let's see how we achieve strong adhesion and weak connectivity between the points, as they say.



    Specialization. Each block solves only one problem. Here we have a good illustration - a children's designer. We have every block, or set of blocks. They are all of their shape, their size. And if we need to build a house, we will take long bars. If we need to build a ball, we will take short bars. Each little bar has its own function. And those who played constructors know that the simpler the shape of the pieces is, the more you can build from it. Nothing is constructed from such zagogulin, or only what is described in the instruction is built. And who needs it?

    The same, abstraction. This is about the fact that the abstraction of the interface from the implementation. The idea is that the interface is external, the way this is our class, our block sticks out, the way it interacts with other blocks should not affect its internal implementation. On the contrary - it happens. In the other direction - never. In good architecture. Here, as an example, the formation of these pimples does not affect the shape of the block itself. We select the block form separately and paste the bumps on it.



    Encapsulation. Continuation of the previous topic. In private methods, that is, from the inside of our blocks, we realize the very meaning of our block, the realization. And the interface, how they are connected, is in public. That is, in this case, all these crosses, dashes and the form itself are the implementation. And the bumps are the interface. And good architecture looks like such a constructor.



    Oh, what a scary monster. This is about reuse code. Initially, this monster, in fact, was in order to show an example of bad architecture, but look at it carefully. He is beautiful. Moreover, he is clearly pleased with life, quite cheerfully running on his strange legs. Maybe he can even fly, or at least he has beautiful butterfly wings.

    What is the idea? If you have a camel implementation and a crocodile sale, and a manager comes to you and says that a camel-crocodile is urgently needed. You do not write separately a crocodile camel. You take the body of a camel, separate it from the whole realization of the camel. Take the head of a crocodile, separate it from the crocodile, and reuse blocks. Why is this necessary?

    Then, when the manager comes running back to you and says that we are urgently expanding to South America, and alligators are there, we need to maintain an irregular jaw shape, or that the crocodile has the fourth tooth is not the same, you will not fumble around the whole project where are your crocodile heads copied? Because you may have some zebra-bison-crocodile there. You just take your crocodile head, make an extension from the alligator's head series, give it the parameters, it will determine which teeth to paint for it. And that's all. In one place, and not in all the places where it is used.

    Here reliability is increased by several times, because you are guaranteed to forget any copied head in some very rare project. In general, there is nothing terrible in such cadavers. Good cadavre, helpful.



    Now we’ll look at examples of bad code. Please note this is pseudocode. Pseudocode is a bit similar to TypeScript, but still pseudocode. Do not try to run it, it does not work. It is possible to repeat, it is not worth running this code, because here syntactic constructions are used, which TypeScript 2.7 does not support, but the illustrations turned out to be good (now there are more actual examples - approx. Red.).

    So, we have a class User. He has a name and age. All is well. We have a User with the last name, I apologize for the dispersed fonts. User with last name, he has first name, age and last name.

    And we have a printLabel method. We give him User. We look further, if we have a User class User, we draw the name and age. If User class is User with last name, then first name, last name and age. Let's still try to see what is bad here.

    Code duplication, yet? Many different code duplications, good. Yes OK. There are two duplications of the code, one about the fact that we are duplicating a UserWithSurname, the second is that we are duplicating in the printLabel method. What else is there? That's right, yes, it's all about the fact that we have a lot of code duplication, potentially even more. Anything else there? Inheritance is also here, and this is also one of the options. There are two problems here - no reuse, no specialization. We also talked about two things. PrintLabel climbs into private methods. Still? Fourth what is missing here? Yes, that's it.

    There is no specialization; two units do the same. There is no abstraction, our interface and implementation are mixed. There is no encapsulation, really, access to private methods. Re-use of the code, about endless if, which can become very much, said very correctly. Let's see how to do it better, but we will not.



    We will create the printLabel interface, this is not because iPrintLabel is not because of the iPhone, but because the interface. And we define a single abstract method getText. Create a User class that implements iPrintLabel. He will have, really, private fields name and age, and a single public method, the same getText from iPrintLabel, in which we will honestly turn from private to its private fields, this is allowed and even encouraged. UserWithSurname, is actually inherited from the User class, and we will only need to define Surname and redefine getText. But printLabel will be very simple. It will take iPrintLabel and just output getText.

    The beauty here is that if an abstraction appears, the interface is separate, the implementation is separate. Encapsulation appears. Specialization, please, we did the inheritance for this. And with the reuse of the code, everything is generally fine, because we can print anything, the main thing is to expand its iPrintLabel interface, and we can not think, it will be printed, not printed, it will be printed. We will not touch the printLabel method anymore. Here is such a good, very simple, short way to improve the architecture in a few extra lines of code.

    At this point we end up with theory. With the theory of everything, because what we have just described, it is true not only for the front-end, for everything, in general. And we turn to the architectural approaches and separately to the architectural approaches that are used in the front-end and are useful, used, found.



    How does the average web application? There is a server. Inside the server, some kind of back-end architecture is implemented. Some API sticks out of it, for example, it can be a REST API or not a REST. All together - the client and the server - is also an implementation of the client-server architectural approach. Because we can have purely server applications, purely client applications, any PowerPoint from which it is all played. This is a purely client server application.

    Next we take a closer look at the front-end. The front-end consists of some large blocks. Each block is somehow implemented, and this implementation allows you to link large blocks together. Inside the module, it is also somehow implemented. Inside the module method. This method also has an architecture. And so architecture is, in fact, a hierarchy. At each level, it exists, at least at the level of declaring a variable, this can also be a piece of architecture. Small

    We will talk today about the top level of the front-end architecture, that is, how large modules are arranged, how data travels from user to server, from server to user, and a little about the implementation inside modules, how to implement them so that they This created.

    > Client-server ( Client-server )
    > Component ( Component-based )
    > Event-driven ( Event-driven )
    > REST ( Representational state transfer )
    > Model-view - * ( MVC , MVP , MVVM )
    > Unidirectional data flows ( Flux )

    These are the architectural approaches. Some of them we mentioned today. Client-server architecture; component architecture, one of its variations is familiar to you from React, I hope, is familiar. Event, which, oddly enough, is also familiar to everyone, it is based on almost all operating systems for personal computers. REST, what we love in the server, and the last two, with which we will get acquainted in detail, are the most front-end, what we are working with is model-representation * and unidirectional data streams.

    Let's start with MV *. Why an asterisk? The story is called, full of pain and anger. It was once upon a time, back in the 80s, a remarkable MVC architectural approach was invented. M - Model, V - View, C - Controller. The approach was very convenient. Invented it at all for console applications. But when web technologies began to develop, when everyone started using it, it turned out that sometimes it was necessary, the MV model is good, and the Controller is not implemented as it is. As a result, there were so many different variations of the implementation of Model-View-something that confusion first arose due to the fact that everyone called it MVC. Because if the MV model is there, then the third one is the Controller, no matter what we actually stuffed there.

    Then it turned out that people are confused and mean by MVC completely different things. Around now, not more than a year ago, we began to actively share this terminology, and to make our name for each implementation of this approach. Anyway, this MV * appeared. I also saw the term MVW on the Internet, where W - Whatever. Well, we turn, in fact, to MVC-technologies.



    How are they arranged? The idea is that we have a model that stores data. They are usually a lot. There is some kind of view that shows this data to the user. They, too, as a rule, a lot. And a third component, which is an intermediary between them, ties up the data and the display. Here is the user in the upper right corner with all this working.



    MVC, what started it all, is the distant 1980 year, Smalltalk. But it is in this form that it still exists in some frameworks. Not in some, quite in many. What is the idea? The user works directly with the view and controller. He enters data into some fields in the view, presses the send button and the data gets to the controller. This is a form submission. Honest such form submission on the submit button, familiar to all for a long time, I hope.

    We look. The yellow arrow from the user to the controller is the user passed the data to the controller via the submit button. Green arrow - control passed to the same place. The controller looks at this data. Perhaps he processes them somehow, there are already the subtleties of implementation, and sends them to the desired model. The controller chooses which model to send to. Sends with a green arrow to control, sends with a yellow arrow data.

    The model also processes the data. Perhaps she validates them. Perhaps she puts them in the base. In short, the model knows what to do with them. As a rule, the result is new data. For example, we can tell the user whether he logged in or not, and the model checked the password with a login. After that, the model transfers control to the controller again, so that the controller selects which view to display. And the data goes directly to the View. How can you do this, in general, how can the model send the data to the view?



    Very simple. If the controller and model are in the back-end, and the View template is server-side. This is how Ruby on Rails, ASP.NET, Django frameworks are designed, in general, wherever you write server templating, and the HTML you receive comes to the client, and the data also goes back, most likely, this is the approach. What are our problems here? In a single page application such a thing does not build. We constantly came to the server, went to the server, the page reloads. Secondly, it is not at all clear where to push client validation, and, in general, client-side JavaScript, AJAX, and all that? Because if we want something quick, there is no place. It simply does not work in this approach, or it works in such a way that it does not work better.

    The last line here is an interesting story with roots that seems to go back to 2008. The question was: where to store business logic - on the model or in the controller? There were those who said: “We keep the business logic in the controller, because it’s convenient, the data is immediately sent to the model. The controller itself pays off, to double-check, if anything, and send an error. ” There were those who said that "The result is fat stupid ugly controllers, thick stupid, ugly controllers." They really turned out huge. And they said that the business logic should be in the model, and the controller should be thin, light, the data passed, the model itself processed. And then in the first version of the model, in general, it turns out, just an API to the database.

    How, in my opinion, really? In fact, you need to watch their tasks. If you have a connection between a view and a model always one to one, one View is one model, then it is convenient for you to do business logic in the controllers, and to make a simple clean model, which really will be an API to the database. If your views and models can intersect, and one view depends on many models, the model works with many views, it is convenient for you to have many thin controllers and multiply them in any progression, you do not care how many they are, they are still small.

    It must be said that in the world, it seems, the second point of view won, with business logic in models. That is, these fat stupid ugly controllers seem to be less actively used. Signals, you can watch the fact that in the documentation for ASP.NET, the framework in 2013 offered business logic in the controllers. And in the latest versions in 2014 - in models. It was a very interesting moment when it changed.

    What MVC has problems. We have already spoken them, but we will speak. Testing is not clear how to implement client validation is possible, but difficult, AJAX is screwed on the side, you have to do something. Come up with a solution. The solution was called MVP, and yes, you can meet MVP in a framework with the text that they are MVC. For example, Backbone MVP framework. About him for a long time in the documentation in the same 2011-2012-2013, it was written that this is a MVC framework.



    Model-View-Presenter. His scheme is much more simple. There are models. They interact with each other. Give data to the Presenter, Presenter sends it to the view, shows it to the user. And back. The user drives something into the view, presses a button, Presenter watches it, AJAX sends it to the model or puts it into the model, and sends the AJAX model to the server. That is, everything is already much more simple and linear here, but without server templating there will already be difficulties. If you want a server one, this system will be complicated.



    Let's compare. Let's look at the first picture, where we will try to implement a very simple thing - sending data from input to the model. We entered something, pressed a button, it should appear in the model, the model will do something with it and tell us that something has happened. We drove in: “my name is Vasya,” they clicked ok. If we want client validation, then it happens here, almost by interception, in especially severe cases, indeed, by intercepting a click through event.preventDefault (). And somewhere point zero client validation is on the side.

    Then honestly we send data through the submit form to the controller. The data goes to the model, the model puts them in, processes, looks. Tells us that, well, the data is accepted, you really Vasya. The third arrow - the control goes to the controller, the model informs the controller that, please display the label “My name is Vasya”. The controller selects the appropriate view, displays the label. And the data is “my name is Vasya”, the fourth arrow, the yellow one, the model puts there. The question is how to test it? Only snapshot. In another way. There is nothing even to write functional tests.

    The second option, already with MVP. We drove in “my name is Vasya”, we clicked ok. Arrow at number one, little green, - control went to Presenter. Presenter said: button pressed. Presenter is watching, arrow number two, blue, please note this is a data request. In a classic MVP, it’s not sending data from a view to a Presenter, but a request with Presenter for data. This is much cleaner because the Presenter may already know in advance, for example, that it does not need the data, everything is still bad.

    Next, the third point on Presenter is honest JS validation. We can already calmly write it; this is a special place for it. The fourth arrow - the data goes to the model, the model, for example, put them in the database, said: "Everything is in order, I put it." The fifth arrow, you see, it is striped, I hope it can be seen that it is striped yellow-green - both the control and the data came back to the Presenter. The model said, “I put it,” Presenter himself realized that once the data were put into the database, it means that it is necessary to display that everything is in order, the data is put. And the sixth arrow, - they sent it to the view, possibly to another one, but then I did not draw the second view.

    What we have here is a plus. JS-validation took its rightful place and everything was fine with it, AJAX also fell into place, it could be the fourth arrow, for example, if the model is on the server, or the AJAX model itself goes to the server. And finally, we can safely test Presenter, write functional tests on it.



    Secondly, what else did we get in the black, besides simplified testing? We got a separation of the visual display and its work. That is, we can still write a snapshot on the View, and we can separately write tests on the Presenter. We can fix Presenter and not touch View, and vice versa. We have improved specialization. This is how frameworks such as Angular1, Backbone, Ember, Knockout of earlier versions are arranged. Once there was a lot of them, just fierce competition.

    What are the features. Presenter is already placed on the client, the model can be there, and there the single page application is quietly being made. It can be better, but it’s a lot of a single page application, or at least it’s done before. Interaction with the server by AJAX is good. Client validation on site. It would seem that all is well, why think further?

    However, at least MVVM was invented. Also an interesting thing.



    In essence, this is a Presenter implementation by means of the framework. It often happened when you wrote the first Presenter, the second Presenter, the fifth Presenter, that they are all the same. And they just knit the view and the model. As you can see, it works like MVP.



    And so many frameworks just solved these binding tasks. What are the advantages? We do not need to write extra code. And it really speeds up development. What are the cons. The connectivity between the Model and the ViewModel is enhanced.

    That is, problems arise there precisely because of strong connectedness, therefore sometimes it happens that MVVM is not used. For example, I am personally familiar with MVVM in the i-BEM framework, which we sometimes use, and sometimes do not use, because it is inconvenient, too rigid a tie. However, there is, Microsoft Silverlight is built on this technology, and they say: well. I do not know, I have not tried it.

    Why did it happen that, apart from MVP and MVVM, something else arose, familiar to you all in the word redux, why unidirectional data flows arose.



    We look at the right picture. We regularly have this problem with MVP. Suppose we have a complex system, not one to one, - many views, many models. They are all interconnected. View from above, yellowish, changed the model. The model has changed another model. The bottom yellow view has changed. The lower view also changed the model. All of them together changed the central red view, and something incomprehensible is happening in it.

    Facebook faced this when they constantly had a bug due to pop-up unread messages. That is, the user sees "You have an unread message," opens, but it does not. Because two views together corrected the state of this one ... In general, the state of the view was corrected from two different sources, and who is right is not clear. They ruled it, the bug appeared again, they ruled again, the bug appeared again. In the end, they are tired, and they decided to solve the problem radically, sorry for the tautology, and just make sure that the state of the view is deterministic.

    The MVP problem is in the non-determinism of the system state. We cannot always predict what condition it is in now, and who first came there, who corrected it. Flux solved this problem genetically. He can not have this. I was told here for a long time that the idea of ​​a unidirectional data flow was in the air, this is true. And this concept was invented, of course, long before Facebook, long before 2013, when they published it. But they, as they say, patented, first released a spreadshit, that we came up with just such a thing, use it.



    Let's take a closer look at Flux. The idea here is this. We have a Store, and this Store is a data warehouse, it is the only source of truth for our application. All the rest is not true. How does he work. At first, if we look at the work cycle, it usually begins with the fact that the user has done something, that is, the view is working. The view creates an Action. Please note that the Action without a fill in the picture. Why is that? Because it is a structure. It is not a class, not an object, it is not something clever. This is a structure. In the web, in JavaScript, we can write it, it is just that abstract object.

    The view structure creates, transfers to the block dispatcher. The dispatcher triggers a callback. That is, he says: “Call the function that I was told to call when Action happens. Said to call the Store. ” That is, the Store method from the dispatcher is called. The method is being invoked. The method is called, it turns out on the Store. Store looks what came to him, somehow changes itself. He changes his state. And he is the only one who can change his state. No one else does. That is, he is the only source of truth. After that, broadkastit all views tied to it, all components tied to it: "I have changed, go for the data."

    Views go for the data, and then an interesting moment begins. In classic Flux, in the way it is presented on Facebook, the view is redrawn completely.



    Here is our mold with a label and a button. How does she work? Look point zero. Point zero here too. He is the blue arrow at the bottom, registration callback. This is what happens first.

    The store in the dispatcher calls: “Register, please, my callback, what will I do when the Action comes on you”. Happened. Then we can work with the application. We pressed a button, created a structure. Note that the Action, besides the data entered by the user, for example, Vasya, he also has metadata type. A very important point is that the Action itself transmits that it is for the Action, but the dispatcher doesn’t care. He throws all the action broadcast. The first arrow, the method is called.

    The dispatcher calls the method, in essence, the Action trigger and passes that same Action there. On the Action trigger, a callback call occurs, which we registered at point zero. Here is the red arrow, this is a callback call with a callback. Store takes this data, looks at what, yeah, change name type, then I change myself in the name field to Vasya, and send it to the back-end, and somehow validates, probably in general, the Store knows what to do . Next, the purple arrow is a change event. We have changed. Everyone knows that our Store has changed.

    Further, a small feature of classic Flux, which may be unfamiliar to be unexpected for those who worked with Redux, more precisely, even with React, and not with Redux. Views follow the data. They go to the Store and say: "I have this field, this field and this field here." We are accustomed to the fact that, on the contrary, everything comes to views if you have worked with React, Redux, or something like that. And the sixth point, complete redrawing.

    Let's look at this scheme and find a bottleneck, because of what? Redraw. Full redrawing, which is why Flux actively began to be used after 2013, when did something arise? What allowed it to do? Virtual home. A virtual house that allows you to redraw only when it really is necessary.



    Let's step aside a little and tell you about React, which, in this way, very successfully combined with Flux, made the world that we know now when this technology is the most popular.

    Same 2013, same 2013, same Facebook. Initially, React was invented in general, as noted by the views in MVC, MVP, variations. And it can really be used there. What is its power. Firstly, a virtual house, as it was rightly said, allows us not to redraw the real house, because it is a very difficult operation, but to redraw the virtual one. And only if, indeed, there was a change, we redraw the component, with the result that everything works much faster than it could be.

    And - pure immunity components. This is the mechanism of properties. The implementation is also a rocket, allows you to create components that do not have their own state. And if you write in this architecture, it is very correct to create components that are clean, without state, without state. They only have the data that came from the Store, and he draws it. It is convenient to test them, they very rarely break. What is static is quite difficult to break, and testing is easy.

    Applications combined with Flux architecture are powerful. Probably many people know that this is really a powerful thing. What is some importance that should definitely be mentioned? In addition to React Redux, there are lots of other bundles. And, probably, you know that there is a second Angular. This is also a combination of a reactive framework and Flux architecture. There is Vue, there are other implementations of Flux besides Redux - Fluxxor, MobX, etc. No need to dwell on React Redux. The same Vue, for example, is more convenient for creating small applications than React Redux. It is much more lightweight.



    How to choose between all this variety? It would seem that now only React Redux and all is well. Well Vue, alright. Not really. If you have a simple website with static pages or very simple client input, it is much easier to quickly launch the MVC framework. Because you probably have an admin panel with a bunch of data and a display. And no interaction is required. On some React Redux you will kill to write it.

    MVP / MVVM frameworks also have their niche. It is now rare, because applications are needed more often - multi-page, with dynamic, but fairly simple data. Not single page application, but multiple page application. Some data from the user still come. For example, it would be convenient to do simple wiki pages, without some super complex formatting and interactivity. Unpretentious, on MVP, it would be quite convenient to do.

    Now the most frequent case for us is a single page application and complex logic, a lot of interaction between components, all sorts of smart inputs, etc. This is Flux with a virtual home React Redux, View, Angular, MobX, Fluxxor, etc.

    Conclusion. Literary.

    > MVC: Smalltalk-80 , General MVC , ASP.NET , MVC on Web
    > MVP: MVP vs MVC , GUI Architecture , Backbone , Angular1
    > MVVM: MS Silverlight , BEM and i-BEM
    > Flux: Hexlet blog , Flux for stupid people , Flux official , ReactJS , VueJS
    > Other: Stoyan Stefanov, “Javascript. Templates , Eric Freeman et al., Design Patterns , D.Garlain, M.Shaw, “An Introduction to Software Architecture”(1994), E.Dijkstra "GOTO statement considered harmful" (1968)

    About MVC, MVP, MVVM you can read a lot of things. It is clear that first of all there is documentation for the corresponding software applications. There are many explanations about Flux on the Internet. Read, it may be clearer. Probably the most interesting line is the last one. She generally about everything. Javascript Templates If suddenly you have to live in the world of ES5, then in the first book “JavaScript. Templates ”you will find a lot about how convenient it is to build architecture without all of these ES6-features - which, of course, exist, but sometimes you have to live without them.

    Eric Freeman, Design Patterns. Very useful book. There are examples in Java, but this should not scare you. Much of what is written there is also used in Flux, as you will notice later. And this is used in MVP, and this is there. But I can use such a pattern in this block, which draws pictures on my screen. Very useful book and easy to read.

    The same book, David Gerlan and Mary Shaw, "Introduction to software architecture." It is, of course, outdated, but what is called reliable. And I highly recommend Edsger Dijkstra’s very article “GOTO operator is considered harmful”. It is like arithmetic. Probably without it anywhere.

    Homework. It will be interesting. We will write our framework. I think any more or less experienced programmer will say that sooner or later this thought occurred to him. You will be prompted to write at least a little Flux, the very story with the label, the button and the input to Flux. You don’t need to write the implementation of server components - it’s enough just to print to the console that we pretended to send something to the server. The implementation of a complete redrawing of the virtual home screen is also not necessary to write. You can redraw only a piece and pretend that the component has been completely redrawn. Questions, wishes, you can write here . Thank you very much.

    Also popular now: