Modern Component based Architecture

in Front-End Web Technologies

download

A component based architecture is not a new idea. VB6 for example, offered such architecture (almost 20 years ago …). Data binding was one of the main feature of VB6. You could throw a control over a form and bind it to a field inside the form.

We know that data binding allows us to develop quickly. On the other hand, a large scale application that is “full” of data bindings is difficult to debug and maintain. This is the reason that I never used automatic data binding too much.

Enter Angular …

Using Angular 1.X you cannot avoid data binding. It is in the heart of the framework. For some reason Angular succeeds in fooling us to believe that any kind data binding is OK. Eventually, Angular 1.X applications suffer from the same maintenance problems as VB6. I had the chance to work with several large scale organizations which use Angular 1.X. The data  binding “mess” is one of the biggest complains. When you loose track of the data flow in your application a performance issue is just a matter of time.

Enter modern world  …

These days everybody seem to talk about immutability, data flow, components and how we can mix all those ingredients together in order to achieve a more reasonable data binding mechanism. Redux talks about single immutable state tree while Flux talks about unidirectional data flow. While both approaches are very interesting and should be considered per application design, I prefer a less strict modeling. Victor Savking has a very interesting post that talks about the same ideas. You must read it.

I find the following section (from Victor’s post) very useful:

Instead of abolishing mutable state all together, let’s just scope it to a component.

1.  Application state that is passed around is modeled using immutable objects.

2. Components can have local state that can only be updated when their inputs change or an event is emitted in their templates.

So we allow mutable state, but in a very scoped form.”

Victor offers a more pragmatic approach for building application. He distinguishes between application global state and component specific state. According to his philosophy each component has inputs, local state (private) and events

Inputs should be implemented as immutable objects. Thus,

1. The component can implement efficient change detection (no need to deep dive into each input when detecting changes).

2. The component cannot accidentally change the input (since it is immutable) and therefor is always in sync with its parent

3. A component has local state which is derived from the inputs + application state (which is mutable)

4. A component’s local state may change only if one of its input changed or when an event is raised.

5. While application global state cannot mutate it can be updated by creating a new state object. In most cases the application raises some events to allow all components to be notified when such new state is created.

For example, lets consider a real life scenario where you have an array of Contact objects and you want to allow the end user to select some of them

Lets assume that the Contact class is defined as follow

 class Contact {
     name: string;
     email: string;
 }

We want to implement a ContactListView component. The component gets a list of contacts (the input) and displays them. Each contact can be checked/unchecked.

Please note that the Contact object has no “checked” field. Therefore, the ContactListView must hold that state internally. For example, we can define a new class named ContactViewModel

 class ContactViewModel {
     name: string;
     selected: boolean;
     contact: Contact;
 }

The ContactViewModel class holds only fields that are data bound to the UI + a reference to the real contact.

Once the ContactListView detects that a new contact array was “pushed” to it, it creates a new ContactViewModel array. While Contact[] is the component’s input, ContactViewModel[] is the component’s local state. Assuming input is immutable the ContactListView does not need to worry about a single Contact instance being changes (it cannot since it is immutable).

The component’s local state (ContactViewModel[]) may change as result of user interaction. For example, the end user may check a single contact. In that case the ContactListView catches the event, updates its internal state and then raises its own event which allow its parent to be notified of the newly checked contact.

You can use the above approach in any framework which supports the idea of one way data binding. Angular 2 is such a framework. But what about Angular 1.X? Can we build more reasonable applications even today using Angular 1.X?

Sure … it is just a matter of some wrapper and correct modeling. Angular 1.5 offers a one way data binding using the ‘<‘ syntax. Assuming your component only uses ‘<‘ then you can install a $watchGroup over all the component’s input and to be notified each time a a new input is pushed. Once a “push event” was detected the component can updates its own local state. A huge benefit of this approach is that all template changes can be detected within 1 digest cycle thus improving significantly Angular 1.X performance.

If you are interested seeing all of that in action using Angular 1.X, give me a call or just wait for my next post …

Contact us
You might also like
Share: