© Luca Mezzalira 2018
Luca MezzaliraFront-End Reactive Architectureshttps://doi.org/10.1007/978-1-4842-3180-7_2

2. Architectures Comparison

Luca Mezzalira1 
(1)
London, Surrey, UK
 

If you think good architecture is expensive, try bad architecture.

—Brian Foote

In this chapter we are going to explore the current status of front-end architectures . When we pick a framework for our projects, someone else made decisions for us on how to structure an architecture following best practices and design patterns for giving us the freedom to make design decisions, focusing mainly on what our applications should achieve more than how to structure them.

It’s important here to highlight the difference between architecture and design because often these terms are misunderstood.

When we talk about architectures, we are defining how our system is going to interact between different elements. For example, think about the communication between a model and a view. Usually when we define architecture we are defining the relationship between objects, how they communicate between each other, and so on. Architectural decisions are hard to change because they usually drive a project in a specific direction, which would require a huge effort for moving it in a different direction.

Design decisions , instead, are local decisions like choosing a specific library, algorithm, or design pattern for solving a problem in our project.

When we make a design decision on a project, it often doesn’t require a huge effort recovering from it, but in certain situations making poor design decisions will lead to a long refactoring of our system. Let’s assume we need to solve a problem where every few minutes we need to refresh the data inside a specific view without refreshing the entire page but only the elements that need to change; we could decide to use React.js for its diff algorithm or create our own algorithm where we could have more control defining a diff algorithm close to our needs.

Sorting out the difference between architecture and design decisions , it’s time to see what we are going to explore in this chapter.

The front-end ecosystem is in continuous evolution, in particular in the past few years where we were experiencing different but fundamental changes that are improving the creation and maintainability of our projects.

We are probably living the most exciting decade of the past 10 years, overwhelmed by revolutionizing concepts that are often coming from the past but with a new twist, transforming them in useful ways and taking actual approaches for solving our daily challenges.

The front-end architectures changed a lot in the past 30 years, as we moved from the classic Model View Control (MVC) to more actual architectures that nowadays are present in many contemporary frameworks.

This could be a representation in a timeline of this evolution. During this chapter we are going to see in action the most famous architecture and we are going to compare them.

Figure 2-1 shows a timeline where I highlighted all the architectures and implementations we are going to explore and in what year they were created. You will see that many concepts from the 1980s or ‘90s are very contemporary and used in the most famous framework implementations currently available in the JavaScript ecosystem.
../images/446957_1_En_2_Chapter/446957_1_En_2_Fig1_HTML.jpg
Figure 2-1

Architectures timeline

The most important thing to remember is that these architectures are not obsoletes but that they are still valid concepts to use, and they can add a lot of value to our projects by drastically facilitating the development and maintenance of them. Creating well-structured and flexible architectures also provide us the agility needed to embrace not only design changes but architectural ones as well.

Also, we need to bear in mind that these architectures can be converted to Reactive architectures if we apply the Reactive concepts in a proper way; therefore if our project is currently using one of them, we can still embrace the Reactive model, applying a few changes to enhance them and moving to a more reactive paradigm.

MV* Architectures

In this section, we are going to dig into the base concepts of MV* architectures ; in order to do that we will work on a simple project (a basic calculator) for understanding how these architectures are composed, and how objects are communicating by embracing the SOLID principles that any project should take in consideration in order to be maintainable and extensible.

The three architectures we are going to explore in this section are MVC, MVP, and MVVM; let’s start with the oldest one, MVC!

S.O.L.I.D.

SOLID is a set of principles created by Uncle Bob. SOLID is an acronym that stands for:

S – Single-responsibility principle

O – Open-closed principle

L – Loskop substitution principle

I – Interface segregation principle

D – Dependency inversion principle

If you are interested in knowing more about them, I suggest watching this Uncle Bob lecture: https://www.youtube.com/watch?v=t86v3N4OshQ

Bear in mind though, that all the code presented in this chapter are just highlights of the final examples; therefore if you have a hard time following the snippets, feel free to download the chapter examples first and switch from this book to your favorite editor or IDE for consulting the code.

Remember first to install all the dependencies with the command:

npm install

And then you can run the n.p script called build in this way:

npm run build

Model View Control

Model View Control (MVC) is an architectural pattern introduced in Smalltalk in the late 1980s by Trivet Reenskaug, and it is probably the most popular architecture of the past 30 years, used by millions of developers in any project independently of the language used (Figure 2-2).

Its main characteristic is the separation of concerns and the single responsibility of its actors; the main innovation of this pattern was finally separating the data from their visual representation, a concept not fully explored until then.

In fact the model objects are completely separated from their representation; therefore there isn’t any knowledge of the view inside the model.

This detail becomes important when multiple views or controllers are accessing the same data because our model objects could be reused across different screens without any problem.

MVC is based on three basic principles :
  • Model: where the application state and domain data live

  • View: the user interface of our applications interacted on by the users

  • Controller: the glue between the model and the view, usually responsible for orchestrating the communication flow inside the application

../images/446957_1_En_2_Chapter/446957_1_En_2_Fig2_HTML.jpg
Figure 2-2

Model View Control diagram (MVC)

How MVC Works

Usually the controller instantiates the view and the model in the constructor or, in certain implementations, are injected by the main application class via dependency injection. The relation between a controller and the views could be one to many, so a controller could handle multiple views: the same relationship is valid for the models as well.

When we want to scale up this architecture for large projects usually we try to split up these relationships in order to have almost a 1 to 1 relation between these three objects so we can reuse components that are self-contained and architected in the same way the entire application works, like a Russian doll.

As described before the main aim of a model is storing the application state and everything that should be persistent across a single or multiple views, usually every time the application state changes or data are updated; the model is triggering an event in order to update the view.

In the vast majority of implementations the object listening for any state or data change is the view, but in certain implementations we can also find a total separation between the model and the view where the controller in this case is listening to the change and is propagating this information to the view.

The view is simply responsible for displaying the application data and listening for any user interactions.

Figure 2-3 shows how MVC works with an implementation of a calculator in JavaScript.

This is the final result of what we want to achieve.
../images/446957_1_En_2_Chapter/446957_1_En_2_Fig3_HTML.jpg
Figure 2-3

This is the output of our Calculator application

It is a simple calculator where every time we are clicking a button, we add the value on the display on the top and when the user is going to click the button “=” we will display the result.

