Advanced JavaScript Application Architecture

In today's world, it's very common to see web applications implemented on client-side, meaning most of the application's logic runs in the browser. This is possible because we have such a wonderful programming language as JavaScript, and also because all modern browsers are built with the ability to host literally full-fledged applications in them.

JavaScript applications (or applications built to run mostly in the browser) have become very popular, and I have a feeling that the demand for them is going a bit ahead of the techniques and approaches used by developers who build such applications. I don't have a problem with any concrete application built using JavaScript, I just have specific vision as to where this momentum will take us eventually. Specifically, in terms of architectures of complex applications. That's what I will cover in this topic.

 

Typical JavaScript Application Architecture

Typically, JavaScript applications are built from bottom to up - first we have some kind of screen mock-ups or prototypes; next those screens are hooked up with code which takes care of screen manipulations, data creation, updates, deletion, and so on. In short, user interface stands in the center of the development at all times. This is absolutely fine, since such software is built to meet the expectations of the users who interact with the application's screens. However, this focus is not exactly helping developers to make right decisions about application's architecture overall.

The above drawing is showing the final architecture of most of the JavaScript applications built to date. Quite simplistic picture, and for simple applications this is perfectly acceptable. Complex applications though, cannot benefit from such architecture long term. With the complexity growing continuously, this kind of simplistic architecture cannot handle the demands that mature applications face, such as separation of concerns, layering, SOLID code, unit-testability, maintainability, extensibility, and so on. If these challenges are not identified and solved at early stages of development, with the complexity growing and deadlines shrinking, the task of adding more capabilities to the application may become too costly in terms of resources, schedule, and budget. I highly recommend to avoid these issues by making upfront investment into research and implementation of better JavaScript architecture, which long-term will pay back by keeping your work feasible and fun.

 

Framework-based Typical Architecture

Since the world realized there is a demand for more mature JavaScript applications and architectures, many frameworks have evolved to solve this problem. They help in many ways - provide simplistic or readable HTML markups by parsing them for you; render and transform the HTML markup in many ways with simple code blocks; integrate seamlessly with server-side handlers. Basically, they have made breakthrough by further detailing the above simplistic architecture.

Above drawing shows where this all advancement is at this point. In short, this is the result of applying either MVC or MVVM pattern to the application. And indeed, most of the popular JavaScript UI frameworks advocate for one of these 2 application patterns.

While UI screen is still the focus of the final delivery, Code behind part (Controllers of MVC, or ViewModels of MVVM) are now more advanced. They not only separate behavioral concerns from presentation concerns, but they also provide many values, such as encapsulation of business logic away from UI screens, unit-testable code blocks (Controller or ViewModel is unit-testable), maintainability, and so on.

Many application developers and architects have taken frameworks which recommend such architectures, and have done a great job implementing their software. I must say that this is an achievement of both the framework authors as well as implementers of the specific projects, who have proven that such approaches work just fine. This is true and will stay true for many JavaScript applications.

In the next section, I want to demystify the framework-based typical architecture, which will help me in explaining how I think the complex JavaScript applications should be architected.

 

Advanced Architecture - Deja Vu

This section is not claiming that there is something wrong with the above typical application architectures. Instead, I want to suggest more advanced approach for consideration, only for complex projects that would not feel so comfortable with the above architectures and would look for something even more mature.

Let's try to see what is so good about the typical framework-based architectures. Effectively, they bring a traditional application architecture flavor to the table. These flavors called MVC and MVVM have been used in software for quite some time and with great success. It was obvious that with the maturity of the browsers and with them the demands for JavaScript, these patterns would be adapted here too. So, what we see is just the first step of JavaScript becoming a full-fledged application platform.

Now, let's try to see where the catch is. Problem is, JavaScript applications go just this far and then keep implementing advanced needs within this same framework architecture, by squeezing complexity into this simple approach. In other words, JavaScript applications end up being based solely on UI architectures, and thus they start having same problems as any other UI software on other platforms - after having only MVC or MVVM implemented. Specifically, domain knowledge is bloated everywhere in code behind; controller or viewmodel becomes the drive and house of business use cases, while manipulating model or view directly; and model (if it at all exists) is just a plain json object without any logic in it. And since controller or viewmodel is now focused on so many concerns - at least interacting with the server as well as manipulating view directly or indirectly - this whole architecture quickly becomes incapable of growing without hurting maintainability and further development costs. Uncovering these issues happens only late in development, when the team is ready to admit that the complexity has exceeded the design's maturity.

If your JavaScript application's use cases seem to be complex, you need to plan for advanced architecture, which is more focused around domain knowledge, and which suggests better separation of classic application layers and responsibilities.

As you see in the above drawing, I have squeezed the typical framework-based architecture completely and have called it just UI layer, because that's what it is (Code behind, either through Controllers or ViewModels, is still purposed to control the screen, rather than to control the business logic). UI layer - through its Controllers or ViewModels - can directly talk to Domain layer, or can do it with the help of the optional Service layer. Service layer is a collection of Facades performing different use cases for the UI layer, so it may or may not be necessary based on the complexity of those use cases. Domain layer is the house of business logic, which holds business objects and Repositories. Business objects are not just plain json objects anymore, they are the entities that encapsulate business behavior and state in them; Repositories provide traditional capabilities for retrieving and storing the business objects. They are implemented so that they retrieve data from the server, by using Ajax calls. Repository operations should be asynchronous for compatibility with Ajax (JavaScript is full of closures anyway, which looks like Ajax already, so nothing new or complex in here). Repositories retrieve json objects from the server and map them back to the business objects.

This architecture provides all the benefits of the full-fledged applications, such as:

  1. Layers are separated, so it's possible to focus on business concerns in separation from the UI concerns.
  2. Business logic is completely unit-testable, and thus can be as stable and reliable as we need.
  3. Business logic can be extended with new capabilities without affecting the existing UI screens.
  4. UI layer consists of both code behind (MVC or MVVM) and UI screens, so none of the existing benefits are lost, when comparing to the typical framework-based architectures.
  5. Finally, UI layer's Controller and ViewModel is not the center of the domain logic anymore; instead, code behind (Controller or ViewModel) just maps domain logic into UI screens; so UI layer has become much easier to maintain and to further extend with less code and less complexity buried into it.

As you can see, nothing extraordinary. Maybe you have even seen such architecture implemented in other platforms, that's why you would call it Deja Vu.

 

Conclusions

Just to recap, for simplest applications such as prototypes or very small projects, you should still go with the typical architecture, without involving any special frameworks. For applications of medium complexity, you should go with so famous approach which I described as typical framework-based architecture. And for complex applications, you should be taking one step further by implementing them using advanced JavaScript application architecture, which was the focus of this topic.

 

Share If You Like It