StateController. An event model in the development of interfaces. Part 1

Introduction
Now more and more JavaScript frameworks are appearing, which are slightly different from the now fashionable jQuery. Some try to implement MVC, others provide a highly coupled architecture, others are aimed at asynchrony, and so on. Each developer chooses what is closest to him and which most effectively solves the task. Therefore, I will not discuss the advantages or disadvantages of frameworks, but tell you what we came to in our products, what concepts were developed and what problems were solved.
I'll start, perhaps, with the task. We built SaaS, an information-analytical system that handled substantial amounts of data. The user could receive a fairly large amount of information in one request, but at the same time he could refine certain blocks of information, moving to an even greater level of detail. If we built the classic scheme of a multi-page application, we would get a sad speed of data retrieval from the database, a large amount of transmitted traffic, but most importantly, we would not satisfy the needs of the market, which required as little time as possible to wait for a response to requests. Therefore, we have chosen a model for building a one-page application, when the data is loaded on demand and only those pieces that the user needs at a given time. They killed three birds with one stone.
Single Page Approach Issues
Such an application requires a special approach to organizing code. Some standard solutions, familiar to the world of multi-page applications, get out sideways with a single-page approach. Imagine that a user, using the program for its intended purpose, after a while has loaded a total of 10,000 tags into a document. The jQuery approach (choose the one you need from the whole document) can cause serious degradation in the speed of work. Of course, you can reduce the visibility of the selector, but this is not always possible, and requires additional painstaking optimizations.
Another approach that required revision was the model for constructing the module itself. I tried to get away from MVC with regard to HTML, because it required a significant amount of work with very questionable efficiency. Modules should be loosely coupled, not have any means of direct communication with each other. Where to store data? Why not use HTML for this! DOM provides smart and convenient tools for working with data structures, in fact, being a ready-made Model.
It remained to find the "threads" with which all this should be sewn together. The only option that occurred to me was to use the event model. This is how StateController v2 came about.
How does the event model work?
It is built on two main components: handlers and event generators. Events themselves can be impersonal and named. An example of an impersonal event is a call to a function or method.
foo(1)
You call this function because you need to perform some action or get a result. Although we can formally name the event as “perform an action” or “get a result,” however it does not appear explicitly anywhere. A handler is a function or method that is called.
An example of a named event is
click
. Everything is clear, familiar, familiar. The generator fires a certain event to which some handlers respond.Structural-event model of the application
The desire to get away from the classical MVC in JS, together with the requirement for weak intermodule communication, led me to the following conclusions: The
best data warehouse is a DOM structure
In order not to make unnecessary data synchronization between JS and HTML, we modify directly with the DOM structure. If you still need data in the form of JS-objects, we collect them at the time of calling the methods in temporary structures, then we throw them out. At first, this seems somewhat illogical, because you have to collect information for each sneeze, but maintaining the consistency of shared data will cost more. Especially in single-page applications, where there is no guarantee that in the given moment of time in this place some other DOM branch will not appear, which one of the modules has loaded at the request of the user.
The best connection between modules is events. It is
much simpler to teach modules to generate certain events than to link their handlers with each other, so that when modifying data with one module, automatically carry out all the necessary actions in related modules. A kind of polymorphism, a single API of communication.
Nodes as carriers of handlers
Shifting the “responsibility” for the actions performed to the final nodes of the DOM tree, we get another abstraction - scripts. No one knows better than a specific node what to do in certain cases. Thus, the structure of the DOM document carries the logic of work. Here lies the most basic difference in the approaches of event and selective framework models.
The logic of developers who work with a selective approach is approximately the following: select the necessary nodes and perform a specific set of actions with them. The logic of the event approach: someone must perform a certain set of actions, because the system has changed state.
It seems not very different, you say. Let's solve the following problem. We have three elements of the form: registration address
(ra)
, address of residence (la)
, checkbox "Address of residence coincides with the registration address (ch)
. " By default, the checkbox is in the marked state, the address of residence is hidden. If the user unchecks, we show him the field with the address of residence. When you turn off the checkbox, the input form is not only hidden, but also cleared of user input. Nothing complicated.An abstract implementation using a selective technique will look something like this:
- Hang a handler
click
onch
that will do 2 - If the state is checked, then 3, otherwise 5
- Show la
- Output
- Hide la
- Clear la
- Output
An abstract implementation using the event method will look like this:
- Hang an event handler
click
onch
that will do 2 - If the state
checked
, then 3, otherwise 5 - Trigger event
equal_data
- Output
- Trigger event
not_equal_data
- Output
- Hang a handler
equal_data
onla
that will do 2 - Hide node
- Clear form
- Output
- Hang a handler
not_equal_data
onla
that will do 2 - Show node
- Output
At first glance, the second implementation seems a bit more complicated. But let's look at the "resistance" of the code to modifications. What will happen to the first code block of each approach if we need to add some additional action, for example, to show some contextual help, the text of which differs when the checkbox is active and inactive. We will have to go to the handler and add the necessary actions with the selective model and do nothing with the event model. Even if there are one hundred edits, the first block of the event approach implementation will not change, because it is abstract and contains a execution script, but not specific actions. In practice, this is expressed in several goodies.
Positive moments from the event approach
Testing time is reduced, because when editing, the basic logic of work does not break, only handlers are added, and vice versa, handlers are not dependent on script changes.
KISS principle in action. The script is easier to read than the final implementation code. If the handlers are made "dumb" so that they perform some specific actions, then it is much more difficult to make a mistake in them. And the portability of the code is very impressive, the handler libraries wander between projects, sometimes together with scripts.
Negative moments
Entry Threshold. Reading specific directives is much simpler than tracking the entire path of an event and the consequences of running a script. For an unprepared developer, the code of the event model is more like magic, something comes from nowhere and disappears somewhere.
There are tasks that can be easily solved by the selective method, but not the fact that it will come out similarly with the event approach.
In the next article I will move closer to practical implementation.
Part 2
Thank you for your attention!