Do you still remember that it's about performance?
The whole thing takes almost 2 MB already in a compressed form, so it’s not surprising that on some tests like “how will it work on a mobile phone?” It gives funny download times. But, nevertheless, this is not such a big problem for us, because most of the clients are corporate, and they climb into the admin area when they need to either configure something, i.e. in the first week after buying the product, or when the hell pipets, i.e. need to get backup. And the man who has a hell of pipets, is ready to wait 16 seconds, until finally the admin panel is loaded. Moreover, here we are talking about a rather thin channel.
The framework is understandable, very difficult and confusing. And the application itself? Climbed into the application code.
It turns out that there are few comments in the code. Some difficult places are not explained. All applications are tightly connected. Instead of one class - long, 2.5 thousand lines, we usually deal with three or four classes of 1000 lines, which are very tough to know about each other, and so on the ring, communicating, send events to themselves, change states within themselves. And we have very big problems inside with the boundaries between the model and the business logic, and between the business logic and the view. It turns out that we have view-classes, which are called somehow like “a magic panel implementing a certain functional”, which both draws itself and draws its child components, and also has a business logic that can switch between then the panels inside, and which can send notifications, even often they climb from the view-classes to the server.
Therefore (very conditionally) it turned out that we have not Mvc, but M + CV. Those. the boundary between control and view is not very defined. It turned out that there is business logic in the models, and there is business logic in the controllers, and in view there is business logic, and UI logic, and the state of the application is also spread over all three types of classes. Therefore, it is difficult, for example, to understand where these data came from, or who is the authoritative point, where this data came from, and who currently stores the most reliable copy of this data, because it is in several parts of the application.
It also turned out that the Ext JS framework itself pushes everyone to the architecture built on publish / subscribe, because, in principle, all UI components are tied to this mechanism, and programmers unwittingly choose what the framework offers. And, like, publish / subscribe is the right pattern, but when you start looking at an application in which there is 100 pages, you end up with what you are trying to figure out: “Damn, but what does pressing this button in this panel result in? , and what is she jerking?
And it turns out that, firstly, events can implicitly fall into the parent classes, which, in turn, generate secondary events that fall into some classes with business logic, which in turn generate more events. Then some of the events are ignored by the framework, then some model changes, this model generates events that “the data has changed in me”. There are still five classes that are subscribed to its changes, and in themselves change some kind of state, which depends on the state of this model.
As a result, in three hours you finally build a coherent picture and understand that all the events have very similar names, and there is onclick everywhere. And you need to understand, it's onclick from this button that you clicked or onclick from the next button that you clicked. Because the framework does not prohibit the subscription of any component to any. Those. You can get from someone supercontroller to a button in a specific panel and subscribe to it onclick. And it will just be onclick in quotes. And such cases are very difficult to debug, because there is no unique selectivity of these components. Those. there is a mechanism called ComponentQuery, similar to XPath, in which you can write a RegEx request that says to you: “Find me there all the buttons that are nested in a specific panel with a specific name”. Therefore, when you are trying to refactor something, it is very difficult to find everything, in general, the places where we react to a specific event. Often, this even led to event cycles when the application hangs, because child events constantly appear, it starts processing them, and this cycle is endless. As long as you do not write any tricky if of the type “if this event has already come to me, I do not process it,” then we do not process it further. Those. it's about confusing architecture.
It's okay
And now I have a big question. In the code of large applications with rigid coherence between the logic of view, between the smearing of functionality for different classes and the very poor delineation of areas of responsibility between languages, technologies and other things, what usually is not?
This is how it turned out. And it is not clear, in fact, why it happened. Because, in my opinion, it could be better. But, in short, we checked the Arrays objects, the rest is how it goes. And the eternal story is about the fact that when you start writing tests, you will learn a lot about your application, that in fact you didn’t have to make so many connections, because locking 15 objects to call one function is very hemorrhoidal. And in this regard, have received tests "come on, goodbye."
What are the conclusions? However, such conclusions, of course ...
But in fact, the real conclusions in what?
That the framework is very difficult to understand developers, especially developers who have not previously defended their doctoral thesis on Java. Secondly, the resulting code is very confusing. There are a lot of connections in it, all the classes know each other, and the events that appear are not controlled by anyone, and this leads to firework-shaped explosions of changes in the application's state, when 15 places are subscribed to any state, the events then generate their children. , - … , . , , , JS-, html, CSS . ? … ? 40-60 . « », UI JS- JS-. Those. , , , , .
, — ? , , . . publish/subscribe, mv, , mvc. dependency injection , , …
, , , , , — , , , , , . , , , , , - , .
: , -, API, – . , -, - , JS- - , , , .. .
, , , . - . , . UI .
( ) — , « , ». , , , , , . Those. .
, , - - , - , , - .
, . , ? .
, , PHP, JS , .
And these thousands of frameworks, each of which, like two peas in water, often resemble each other, especially in flux frameworks, are directly “think up your name for the JS point”. And from this hell, where Google Web Toolkit has long died, you must somehow choose. Damn, what to do? Of course, it was necessary to think about something, how to see how others choose something on the Internet somewhere, climb and steal the result somewhere.
As a result, it turned out that I would not be able to figure out the result, I would have to make an honest assessment, because they are all very different. Therefore, a whole big serious presentation was made for the authorities, in which there was an attempt to really and unbiasedly evaluate what, in fact, frameworks all sorts of companies and websites use.
It was about the companies and websites that I cut out the slides from there, just the honest numbers remain. This is the number of lines of code written in general since the advent of Github on different technologies. Plus or minus.
This slide tells about how many reports were made on which technologies at which major conferences devoted specifically to the front, in 2015 abroad.
And everywhere the picture is different.
In this picture, the trend of popularity requests in Google. There are several of them ... Here, if you take a closer look, it is clear that all technologies are actually declining, except for React js and Angular js.
If you take any old more or less Dojo, Yahoo ui and our favorite Ext js frameworks, then everything also goes down. In this regard, no one will fight React js and Angular js, because this is the only thing that goes up.
We further looked at such a study, where 2.5 thousand developers were interviewed, each of whom chose one technology.
This is an American company that makes and sells cloud IDE. The result was such a picture, completely different. Those. those developers who support products, they are still strong, for example, Backbone, which by and large is outdated, but, nevertheless, there are many projects on it that are still being completed.
And this is the Russian market. We tried to assess who we can hire, because it is obvious that we are not working in space, and we need to make products in the company, there are a lot of products and plans — a lot, so someone needs to be hired. Here, in general, the picture is different. It turned out that one way or another with some of the versions of ExtJS (since it is quite long) and with some of the versions of Backbone (since it was also born in 2008), one way or another someone had to deal with. Those. it does not guarantee that this person is ready to do something realtime on this framework right now, but it turned out that among the growing technologies React js and Angular js, Backbone and ExtJS suddenly appeared, and He is, and they are many. There are more jobs on Backbone than with knowledge of React. Here is an amazing picture on the Russian market.
As a result, we all crossed these studies as much as possible and left what we are interested in. They added Dojo there and added ExtJS 6, which they initially wanted to switch to. And Dojo, because it is used by Parallels, with which we are closely integrated, and in which they have something written.
Here five slides were brazenly cut out. I will not talk about why this did not suit us, because the story there is very boring. I will not stop there. If you come to study for yourself, then form a picture for yourself. We evaluated, based on our objectives. One of the tasks was that the technology should be more or less embedded in parts in the existing code, i.e. we do not need a monolithic framework, but rather a set of some methods and libraries that we can slowly add. In this regard, it turned out that Knockout is not a framework at all, but a UI library, Dojo is just a mammoth, and ExtJS 6, although it introduces a new architecture, is actually not much different from ExtJS 4. That is, there appeared some kind of support, better work with mobile devices, but the concept has not changed. There, architecture has become a little better, but for us, as we have estimated, it’s about the same, that we will honestly rewrite architecture on ExtJS 6, just as they suggest that we will redo it on any other framework — about the same cost. As a result, they refused, because the same UI layer, the same publish / subscribe.
There were only two true candidates.
The first one is AngularJS - for obvious reasons, which was also very actively defended by several departments of the company, and some external advisors. But he had a very interesting dilemma. On the one hand, it looked like a really very good solution; on the other hand, I saw a lot of articles on Habré and, in general, on the English-language Internet, where they discuss some conceptual errors made during its design, which lead to everything it would be very cool, but we are confused.
Our own vision of this matter is that if we take version 1, in which we have two projects in our company, and sit-smoke the source code, then this framework has really good modularity of separation into separate pieces, each of which makes its own small functionality - This is very useful and good. But there is no single layout style for files, there is no single style for naming some variables, and there is no single style for formatting code, i.e. This is the thing that I would like to somehow get to the heap with the framework, but the fig will not work. And over time, this layout style changes. Also from myself I would add that there are often places in the code that, in a good way, should be separate classes, but for some reason they are shoved as an object with functions. It is difficult to debug, a lot of tricky "magic", it is very difficult to integrate with some new technologies, because the standards are absolutely all yours ... How to collect this business is also not very clear, but this issue can be solved. But the worst thing is that I couldn’t sell it to the authorities, because we all said that "Guys, they are making a new version, and the code will be incompatible." What to do next is not clear.
OK, they got to watch version 2. Version 2 looks really good at all, like what you need, such a backend-oriented approach, everything is laid out on the shelves, a very good syntax in TypeScript is what you need. But, damn, there is no chance of release, in general, no. I, most importantly, do not understand, this super-mega google corporation, it has been working with python for a long time ... An example of how python moves from version 2 to 3 is just a textbook example of how to do it. It is necessary to maintain the syntax of the old version, you must be backword compatible. And here some hell of a hell is simple. It will be incompatible. “We are doing something new now. Here is the alpha version, for her no shit there is no documentation. When we start, it is not clear and, most importantly, we have another syntax in all three languages. ” Well, zashib, damn it!
Is this a solution? Excuse me, is this a front-end development engine, which is, like, the coolest framework that everyone loves terribly? And what should I do with the admin panel, which four people are currently writing on AngularJS? Come and say: “Guys, you know, we just sit down and rewrite everything. Nothing will be better with us, we are just moving to a new version. ” - “Why are we moving?” - “Well, because the old one was abandoned.” And they, of course, will ask me: “Listen, but there is such a thing as in python, like,“ by 2 to 3 ”. Those. let's set on some kind of parser, and it is reformatting the code for us now, and it will somehow begin to assemble. ” You say: “Sorry, no. Moreover, not only is it not, it will now change everything. Tomorrow we will have another syntax. ” And it is also impossible to sell to anyone. The board of directors will look at me and dismiss me tomorrow. Those. what to do with AngularJS is not clear.
We began to look further, and there was a second decision - this is React JS, which made Facebook. With surprise it turned out that this is not a framework, but only a UI library. It has a very clear understandable structure, it is clearly understood that this is a single data flow, which only receives data, only draws it. Each component is isolated, each component has a declaration of what it receives at the input, what it eventually draws, what it stores inside as an intermediate state. No, in general, some magic filters and other garbage that you need to connect from somewhere, learn and know how it works ... In this respect, everything is as predictable as possible and it is very cool. I liked that there is a very simple possibility of tuning performance - it is clearly understandable how it works, it is clearly understandable how to use it, there is nothing super-complicated in this. There is even server rendering, which we do not need, but it's cool that it exists.
To heap to this was the architecture of Flux, which Facebook is actively moving. We looked at the whole thing, we, as it were, had so-so. On the one hand, the fact that one-way data flow, and the fact that synchronous processing is like that of the state machine, where the clearly defined application state is super. But how the application is divided into independent blocks and how to divide it, as in Angular JS, into some separate entities, is not very clear. Because, it seems to me, there are obviously anti-patterns in the form of the fact that the store stores data, at the same time implements the business logic, also implements the logic of changing these data. Those. This is both a model and a controller at the same time. The idea of ​​a single dispatcher as a single Event Bus with uniquely named events, where you can quickly find in the code, where things have changed, do quick refactoring, and the components work isolated from each other - this is super. But it is completely incomprehensible how the dynamics are provided, how to open, for example, two windows on one screen, which would work independently from each other, but would generate the same, for example, events ...
By and large, Facebook hasn’t released the code, it’s not, it’s not a framework, it’s an architectural idea. Moreover, invented in the 80s, which is called the Event Bus.
OK. Let's look at some third-party frameworks that implement this garbage. I reviewed five of them, they all look like two drops of each other, and they are much worse in this respect than AngularJS, and much worse than Ext JS, because there is almost nothing in them. Yes, it shows better how the architecture works, but there is still no talk about any dynamic creation of stores, their unloading and some linking of UI components between stores, so that parts of the application work isolated from each other and can If two components were created to be the same, with the same view, and two controllers, and they would not fight each other with these events. Therefore, in this regard, with the development of web applications, everything is very strange, i.e. it is often not clear how to do this. But in these frameworks you can see the development of javascript over the past 5 years, in the form of isomorphism, in the form of npm-modules, in the form of library functionality, in the form of ES6 support - this is good. Only, damn, there is no fig, in general, they have no testing infrastructure, and it is not clear how to write a test. Especially with this new hierarchy, it’s not clear how to write a test. And there is no internationalization.
Along the way, we stumbled upon typescript. In this regard, it is, in general, a bomb.
I thought that the most super - remove the excessive creativity of different developers who love to make their own "bikes" - using this is perfectly possible. Typescript is a trans compiler, i.e. You write code that looks like javascript, with the same syntax, just arranging the types. Those. each variable has some type, and they can be complex, a variable can have several types at the same time, and as a result it removes these types, creating a javascript file with absolutely the same syntax, where these types are simply removed, and there are still some useful syntactic substances that meet ECMAScript 2006 standards. just a compiler from ECMAScript 6 to 5.
There, for example, there are such complex data types, when you can make a whole contract, i.e. there are objects with a nested structure, and now you have different parts of the application know in advance that this tricky nested object comes from the API, or, for example, the fields are repeated in it. We use this as a kind of glue between the individual parts of the application, i.e. Everyone writes this business logic, focusing on some kind of interface. When compiling, the compiler immediately checks whether it is possible to compile it, whether you are organizing access to these fields correctly, and whether you have the right type.
Then, there are interfaces. Looking ahead, the framework we wrote is based heavily on interfaces, i.e. we, being guided by the principle of solid, we divide into smaller areas of responsibility and make it so that we have different classes dependent on small interfaces. It turns out we have a larger decoupling application.
Just like in python, there is generic support. There are decorators, as in python, there are generics, as is customary in the C ++ world, and which we actively use. And there are composite types. In rare cases, it can be said that there can be either a string or a number in this variable, when this cannot be avoided. He also works fine with it.
As a result, after this research questions only became more. What architecture to choose? What is the right decision? How to keep up with the development of javascript, in the form of ECMAScript 6? Where can I get the library of UI components?
And in this regard, Ext JS is very active in hitting, it all has it. It has its own build, it has an internationalization mechanism, it has a clear architecture and so on. Those. what happened then turned out strange, but there is no alternative. Well, as if, it is, but it must be done by yourself. As a result, we want a framework with Typescript, everyone wanted at this moment a framework with Typescript. Without - no one wanted.
Well, what to do? Let's write the task for ourselves. JS coders must write code. Layout designers should design and communicate with designers. Obviously, you need to make the UI layer as simple as possible so that the designer can figure it out and make it clear to the programmer without creepy inheritance of CSS styles at three or four levels without creepy component inheritance. You need to make a clear and understandable architecture, a code that is roughly comprehensible to backend developers, and you need a separation of areas of responsibility - separate layout, separate code, separate controllers, separate data storage, try to cram the state of the application into one of some type of classes, calling it a model. And, most importantly, more boundaries, rules and standards: naming, formatting code, layouts for files, the whole thing. And while on Typescript. And while still so that this whole thing was not a monolithic framework, because the whole thing will need to be introduced into the existing code.
We end up with a framework called Este.js. He does not tell you anything, he was the most revolutionary and innovative. Smoothly rewritten, until nothing was left of him.
As a result, there were several problems.
The first problem. It turns out that the store is a kind of anti-pattern during flux. In practice, we have nothing good to do with it. We ended up sharing them back into classes that store data and can change them, and separately the business logic in the controller. This is about the same as where flux is currently developing, when they have separate objects with the state. We have this object with a state just called store.
It was like this.
It turned out like this:
Those. isolated blocks, about the same as in AngularJS, with the same mechanism, in the form of modules. In each module there is one or more of its own stores, which communicate with one of several controllers. And in the end, the whole thing works separately from the view. View only reads the data of the stores and generates certain actions that the single dispatcher scatters (in fact, not one, each isolated block can have its own) between the controllers, each of which subscribes to events and decides, he responds to this event or not. As a result, our application works as a set of applications nested in each other, each of which is inside flux. This is a hierarchical MVC, where the views are simply nested and the controllers are isolated.
The second problem is that Facebook suggests doing templates like this:
Of course, we suffered for a long time, we realized that this is not an option at all, and we shoot ourselves in the foot. I absolutely do not understand why I need to mix a bunch of JS-code, curly brackets, round brackets, logic, and all together in the UI component, when, by and large, the essence of the UI component is that it takes some kind of template and renders it in the browser. We looked at such a project as wix-react-templates, wrote our own, very strongly similar. But there is no code in it. Only there are blocks that provide iteration, if, then, else and variables, nothing else. Those. the task of the component is to push in this variable in advance what will be displayed in it. And the task of the component is to specify how many times to iterate which block with which data. This is what the template looks like:
This is how we wrote our own parser of these templates, which makes a DOM tree from it and generates such templates, much the same as their JSX:
Here, this case is automatically generated, and React is working with this case.
And the essence of the UI component is that it declares certain props, declares certain states, and in the simplest way pushes these props into blocks and variables. They built a kind of tree, which is then rendered.
For translations we did a little thing that bit the text out of these templates and generated a file for us. We translate this file into Russian with pens. You can add some kind of layout there. Notice there is a span added in the last line. We are laying this case for the pluralization of words.
, , , span .
, Facebook , , . .
What is the result?
, , , java. dependency injection, , — React lodash. — , , MVC — MVC. React. web-pack…
— Ext JS 6, React. , , , , . , - .
— , , , - , , , , json rest, , API .
:
, , , , flux + react 2- 5- . , UI , ExtJS, , , , , .
, . , , , 60 , 15 — , - , , , -, — .
. react', - 4 .
, 10 , , 2 . 4 2 - UI , .
, , , , UI . , « » « , ». , , , , . , UI Ext JS, , - , - - , , , - . , , , , .
So the essence of the report, as always: overcome difficulties; bicycles, bugs, crutches - do your all. Do your thing, because your team now has the technology and expertise in how it works. Those. we read the source code of react'a and, finally, we understand how he, damn it, works.
This report is a transcript of one of the best speeches at the conference of developers of high-loaded systems HighLoad ++ . Now we are actively preparing for the conference in 2016 - this year HighLoad ++ will be held in Skolkovo on November 7 and 8.
Also, some of these materials are used by us in an online training course on the development of high-load systems HighLoad.Guide is a chain of specially selected letters, articles, materials, videos. Already, in our textbook more than 30 unique materials. Get connected!
Source: https://habr.com/ru/post/311096/
All Articles