Should You Use A ‘Reactive Architecture’ In Your UI App?

Today we are going to talk about something which sounds confusing but truthfully isn’t; functional reactive programming (FRP) or just "reactive architecture" as it's also known when we talk about the overall approach to using it in an app.

In my experience engineers often think a reactive architecture is

  1. Something to do with React
  2. Something new and trendy and therefor ‘different’
  3. Something they don't need to learn because it's just another JavaScript fad

But reactive architecture is none of these, it’s a simple design paradigm for enabling the data in an app to become more predictable and easier to scale.

Single Threaded Applications

Because JavaScript only runs in a single thread it relies heavily on event-driven processes to initiate ‘what’ code will fire ‘when’. Although JavaScript is single threaded the systems it runs on (the browser/node.js) are not.

These systems can provide resources such as disk access and http calls which could take an indeterminate amount of time to complete. For this reason they ‘could’ allow a JavaScript app to ‘lock-up’ whilst it’s waiting for them to complete.

To avoid this; when we build a JavaScript app we use callbacks. Callbacks are functions that we pass to these external boundaries and say  ‘here - call this when you are finished’. 

We say JavaScript is a naturally ‘event driven’ language - it configures itself as a series of events which are called back at some 'event' during the future.

The Predictable State Problem

There is a common opinion amongst JavaScript engineers when building UI apps in any of the main UI frameworks (React, Angular or Vue) that apps should be 'stateless'. 

Most engineers say this because of the inherent difficulty with accessing data in an event driven application. The problem with events is that you never have full linear control over data. This means that if you have an event accessing some data in your app, you don't know if another event came and changed it without you knowing. This creates a sort of ‘race condition’ which makes the state in a JavaScript app unpredictable.

But, it’s impossible to write truly stateless UI apps because of the existence of the assignment operator (=). The reason that engineers hang onto 'statelessness' is because they believe JavaScript is purely functional; and functions have no state.  In the true mathematical sense this is accurate, but this is not math, this is application development. Practicality tells us regardless of functions and theory, you can't really build a UI app without state. Because if we never store state in a JavaScript UI app then we could not do anything useful like merging, sorting or recalculation of data in the Single Page App (SPA) itself.

They do have a point about state, but I think what they really mean is...

Firstly, the state lifecycle needs to be managed so that we know it will be set and read at the right times removing the unpredictability issue.

Secondly, we also need to make sure we can encapsulate the dangerous parts of our state and expose useful parts too removing the unpredictability issue even further!

Luckily we can solve this problem using functional reactive programming in our architecture, we can call this the reactive architecture!

Reactive Architecture

Before looking at a reactive approach lets look at the problems in a normal event driven approach. Consider the following code which is designed to do a simple event update when our api data (usersData) changes…

var userData = api.get('/users')

api.onDataUpdated(callback)

function callback() {
  console.log(usersData)
}

In this code you can see how we are binding an event handler to our api and then triggering update functions when it changes (line 3). But when we do this, we are not properly encapsulating usersData because we can access it lower down the example (line 6). Because of this we run the risk of something reading or even changing this data after it is changed by the api. This leads us to the problem of unpredictability we saw in the last section. We want to avoid this.

So, consider the following;

let rf = new ReactiveFramework()

let reactiveContext = rf.listen(api.startPolling('/users'), (usersData) => {
  // 1st mutable or immutable change
  return usersData
})

rf.listen(reactiveContext, (newUsersData) => {
  // 2nd mutable or immutable change
  return newUsersData
})

rf.listen(reactiveContext, (newNewUsersData) => {
  // 3rd mutable or immutable change
  return newNewUsersData
})

In this code I have introduced an object called reactiveContext. The reactiveContext is a separate module which lets us funnel requests for updates and changes to our state through it. This reactiveContext does something called "boxing".  This boxing allow us to put the state data into an encapsulated function (starting on line 4), then; it allows us to add listeners to it (line 3,8,13) which trigger when it updates.

By forcing access like this through a "context" we can intercept all updates to the base data userData using a callback function at each step. This gives us the ability to chain together functions which act on state that operate in a sequence.

We can also allow helper functions to be called on the data during it's movement through our context chain. These helper functions are usually implemented as prototype functions like .map() .flatMap() etc.

So, instead of dangerously responding to and directly reading state data across boundaries like in the first example, the reactiveContext lets us control the underlying data. Thus; we can control the lifecycle of updates and protect it when we need to. The major benefit to this approach is firstly the encapsulation becomes (functional) and secondly the lifecycle becomes (reactive), aka functional reactive!

We can visualise how a FRP/reactive architecture let's us clean up our data transformation that might happen in a chaotic event app; and then compare it with a more controlled manner afterwards;

 

Frameworks

At this point you are probably thinking - what about React.js? And that's a great question.

Because, guess why it's called React.js? It also uses the reactive approach! Each of the components in React create their own functional closure like we saw above. The React framework is simply the proxy itself and allows the passage of data through its render tree, but it does this using HTML bindings!

In our reactiveContext we were responding to changes of simple data. But in the React world our app responds to user interaction and changes to HTML data. But the idea is the same - a reactive interface which allows the encapsulation of data (state).

If you want to begin using a fully fledged reactive framework in your app and extend out the functionality in then your main choices are RXJS which is the default for Angular apps or Mobx which works well with React and Vue.

Mobx is known as an observable framework that enables a functional reactive approach for using data and managing state in an app. It’s pretty easy to learn and we teach you how to use it in our course UI Architecture Academy.

Conclusion

In this article we have seen how we do need to manage state in our UI app but that the event driven nature of JavaScript means it can become dangerous because of synchronisation issues, and encapsulation issues.

So we saw how using an FRP based reactive architecture lets us solve these problems because we can use functions and a centralised callback proxy to manage the state lifecycle and to improve data encapsulation. In reality we wouldn't use our own reactiveContext we would use a framework like Mobx or even RXJS.

Reactive architecture and FRP is a good paradigm to be able to build JavaScript apps because it solves a problem you "will" hit when you want to grow your UI apps. It will allow more predictability which will aid in better UI architecture and also testability!


Author: Pete Heard

Pete is the founder of Logic Room. He designs the companies core material for JavaScript architecture, test automation and software team leadership.

LinkedIn

Want to learn 5 critical lessons for framework-agnostic JavaScript UI app design and structure?

Download our 28-page book exploring big picture ideas to help you create better architecture with any UI framework (inc. React, Angular or Vue).

Download
Close

50% Complete

Book Trial

Please fill out your details if you would like to trial our system.