Let’s start to explore our MVC example from the controller. See Listing 2-1.

initialize(){
        const emitter = this.initEmitter();
        this.model = this.initModel(emitter);
        this.initView(emitter, this.model);
 }
Listing 2-1

CalculatorController.js

In our implementation, the controller is going to instantiate the view and the model, and it’s injecting an event emitter for communicating between objects via events. This will immediately improve the decoupling between objects because if in the future we want to reuse some of these objects in other projects, we won’t need to copy more than the object we are interested in, considering they are communicating via events, and as long as we respect the contract our code becomes reusable and flexible.

We are going to use React.js for handling the views of our project.

React usually renders the components again when there is a properties update, but in our case what we implement is using the event bus for notifying the view that a new result should be rendered on the calculator’s display, and then the view will retrieve the data from the model, updating with the new string the display.

In order to do that, we need to inject the model and the emitter instance inside the view. See Listing 2-2.

initView(emitter, model){
        const cont = document.getElementById("app");
        ReactDOM.render(<Calculator emitter={emitter} model={model} />, cont);
}
Listing 2-2

CalculatorController.js

Then we will use the React Component life-cycle methods to store these two objects locally and listen for any change from the model; when a change happens, we are going to update a state property inside the React component to display the correct value. See Listing 2-3.

componentWillMount(){
        this.model = this.props.model;
        this.emitter = this.props.emitter;
        this.emitter.on("TotalChanged", _ => this.setState({displayValue: this.model.total}));
        this.setState({displayValue: this.model.total})
}
Listing 2-3

Calculator.jsx

So, every time the displayValue property is updated, this will trigger the render function; therefore the view will be updated with a new result as shown in Listing 2-4.

render(){
        return(
            <div>
                <div style={displayStyle}>{this.state.displayValue}</div>
                {this.createRow("row1", "AC")}
                {this.createRow("row2", "7", "8", "9", "/")}
                {this.createRow("row3", "4", "5", "6", "*")}
                {this.createRow("row4", "1", "2", "3", "-")}
                {this.createRow("row5", "0", ".", "=", "+")}
            </div>
        );
  }
Listing 2-4

Calculator.jsx

Inside the model instead, we are going to keep the application state, handling what should be displayed in our view and performing some calculations.

Our model is composed by a few methods that will allow the controller to call every time a button is clicked from the Calculator keyboard as you can see in the following code in Listings 2-5 and 2-6.

initEmitter(){
        let emitter = new LiteEventEmitter();
        emitter.on("CalculateEvent", _ => {
            this.model.calculate();
        });
        emitter.on("AddValueEvent", content => {
            this.model.addValue(content.value, content.type);
        });
        emitter.on("ResetEvent", _ => {
            this.model.reset();
        })
        return emitter;
 }
Listing 2-5

CalculatorController.js

calculate(){
    this.totalOperation = math.eval(this.totalOperation);
    this.state = FIRST_OPERATION;
    this.emitter.emit("TotalChanged");
}
addValue(value, type){
    if(type === NUMERIC){
        this.totalOperation = this.getValue(value);
    } else if(type === SYMBOL){
        this.totalOperation = this.checkSymbol(value);
    }
    this.state = IN_PROGRESS_OPERATION;
    this.emitter.emit("TotalChanged");
}
reset(){
    this.totalOperation = 0;
    this.state = FIRST_OPERATION;
    this.emitter.emit("TotalChanged");
}
Listing 2-6

CalculatorModel.js

The Controller, via the emitter object, is listening for any event triggered by the view and it is requesting to the model to perform some operations like reset, calculate, or add a new value.

The model, instead, every time totalOperation value is changing it, notifies via the event bus our view that will display the new value updating the state property of our React component, triggering then the render function.

MVC is a pretty simple and straightforward pattern: there is a good separation of concern, each object has a unique responsibility, and all the information is well encapsulated.

Model View Presenter

Model View Presenter (MVP) is an architecture created in the 1990s, and one of its first appearances was made in IBM software (Figure 2-4). From my point of view, MVP shines when we need to reuse views or behaviors in different projects or different areas of the same application; with this architecture we start to give more importance to the modularization of our front-end applications and provide architecture specific for a front end more than a generic one that could fit a back-end or front-end application like for MVC.

MVP is very helpful, in particular, when we work on cross-platform applications and we want to reuse the application data, communication layer, and behaviors or when we want to swap the views changing them at runtime or compile/transpile time.

The main differences between MVP and MVC could be summarized in the following list:
  • Having a presenter instead of a controller, we will see in a moment which benefits come in with a presenter.

  • The relation between a view and a presenter is not 1 to many like in MVC but is always 1 to 1.

  • The best MVP implementation for having reusable components is when we design our views as passive views because swapping them becomes easier as long the contract between the presenter and the view is respected.

../images/446957_1_En_2_Chapter/446957_1_En_2_Fig4_HTML.jpg
Figure 2-4

MVP diagram where the view is unaware of the model’s existence

How MVP Works

The presenter object is inspired by the presentation model pattern, and my favorite implementation is when the presenter is designed as a Supervising Controller where it retrieves all the data useful for a view from the model, and at the same time it should handle any user interaction updating the model. As mentioned before, the views are passive or if you prefer dumb, they just know how the rendering logic works, possible animations, integration with CSS styles, and so on.

On top, the presenter is also dealing with updating the model and retrieving the information needed for rendering a view. Usually, in complex applications, you could have a persistent model (or more than one model maybe exposed by a façade) across the entire life cycle of an application and multiple presenters that retrieve and update the application data in the models.

Another important point to highlight is the fact that the model and the view should not be aware of each other; maintaining these two completely isolated from each other will help a lot in the case of large applications or when we need to swap views for targeting different devices.

Imagine for a moment that our assignment is a project where we need to target different devices like browsers, mobile, and smartTVs – exactly the same application but different UI for different targets considering that each target has different input methods and UI patterns.

With an MVP architecture, maintaining the behaviors inside the presenter, the business domain in the model and having just passive views for the UI will allow us to have similar behaviors across the application, reusing the same code for the models and changing the views – adapting them for the device we are targeting without much effort.

Passive View

A passive view is a view without any knowledge of how the system works but just relying on another object for handling the communication with the system. A Passive view doesn’t even update itself by retrieving data from the model; this view is completely passive, and its main scope is focusing on what to render on the screen when a specific render function is called from a controller or presenter.

Supervising Controller

A supervising controller is a specific type of controller that is handling user interaction as well as manipulating the view for updating it. When a supervising controller is present in an architecture, the view needs only to redirect the user events to the supervising controller (in MVP the presenter is our supervising controller), and it will take care of handling the logic and updating the view with new data.

The supervising controller is responsible for the communication in the system and it’s taking care to update the view it is associated with.

It’s time to see MVP in action with the Calculator example discussed above, but this time with the Model-View-Presenter in mind.

We can start from the App.js file where in the constructor we are going to create the model and the presenter, and we import the view called Calculator.jsx.

We then inject React component and model inside the presenter as shown in Listing 2-7.

export default class App{
    constructor(){
        const mainModel = new CalculatorModel();
        const mainPresenter = new CalculatorPresenter();
        mainPresenter.init(mainModel, Calculator);
    }
}
Listing 2-7

App.js

Then we can move inside the presenter where we are going to store all the objects injected in variables and then we render the React component injected. See Listing 2-8.

initialize(model, view){
        this.model = model;
        this.view = view;
        this.cont = document.getElementById("app");
        this.renderView();
}
renderView(){
        const component = React.createElement(this.view, {result: this.model.total, onBtnClicked: ::this.onBtnClicked});
        ReactDOM.render(component, this.cont)
}
Listing 2-8

CalculatorPresenter.js

In our Presentation model we are injecting the model and the view for having complete controls on them; we then call the method renderView that will be our trigger for communicating to a React component to render again because something happened inside the application and the UI should be updated.

As you can see, the view doesn’t have any knowledge of the model but we pass the result to display in our calculator via the props object exposed by React.

Now it’s time to take a look at the view; and as we defined at the beginning of this section, the view should be a passive view, so in this case it is taking care of what to render and how nothing else should be integrated in a passive view.

The communication with the presenter is happening via a method passed via the props object. Like we have seen in the renderView method, the presenter is passing a callback that should be invoked every time the user is selecting a button of our calculator. See Listing 2-9.

import React from "react";
import ReactDOM from "react-dom";
import {ulStyle, acStyle, btnStyle, displayStyle} from "./Calculator.css";
export default class Calculator extends React.Component{
    constructor(props){
        super(props);
    }
    componentWillMount(){
        this.btnClicked = this.props.onBtnClicked;
    }
    onButtonClicked(evt){
        evt.preventDefault();
        this.btnClicked(evt.target.innerHTML);
    }
    createRow(id, ...labels){
        const items = labels.map((value, index) => {
            return <li key={`${id}_${index}`}
                       style={value === "AC"? acStyle : btnStyle}
                       onClick={::this.onButtonClicked}>
                       {value}
                   </li>;
        })
        return(
            <ul key={id} style={ulStyle}>
                {items}
            </ul>
        )
    }
    render(){
        return(
            <div>
                <div style={displayStyle}>{this.props.result}</div>
                {this.createRow("row1", "AC")}
                {this.createRow("row2", "7", "8", "9", "/")}
                {this.createRow("row3", "4", "5", "6", "*")}
                {this.createRow("row4", "1", "2", "3", "-")}
                {this.createRow("row5", "0", ".", "=", "+")}
            </div>
        );
    }
}
Listing 2-9

Calculator.jsx

All the methods present in the React component are defined for rendering the correct button or the display, and this.props.onBtnClicked is the method passed by the presenter.

This method is identifying which button was selected so the presenter can capture the user interaction and it calls the correct method exposed inside the main model as you can see in the snippet below in Listing 2-10.

onBtnClicked(value){
         switch (value) {
            case "AC":
                this.model.reset();
                break;
            case "=":
                this.model.calculate(value);
                break;
            case "+":
            case "-":
            case "/":
            case "*":
            case ".":
                this.model.addValue(value, SYMBOL);
                break;
            default:
                this.model.addValue(value, NUMERIC);
                break;
        }
        this.renderView();
}
Listing 2-10

CalculatorPresenter.js

It’s time to see what the model is doing; in this case the model is taking care of all the calculations and maintaining the application state. That will facilitate the debugging of our application because we know that the view is dealing merely with the UI of our application, and the presenter is handling the user interactions and the model keeps the application state and the caching of application data.

Let’s take a look to the model shown in Listing 2-11.

export default class CalculatorModel{
    constructor(){
        this.totalOperation = 0;
    }
    calculate(){
        this.totalOperation = math.eval(this.totalOperation);
        this.state = FIRST_OPERATION;
    }
    addValue(value, type){
        if(type === NUMERIC){
            this.totalOperation = this.getValue(value);
        } else if(type === SYMBOL){
            this.totalOperation = this.checkSymbol(value);
        }
        this.state = IN_PROGRESS_OPERATION;
    }
    checkSymbol(value){
        const str = this.totalOperation;
         if(this.state === FIRST_OPERATION){
            return str + value;
        }
        return !isNaN(str.charAt(str.length - 1)) ? str + value : str.substr(0, str.length - 1) + value
    }
    getValue(value){
        return (this.totalOperation == 0 || this.state === FIRST_OPERATION) ? value : this.totalOperation + value;
    }
    reset(){
        this.totalOperation = 0;
        this.state = FIRST_OPERATION;
    }
    get total(){
        return this.totalOperation;
    }
}
Listing 2-11

CalculatorModel.js

As you can see in the model, there are all the methods called by the presenter, like reset or calculate, and a few others like checkSymbol and getValue, used for handling the application logic.

The separation of concerns in MVP is very strong and any application would be easier to debug and maintain if we properly apply these few concepts; it’s definitely an architecture that largely improved the MVC concept created 10 years before it.

Model View View-Model

Model View View-Model (MVVM) is an architecture created by Microsoft in 2005 for handling the GUI management with Windows Presentation Foundation (WPF) . It sticks with a true separation between the view and the model like we have seen in the MVP architecture, but MVVM encapsulates few differences compared to other architecture (Figure 2-5).
../images/446957_1_En_2_Chapter/446957_1_En_2_Fig5_HTML.jpg
Figure 2-5

MVVM diagram, similar to MVP but the view is not a passive one anymore

How MVVM Works

The first difference is that we have a View-Model instead of a presenter; this specific object will be the bridge between the data stored inside a model and the view.

In a nutshell the view-model is responsible for exposing the data present inside the model to the view and it is also responsible for preparing the data in a way that the view expects, so you can immediately understand that the logic of the view-model is tightly coupled with what the view should render.

For instance, let’s imagine that we have a stock value stored in the model with dollars currency but the view needs it to be shown in euro. In MVVM the model stores the raw data, that is, dollars value, and the view-model would be responsible for converting the value to a given currency, in this case euro.

Another important aspect of the View-Model is the fact that it has a relationship with the views that is 1 to many: therefore we can have one view-model that is handling multiple views or components.

The communication of the View-Model and the view usually happen via bindings; therefore every time a value is updated on the view or in the View-Model, this value is communicated to the other object in order to keep it in sync.

It’s very important to understand that with MVP we enforced the concept of complete separation between the model and the view and in MVVM this strong concept doesn’t change at all.

The model is very simplistic; we store data in a raw format without any particular change, and in this case we should even avoid keeping the state in the model and moving this information to the view-model or even the view if it’s a small component.

Let’s see now how our calculator would work with an MVVM architecture.

The App.js file is instantiating all the objects for an MVVM architecture: model, view-model, and view; in the view-model constructor we are going to inject the model and view instances so it will be able to retrieve data from the model and serve the view with the correct value to display. See Listing 2-12.

export default class App{
    constructor(){
        const model = new CalculatorModel();
        const emitter = new LiteEventEmitter();
        const vm = new CalculatorViewModel(model, emitter);
        const cont = document.getElementById("app");
        ReactDOM.render(<Calculator emitter={emitter} initValue={model.total} />, cont);
    }
}
Listing 2-12

App.js

The Calculator view is a React component that has two key concepts: dispatching the data from the view to the view-model and retrieving the data from the view-model.

In order to do that we can use a data binding library or simply events as both are accepted from MVVM architecture, therefore we are using an event emitter, injected when the view and the view-model were instantiated, for handling the communication between these two objects, as shown in Listing 2-13.

componentWillMount(){
        this.setState({displayValue: this.props.initValue})
        this.emitter = this.props.emitter;
        this.emitter.on("UpdateDisplayValue", value => this.setState({displayValue: value}));
    }
manageDisplayState(value){
        switch (value) {
            case "AC":
                this.emitter.emit("ResetEvent")
                break;
            case "=":
                this.emitter.emit("CalculateEvent")
                break;
            case "+":
            case "-":
            case "/":
            case "*":
            case ".":
                this.emitter.emit("AddValueEvent", {value: value, type: SYMBOL})
                break;
            default:
                this.emitter.emit("AddValueEvent", {value: value, type: NUMERIC})
                break;
        }
    }
Listing 2-13

Calculator.jsx

In manageDisplayState we have all the events we will communicate to the view-model, but in the componentWillMount we define only the event we need to listen for updating the calculator’s display.

The rest of the view is very similar to the other views we have discussed in the previous examples.

Now it’s the turn of our view-model. Here we need to do exactly the opposite of how we handled the events in the view; therefore we are going to listen for all the events emitted by the view and dispatch the event for updating the view’s display every time the value changes. See Listing 2-14.

initialize(){
        this.emitter.on("CalculateEvent", _ => {
            this.calculate()
        });
        this.emitter.on("AddValueEvent", content => {
            this.addValue(content.value, content.type);
        });
        this.emitter.on("ResetEvent", _ => {
           this.reset();
        })
}
updateDisplayAndState(state){
        this.state = state;
        this.emitter.emit("UpdateDisplayValue", this.model.total);
}
Listing 2-14

CalculatorViewModel.js

The view-model is responsible for retrieving and updating the data stored in the model, so every time the user clicks a button in our view we are going to update the value in the model and then call the updateDisplayAndState method for dispatching this change to the view.

We keep a state internal to the view-model to understand which method we need to call during the calculation; therefore we need to update it when the state is changed.

Let’s see, for instance, how we handle the changes in the three methods we have created for handling these operations, as shown in Listing 2-15.

addValue(value, type){
        let valueToAdd;
        if(type === NUMERIC){
            valueToAdd = this.getValue(value);
        } else if(type === SYMBOL){
            valueToAdd = this.checkSymbol(value);
        }
        this.model.add(valueToAdd)
        this.updateDisplayAndState(IN_PROGRESS_OPERATION)
 }
 reset(){
        this.model.reset();
        this.updateDisplayAndState(FIRST_OPERATION)
 }
 calculate(value){
        this.model.calculate(value);
        this.updateDisplayAndState(FIRST_OPERATION)
 }
Listing 2-15

CalculatorViewModel.js

All of them are doing two main operations :
  1. 1.

    They are updating the model.

     
  2. 2.

    They are dispatching to the view the new value to display.

     

It’s now clear that the majority of application business logic is present in the view-model; therefore if we want to reuse a specific component or part of the application. we need to maintain the event or the binding contract between the view and the view-model as it is. So we can say that these two objects become slightly more tightly coupled compared to their relation in the MVP architecture.

Last but not least, it’s time to discuss the model. As you can see, the model just exposes a few methods in order to update the value to display; it doesn’t have any data manipulation or any state, and in this case the model is just a data representation of the main application so if we need to use it in combination with another view-model, the model will provide the data expected and nothing more. See Listing 2-16.

export default class CalculatorModel{
    constructor(){
        this.totalOperation = 0;
    }
    calculate(operation){
        this.totalOperation = math.eval(this.totalOperation);
    }
    add(value){
        this.totalOperation = value;
    }
    reset(){
        this.totalOperation = 0;
    }
    get total(){
        return this.totalOperation;
    }
}
Listing 2-16

CalculatorModel.js

JavaScript Frameworks

Now that we have explored the basics of MV* architectures, understanding the benefits and the issues related to each of them, it’s time to review what the JavaScript ecosystem is proposing and how these architectures are implemented.

I’m sure you will realize very soon that understanding the three architectures mentioned before will help you to capture the technical approaches provided by well-known frameworks like Angular, Ember, or Redux.

In this section we are going to re-create our calculator application three more times: the first one with Angular, then with Ember, and we will conclude this journey with the combination of React and Redux.

Angular

Angular is an open source framework created and maintained by Google. It’s been around since 2010 and has reached recently version 5, but from now on Google explained that we should just call it Angular.

This framework passed through different stages in the past years, from a huge hype when launched with version 1; then, after the announcement of version 2 not being retro compatible with the previous version, many developers decided to move away from it and embrace other frameworks – in particular, React and Flux or Redux or similar combinations.

