Later, Ajax appeared, and we were no longer limited to the content delivered by the initial request. Instead, we could fetch additional data on demand by consuming various endpoints. That opened the way to create vast interfaces with not only a dynamic structure but dynamic data too.
The history of DOM manipulation
That is the philosophy behind a scripting language in web development. Nevertheless, a problem reveals itself when we scale the application up and do not control the clarity of the logic. This direction seems inevitable because systems tend to become more complex as time goes by.
The problem I am referring to may go like this. We handle some user interaction that changes two related places, and those may be a state or DOM elements. Then, another interaction also changes two associated places, where one is related to the first interaction and the second one is not. In this case, the second interaction may break the integrity of the states that the first one established; it is also true the other way around. That kind of situation may result in an illogical state or an incoherent visual representation. The main reason for this is that logics of those two modification do not know about each other regardless of interacting with the shared state. It is often not easy to spot that kind of relation, which is the first step toward more significant trouble.
Going further and adding an extra layer of dependency, we may observe one state change and act upon it changing another state. That will make the relationship between them even harder to find.
Furthermore, we may add asynchronous logic by consuming endpoints, which changes the state in a nondeterministic manner. All in all, our application becomes challenging to debug very quickly, and when you scale this design up, you end up with a nightmare.
HTML vs. JS
It became evident that implementing more extensive applications in an imperative way is cumbersome and requires a lot of care from the programmers. All things considered, it turns out to be a very pricy approach requiring the maintenance of an extensive codebase. It seems like we have to come up with an alternative.
What may be a valuable substitute to the static markup alongside a scripting language selecting elements and explicitly changing them? Well, the different option to the imperative approach is, as you may guess, the declarative one.
The core of the declarative paradigm, in the web development world, is to define how a given state should render its visual representation using presentational entities — components.
Declarative front-end abstraction
Long story short, there are various solutions to implementing functional paradigm and introducing proper abstraction to create scalable web applications. Eventually, we end up with components that accept some attributes and render the presentation layer.
Because this is an abstraction, a lot is going on under the hood. For instance, we may need virtual DOM or update functions that await all renders that our components produce and then apply required changes to the actual elements. This implementation is undoubtedly an imperative logic, but the programmer does not see this. In this case, all one cares about is the high-level functional concept.
Let’s get back to our problem with explicit state modification by user interaction logic. Well, in a declarative way, we are truly protected from the whole category of errors.
First of all, the state may be in one place, representing the single source of truth, and the visual depiction is just a pure representation of that state. The top-down data flow provides deterministic outcomes, so the same state always renders the same result.
Second, the interactions happening in pure components do not change the state directly but rather trigger the callback passed as an attribute. Thus, the update logic resides only in one place, preferably next to the state itself.
Because of those two design decisions, we are not afraid of complex updates and render logic. Debugging a declaratively designed application is pretty straightforward. There is one place to monitor essential changes and an easy way to validate render relations.
In recent years, web development went a long way to simplify the construction of complex web services. All of this was possible because we were able to introduce valuable abstractions. It seems that the evolution of front-end frameworks and visual libraries based on a declarative paradigm brought great benefits and allowed to solve problems that programmers experienced before it.
Various solutions are evolving today, trying to incorporate useful features into the declarative design. It is difficult to predict the future changes in web development, but I think that higher-level abstractions and the functional approach will lead the way.