Recently, as in 2017, Google released a new version that should enhance the experience of the JavaScript developers with Angular, providing a complete ecosystem of tools and patterns in order to work easily with this framework without the need to scrap the Web for assembling multiple libraries inside the same project.

Since version 2, Angular embraces TypeScript as its main language; JavaScript ES6 and Dart are supported too, but the vast majority of the resources in the Angular website are prepared with TypeScript.

Angular as a framework is providing a full architecture and utilities out of the box with also an interesting CLI tool for speeding up a developer’s productivity.

TypeScript

TypeScript is a typed superset of JavaScript, and it enhances the language adding Enum, Generics, Abstract, and Interfaces very familiar with strictly typed languages like Java, for instance.

More information on the official website: https://www.typescriptlang.org

How Angular Works

The architecture we will evaluate in this section is related to Angular 2 and onward (Figure 2-6), so we won’t take into consideration the previous one because it works in a different manner.
../images/446957_1_En_2_Chapter/446957_1_En_2_Fig6_HTML.jpg
Figure 2-6

Angular architecture example

Angular architecture introduces four interesting concepts :
  • Dependency Injection

  • Modularity with NgModules and Components

  • Data binding between Templates and the Components

  • Large use of decorators for defining the objects like Components or Modules

We will now go more in depth of this architecture, analyzing the different parts that compose an Angular project.

Any Angular application has at least an NgModule called the root module ; an NgModule is not like a normal JavaScript Module. The peculiarity of the NgModule is the metadata; in each NgModule (root module included), we will describe how the module is composed, and in particular we will define which components belong to a module, if a module has dependencies from other modules, directives, or components; and we also describe the services used by the components present in the module.

As described before, any Angular application contains at least one module called the root module.

For instance, this is the root module created for our Calculator project in Angular:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

As you can see in this code snippet, Angular is largely made up of decorators (@NgModule) for wrapping our code inside the Angular framework.

Decorators

The decorators in JavaScript are actually in proposal (stage 2) for becoming part of the language (more information on the proposal at this link: https://github.com/tc39/proposal-decorators ).

They are based on a simple concept: a decorator wraps a function, augmenting its functionalities without manipulating the function decorated.

Usually, in a decorator, we add methods or properties that should be common in our project at runtime; that’s why Angular is using a large number of them. It’s so we can write our logic without inheriting from some base class, thereby creating a tight coupled connection between and decorating it with the built-in functionalities available in the framework.

The next topic to introduce is the Angular components. Since Angular 2 we have the possibility to create components, and we can think of them like a bridge between the template system present in Angular and the data we can retrieve from REST API or specific endpoints. Their role is mainly retrieving the data and populating the template with new data via a binding system that is present out of the box in Angular 2.

The Angular component is a mix of properties we can find in the presenter and the view-model. In fact, the following is true:
  • A component is updating the view via binding like in the view-model object.

  • The relation between a component and a template is always 1 to 1 like for the presenter.

  • The component handles all the user interaction happening in the template like for the presenter.

In order to define a component in Angular we need to specify another decorator, @Component. For our calculator example, we have defined just one component considering how simple the application is; but potentially we could have split them in multiple parts as shown in Listing 2-17.

const ON_SCREEN_KEYBOARD = [
  ['7', '8', '9', '/'],
  ['4', '5', '6', '*'],
  ['1', '2', '3', '-'],
  ['0', '.', '=', '+']
];
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [UpdateTotalService, CalculatorModel]
})
export class AppComponent implements OnInit {
  onScreenKeyboard = ON_SCREEN_KEYBOARD;
  total:string;
  constructor(private updateTotalService:UpdateTotalService){}
  ngOnInit(): void {
    this.total = this.updateTotalService.reset();
  }
  updateTotal(value: string){
    switch (value) {
        case 'AC':
            this.total = this.updateTotalService.reset();
            break;
        case '=':
            this.total = this.updateTotalService.calculate();
            break;
        case '+':
        case '-':
        case '/':
        case '*':
        case '.':
            this.total = this.updateTotalService.addSymbol(value);
            break;
        default:
            this.total = this.updateTotalService.addValue(value);
            break;
    }
  }
}
Listing 2-17

App.component.ts

As you can see in the decorator (@Component) we are specifying the HTML template and the CSS associated with the component. The objects to inject will be accessible inside the component but they will be instantiated by Angular and a selector that is just an ID to identify the component.

The last thing to mention about Angular components is that we can use life-cycle hooks like ngOnInit method that is triggered when the component is initialized and in our case we use it to set the first value in our calculator display.

Now it’s time to see how the components interact with templates. Angular has its own way to handle HTML markup; we can use some directives in order to iterate through a data structure for displaying multiple HTML elements or for adding specific attributes if a certain condition happens in our code.

Directives

Directives in Angular are instructions for the HTML template on how the template should handle the DOM.

In our example we have associated an app.component.html template to the app.component.ts described above and this is the code used for the template:

<div class="displayStyle">{{total}}</div>
<div class="acStyle" (click)="updateTotal('AC')">AC</div>
<ul *ngFor="let row of onScreenKeyboard">
    <li *ngFor="let value of row"
      class="btnStyle"
      (click)="updateTotal(value)">
      {{value}}
    </li>
  </ul>

In this code it is important to highlight a few concepts. The first concept is that the binding with the total property is created inside the component, so every time we are updating this value, the new value will automatically be displayed inside our template.

The other interesting thing is how we have created the buttons in our calculator; we are iterating an array present in the component object and with *ngFor directive we are creating multiple tags with different values; then, when a user clicks on the button we are calling the method updateTotal passing the button’s label; also in this case we use Angular markup for triggering the user interaction ((click)="updateTotal(value)").

Interestingly enough, just with few lines of code. Angular provides a simple but very powerful mechanism of data binding, templating, and styling our views.

It’s time to talk about the dependency injection part; as we saw in the component decorator we are defining an array of providers. Basically we are injecting UpdateTotalService and CalculatorModel to the component.

The CalculatorModel won’t be used by the component but if we want to inject this object inside the service, we need to specify it there.

What is a Service in Angular? A Service is inspired to the Command Pattern , and it’s used for fetching data from an endpoint or for retrieving/passing data to a model like in our case.

Command Pattern

The command pattern is a behavioral pattern. A command contains all the objects needed to perform an action when a specific event happens inside an application such as user interaction, data fetching, and so on.

Usually the command pattern has an interface with just one public method called execute; and after instantiation, where we can inject the objects needed for performing the action, we can call this method for performing the logic described inside the command.

Usually the command is used for decoupling the interaction within objects like the controller and model or presenter and model, and then we maintain them totally decoupled.

This is our UpdateTotalService class as shown in Listing 2-18.

@Injectable()
export class UpdateTotalService{
    constructor(private model:CalculatorModel){}
    calculate(){
        this.model.calculate();
        return this.model.total;
    }
    addValue(value){
        this.model.add(value, VALUE);
        return this.model.total;
    }
    addSymbol(value){
        this.model.add(value, SYMBOL);
        return this.model.total;
    }
    reset(){
        this.model.reset();
        return this.model.total;
    }
}
Listing 2-18

UpdateTotalService.ts

This service exposes a few methods that will be used for manipulating the model in a specific way.

The model is injected in the constructor via the framework; therefore when we call this.updateTotalService.reset(); from the component class we won’t need to have any knowledge of the model but the service will return the value retrieved from the model, isolating the view from the model like we have seen in the MVVM pattern, for instance.

Another important thing to notice in this class is the injectable decorator provided by Angular for describing a class that is injected inside a component; just adding this decorator, the framework knows when to instantiate and inject.

The last part to describe is our model that is a very basic model with some knowledge on how to manipulate the data to store. Here again we are using the @injectable decorator for the possibility of being injected by Angular. See Listing 2-19.

@Injectable()
export class CalculatorModel{
    private state:string;
    private totalOperation:string;
    constructor(){
        this.state = FIRST_OPERATION;
        this.totalOperation = '0';
    }
    get total(){
        return this.totalOperation;
    }
    reset(){
        this.totalOperation = '0';
        this.state = FIRST_OPERATION;
    }
    add(value, type){
        if(type === VALUE){
            this.totalOperation = this.getValue(value);
        } else {
            this.totalOperation = this.checkSymbol(value);
        }
        this.state = IN_PROGRESS_OPERATION;
    }
    calculate(){
        this.totalOperation = math.eval(this.totalOperation);
        this.state = FIRST_OPERATION;
    }
    checkSymbol(value){
        const str = this.totalOperation;
        if(this.state === FIRST_OPERATION){
            return str + value;
        }
        return !isNaN(Number(str.charAt(str.length - 1))) ? str + value : str.substr(0, str.length - 1) + value
    }
    getValue(value){
        return (this.totalOperation === '0' || this.state === FIRST_OPERATION) ? value : this.totalOperation + value;
    }
}
Listing 2-19

CalculatorModel.ts

Our model is a simple object that contains the source of truth for our application, maintaining the state and the value that should be displayed inside the views.

Just to summarize the Angular calculator example: we have seen the key concepts of Angular, we also noticed quite a few similarities with MVVM and MVP architectures like the relation between view and template or who is handling the user interactions. The last thing worth mentioning is that Angular can become a reactive architecture pretty easily, because it incorporates Rx.js library inside the framework; therefore, within a certain degree, we can twist this architecture to a Reactive one almost out of the box.

Ember

Ember is a framework oriented to web applications. It’s well-known in the JavaScript community and used by large organizations such as Netflix or Groupon.

Ember has an interesting ecosystem composed by EmberCLI, EmberData, and Ember as a JavaScript framework.

The paradigm behind Ember is slightly different from other frameworks but the productivity is high if the application fits this paradigm.

Ember favors convention over configuration; a key thing to remember is embracing the EmberCLI tool because it will facilitate your life and boost your productivity, the CLI takes care to generate all the files needed for a specific view (template, router, unit testing files, and so on), model, route, or even controller.

The Ember framework shines when a project has an architecture “fat server – thin client” where the majority of the logic is handled on the server; the client should be as dumb as possible and it should be a multipage application over a single page application (SPA) .

How Ember Works

Ember architecture (Figure 2-7) is based upon MVVM architecture, and there are some key elements that composed this framework:
  • Routes

  • Templates

  • Components

  • Controllers

  • Models

../images/446957_1_En_2_Chapter/446957_1_En_2_Fig7_HTML.jpg
Figure 2-7

Ember architecture example

In Ember everything starts from a route module and each view is tightly coupled with the endpoint associated. By default any Ember application has a main route system where we define all the application routes; for instance, in our calculator application we have defined this route shown in Listing 2-20.

Router.map(function() {
  this.route('calculator', {path: "/"});
});
Listing 2-20

Router.js

That means the root of our web application will be routed to the calculator route. Because Ember works with conventions, we need to save the modules in the right folders in order to be picked up. But luckily the Ember CLI comes to the rescue by providing some useful commands that prepare all the files needed out of the box:

Ember generate route <name>

And automatically the CLI will generate a route file, the associated test file, and the template, and then it will also insert the code for the new route to the application route system.

The route we created for our calculator exposes the model to the template; in Ember only the routes and the controllers have access to the model. Therefore, there is a strong separation of concerns between the view and how the model should be in an MVVM architecture .

export default Ember.Route.extend({
    model(){
        this.store.push({
            data:[{
                id: 1,
                type: "calculator",
                attributes: {
                    total: "0",
                    state: AppState.FIRST_OPERATION
                },
                relationships: {}
            }]
        });
        return this.store.peekRecord('calculator', 1);
    }
});

The concept of Model in Ember is slightly different from what we are used to; the Model class defines that the value will be present in the store (the concrete model) facilitating the data validation when they hit the client side of our Ember application.

If we check our model class, present inside the models folder, we can see that we are defining two properties” both of type string, one called total and the other state. See Listing 2-21.

import DS from 'ember-data';
export default DS.Model.extend({
    total: DS.attr("string"),
    state: DS.attr("string")
});
Listing 2-21

models/calculator.js

As you can see from the route code above, the store is a data structure centralized for the entire application (think of it as a Singleton), accessible by the routes and controllers, so independently from the amount of templates, routers, or controllers our application is composed of, we have a unique source of truth to fetch or cache data.

The store object is a very interesting one because it allows data to be automated and fetched from an endpoint, and then it will store the response directly inside the store object without handling all the code for defining these kinds of operations.

The store works with records; a record is a concrete model that contains the data fetched from a REST endpoint or cached inside the application like in our case.

It’s very important to notice the structure of an object stored in a record, as shown in Listing 2-22.

{
        id: 1,
                type: "calculator",
                attributes: {
                    total: "0",
                    state: AppState.FIRST_OPERATION
                },
                relationships: {}
}
Listing 2-22

routes/calculator.js

Inside the store we need to define the data object with a unique ID; a type value, used for retrieving it later on; and the attributes we need to store inside it, for our application will be the value total and the application state.

Because we are not fetching the data from any remote endpoint we are using peek Record method, which will skip the server request and retrieve the data directly from the concrete model.

Instead if we would need to retrieve data from a specific REST endpoint, we could use find Record that will perform a request to the endpoint specified, and it will store the response inside the store object.

Our application logic sits in the controller where we are providing public methods for the views to be called and we are handling the setting and getting of data to and from the model.

When we extend the base controller from the Ember framework we have an object called actions where we can expose all the methods to the template; in our case we just have one method called updateTotal :

export default Ember.Controller.extend({
    onScreenKeyboard: [
        ["7", "8", "9", "/"],
        ["4", "5", "6", "*"],
        ["1", "2", "3", "-"],
        ["0", ".", "=", "+"]
    ],
    actions:{
        updateTotal(value){
            let result;
            let model = this.store.peekRecord('calculator', 1);
            switch (value) {
                case "AC":
                    model.set("total", 0);
                    model.set("state", AppState.FIRST_OPERATION);
                    break;      
                case "=":
                    result = math.eval(model.get("total"));
                    model.set("total", result);
                    model.set("state", AppState.FIRST_OPERATION);
                    break;
                case "+":
                case "-":
                case "/":
                case "*":
                case ".":
                    result = checkSymbol(model.get("total"), value, model.get("state"));
                    model.set("total", result);
                    model.set("state", AppState.CALCULATING);
                    break;
                default:
                    result = getValue(model.get("total"), value, model.get("state"));
                    model.set("total", result);
                    model.set("state", AppState.CALCULATING);
                    break;
            }
        }
    }
});

Here in each case we are retrieving the current value from the store and manipulating it, but the annoying part is that Ember works a lot with strings in order to identify a specific object or value. Therefore we won’t have code completion provided by our editor and it could be prone to error if it’s not properly wrapped in a constant statement.

The last bit to discuss is the template. Ember is using handlebars out of the box; therefore if we are familiar with this famous template library we will be productive in no time.

Handlebars has some specific markup, like Angular, for identifying specific behaviors like filtering, creating similar tags populated with data retrieved from the controller or the route and so on.

This is the handlebars code needed in order to render our calculator:

<div class="displayStyle">{{model.total}}</div>
<div class="acStyle" {{action "updateTotal" 'AC' on="mouseDown"}}>AC</div>
{{#each onScreenKeyboard as |row|}}
<ul>
  {{#each row as |value|}}
    <li class="btnStyle" {{action "updateTotal" value on="mouseDown"}}>{{value}}</li>
  {{/each}}
</ul>
{{/each}}

It’s interesting to highlight how we handle the method exposed by the controller via the action command:

{{action "updateTotal" value on="mouseDown"}}

We identify the method name passing a parameter called value in this case, and specifying when the method should be invoked: in this case on mouse down.

To summarize, Ember is a really productive framework based on MVVM architecture with a lot of common activities ready to be used out of the box. It favors convention over configuration, it has a reach ecosystem composed by different tools and libraries, and the documentation is really exhaustive.

React + Redux

React and Redux is a combination of libraries that together can resemble a minimal framework with a large ecosystem that is not imposed at the beginning like for Ember or Angular but is more oriented to a plug-in system where we can use what we really need without the need to import everything up front.

React is a library useful for manipulating the DOM, based on components as first citizen; it takes care of the view part of an architecture only, implementing smart algorithm like the reconciliation one – a diff algorithm used for rendering only the part of the DOM that should change.

React introduced a very powerful concept embraced nowadays by several other libraries: the Virtual DOM . The Virtual DOM is a DOM representation where the diffing algorithm operates at first glance and where React understands what should change and when, minimizing the changes to the real DOM and improving the performances of our web applications.

Reconciliation

Reconciliation is a key concept for React. If you want to know more, I suggest reading the official documentation regarding this topic: https://react-cn.github.io/react/docs/reconciliation.html

On the other hand, Redux is a state container not tightly coupled with React because we can find examples of Redux used in combination with other frameworks like Angular.

Redux is solving a well-known problem of how to manage the state inside an application.

The most interesting part of it is that it leverages a concept introduced in 2015 from another library called Flux, created by Facebook, of unidirectional flow .

Unidirectional flow is a powerful but simple concept: the objects communication inside an application should be unidirectional, and this, in combination with good encapsulation, will allow any application to be easier to debug, to be picked by any team because also complex applications are easy to understand and debug, thereby improving the code quality and the possibility of extending them.

The Redux paradigm is straightforward and is composed by only three key elements :
  • Actions

  • Reducers

  • Stores

The action is just a plain JavaScript object containing the information of what happened inside the application.

The reducer is retrieving from an action that the interaction happened in the application and knows how the state should change based on the action dispatched.

Finally, the store is the object that brings all together; the store is passing to the reducer the current state tree and the action, and it waits until the reducer provides back the new state, then the store will append to the state tree and all the objects that are listening for a change will be notified.

Redux was created on top of three core concepts :
  • Single source of truth: the application state is represented inside a tree defined inside a single object called store.

  • State is read-only: the only way to change the state with Redux is via an action.

  • Changes are made with pure functions only: the reducers are pure functions that are receiving the current state tree and an action, and they know how the application will change to the next state. If we always pass the same parameters, we know the output of a pure function; in this case the reducer will be always the same.

Let’s see React and Redux in action with our calculator example written for the last time with a different architecture.

How Redux Works

The starting point of any Redux project (Figure 2-8) is usually a main application where we create the store object and we wrap our main view inside a provider object from the Redux library. See Listing 2-23.

export default class App{
    constructor(){
        const store = createStore(CalculatorReducer);
        const cont = document.getElementById("app");
        ReactDOM.render(
            <Provider store={store}>
                <CalculatorContainer/>
            </Provider>, cont);
    }
}
let app = new App();
Listing 2-23

App.js

../images/446957_1_En_2_Chapter/446957_1_En_2_Fig8_HTML.jpg
Figure 2-8

Redux project architecture diagram

As we mentioned before, after creating the store and associating it to a specific reducer (Calculator Reducer), we are wrapping our main view (Calculator Container) inside a Provider object from the redux library.

Think about the Provider as an object that receives as input the store and it propagates it to all the container components inside an application in order to have complete access to it.

Considering we have mentioned the container components, it’s time to move to the view part, where we need to distinguish between presentational components and container components.

The creator of Redux, Dan Abramov, wrote a post on Medium.com regarding this topic where is explaining the difference between the two types of components.

To summarize Dan’s thoughts, in Redux we distinguish the presentational components as component with the only scope of managing the look and feel of the view, more or less like the Passive View described in this chapter. Meanwhile we identify the container components as the ones that can handle the presentational component logic like user interactions, having access to the store, and mapping the store values to the React component via a props object, similar to the Supervising controller of the MVP architecture.

This approach will lead to a better separation of concern and reusability of our components across different projects.

Presentational vs. Containers components

In Redux this is a very important topic. I strongly suggest having a look at this link to Dan Abramov’s Medium post on the presentational and containers components explanation: http://bit.ly/1N83Oov

Based on what we have just described, it’s time to see what a presentational component looks like and how we handle the communication with the Redux framework.

In the calculator example, our presentational component code looks like that shown in Listing 2-24.

export default class Calculator extends React.Component{
    constructor(props){
        super(props);
        this.onBtnClicked = this.props.onButtonClicked;
    }
    createRow(id, ...labels){
        let items = labels.map((value, index) => {
            return <li key={`${id}_${index}`}
                       style={value === "AC"? acStyle : btnStyle}
                       onClick={::this.onBtnClicked}>
                       {value}
                   </li>;
        })
        return(
            <ul key={id} style={ulStyle}>
                {items}
            </ul>
        )
    }
    render(){
        return(
            <div>
                <div style={displayStyle}>{this.props.result}</div>
                {this.createRow("row1", "AC")}
                {this.createRow("row2", "7", "8", "9", "/")}
                {this.createRow("row3", "4", "5", "6", "*")}
                {this.createRow("row4", "1", "2", "3", "-")}
                {this.createRow("row5", "0", ".", "=", "+")}
            </div>
        );
    }
}
Listing 2-24

Calculator.jsx

We can immediately spot that we are focusing more on what our component looks like than what it does. The only method that is going to be used is the onButtonClicked method retrieved from the props object as well as the result property that will be used to show the calculation inside the calculator display div element.

The entire logic of this component as well as the communication with the rest of the application is made inside the container component, as shown in Listing 2-25.

const mapDispatchToProps = (dispatch) => {
    return {
        onButtonClicked: (evt) => {
            evt.preventDefault();
            let value = evt.target.innerHTML
            manageDisplayState(value, dispatch);
        }
    }
}
const manageDisplayState = (value, dispatch) => {
    switch (value) {
        case "AC":
            dispatch(reset())
            break;
        case "=":
            dispatch(calculate())
            break;
        case "+":
        case "-":
        case "/":
        case "*":
        case ".":
            dispatch(appendValue(value));
            break;
        default:
            dispatch(appendValue(value));
            break;
    }
}
const mapStateToProps = (state) => {
    return{
        result: state.result
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Calculator);
Listing 2-25

CalculatorContainer.js

In this module , we can find many interesting things like the following:
  • The presentational component is created after calling the connect method. The connect method is used to “connect” the store to the component, and it returns a higher-order React component class that passes state and action into our component derived from the supplied arguments.

  • mapStateToProps is the method we use in order to translate the new state passed by the store into properties that will be rendered in the presentational component.

  • mapDispatchToProps is the method we use to trigger all the dispatch actions happening inside our container component. The dispatch method accepts an action that will be triggered and listed into the store and passed to the reducer.

Before we move to the reducer, it’s good to understand what an action is. Basically an action is just a plain JavaScript object. Inspecting the CalculatorAction module, we can see it clearly in Listing 2-26.

export function calculate(){
    return {
        type: CALCULATE
    }
}
export function reset(){
    return {
        type: INIT,
        result: 0
    }
}
export function appendValue(value){
    return {
        type: APPEND,
        toAppend: value
    }
}
Listing 2-26

CalculatorActions.js

The actions are similar to commands where they bring with them the information needed to the reducers in order to change the current state to a new one. Usually they have a property type where we define the type of action called from the store.dispatch method.

Finally, it is the turn of the reducer. The reducers are used when we need to change the application state, because the action is notifying us that something happened inside the application but it doesn’t have the knowledge of how the application should change – that’s the reducer’s duty. See Listing 2-27.

const calculation = (state = reset(), action) => {
    switch (action.type) {
        case CALCULATE:
            return {
                type: action.type,
                result: math.eval(state.result)
            }
            break;
        case APPEND:
            return {
                type: action.type,
                result: resultHandler(state, action.toAppend)
            }
            break;
        case INIT:
            return {
                type: action.type,
                result: resultHandler(state, action.toAppend)
            }
            break;
        default:
            return state;
            break;
    }
}
Listing 2-27

CalculatorReducer.js

In our reducer, we set as the default state the reset action that starts the application with the initial state (INIT in our switch statement).

Every time an action is dispatched, the store calls the reducer passing the current state and the action dispatched, and then the reducer is mapping the action to the next application state.

Redux is a very simple but effective state management library, and it’s interesting that there are many similarities with the MVP architecture – in particular for the relation view presenter like we have in Redux with the presentational component and its container.

Also in the redux ecosystem there are other libraries that we can use in combination with Rx.js, for instance, or other reactive libraries.

Wrap-Up

In this chapter, we have evaluated different architectures from the oldest one like MVC to the most recent one like Redux. We saw a clear evolution of them but with many references to the past principles. Often we spend a lot of time with a framework without asking us why the authors picked one decision over another. I hope that this journey through the most famous architectures/frameworks available for the front-end development provided you some benefit in your future projects because I truly believe that it is very important to have a good knowledge of them for choosing the right one for a specific project. Too often I have seen developers and architects always using the same architecture fitting any project inside it instead of using “the right tool for the right job”.

From the next chapter on, we are beginning the Reactive journey that will lead us to learn how reactive architectures work from different point of views and we will discover more about Cycle.js, MobX and SAM.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.224.197