Cycle.js a reactive framework

I had the chance to spend quite few evenings with Cycle.js preparing my presentation for JSDay 2016 and I have to admit that I had quite a lot of fun so I decided to share my experience in this post.

I’d suggest first to take a look to my previous introduction to reactive programming just to cover the basics if you are not familiar with this paradigm.

Cycle.js is an incredible light framework that allow you to work in a reactive fashion way. As mentioned on all my talks regarding this topic, the initial entry level is a little bit higher than other frameworks if you are not familiar with Reactive concepts like hot and cold observables for instance and Functional concepts like pure functions.
Cycle puts the functions as first class citizen for the entire framework, having a previous knowledge of reactive and functional paradigms definitely it helps to speed up working with this framework.
Let’s start to see how it works from an eagle eye perspective:

Screen Shot 2016-05-22 at 11.37.17

This image above represent the main concept behind Cycle where we have a loop between the a main method, that receives as input a read effects (sources), and the “external world” that receives some write effects as output (sinks).
The side effects generated by the main function will be handled by the “external world” inside drivers that will communicate with the external world.

Cycle in practice

 

Cycle.js allows you to work with an interesting architecture created ad hoc for reactive programming called MVI (Model View Intent), I wrote an extensive article on this topic and I suggest to read it because the architecture is really interesting leveraging new concepts like the communication between objects via observables.

mvi

There is an interesting read in the Cycle website that explains how MVI works in the official website.

For the JSDay I prepared a simple example in MVI with Cycle just to show how simple is working with this architecture and with Cycle framework.
The example is a real time monitor for London Underground trains showing the position of each train and the expected arrival to their destination.

Screen Shot 2016-05-11 at 11.52.07

You can find the project on my github account

The application is mainly composed by 4 main areas:

  • Main.js is the entry point of our application where I’m instantiating Cycle run loop and I’m adding the hot reloading module for Cycle.js
  • App.js where there is the business logic of the application written in MVI (mvi-refactor branch)
  • Networking.js where I’m handling the HTTP request and response made via HTTPDriver
  • Template.js that represents the renderer object made with hyperscript (default virtual-dom library present in Cycle)

The App.js is where the business logic of the application sits with the division of competences between Model – View – Intent.
I warmly suggest to have a read to my article on MVI as mentioned before in order to understand how MVI works.

export default function app(_drivers){
   const response$ = networking.processResponse(_drivers.HTTP);
   const actions = intent(_drivers.DOM);
   const state$ = model(response$, actions);
   const vtree$ = view(state$);
   const trainsRequest$ = networking.getRequestURL(actions.line$, DEFAULT_LINE);

   return {
      DOM: vtree$,
      HTTP: trainsRequest$
   };
}

the interesting part here is how I’ve divided the interaction between different actors present in the app inside the main method.
All the constants that ends with $ symbols are observables (this is a simple convention to immediately recognise which variable is an observable and which is not).
The app method has a unique argument (_drivers) and it returns an object containing 2 observables that will be handled by the outside world via drivers (check Main.js to see where I’ve instantiated the DOM and HTTP drivers).

Then I’ve created the networking object that is handling the interaction between an end point and the application.
response$ is the observable where I’m going to store the service response and trainsRequest$ is where I’m defining the request using the tube line chosen by the user in query string (check Networking.js for that).

Last but not least I’m creating the MVI structure where the only point of communication between these pure functions is an observable or a collection of observables.
That would help me to testing easily the application, encapsulating properly the behaviours of each part and having a unidirectional flow of information that are flowing inside the application or component.

I’d like to bring your attention now to how the view is handled in Cycle.js, the view is generating a virtual tree of elements that will be rendered by a third party library like Hyperscript or React.
It’s not a case that Cycle is using a render library that implements the virtual-dom concept because, as we describe at the beginning, Cycle works with loops so having a diff algorithm that update the DOM only when needed it’s a great boost performance wise for the entire application and it removes some complexity to handle on the developers side.

export default function getBody(results){

   let selectedLine = results[0].length > 0 ? 'Selected line: ' + results[0] : "";
 
   return div(".container", [
      h1("#title", ["Reactive Live London Tube trains status"]),
      select("#lines", [
         option({ value: 'piccadilly' }, ["Piccadilly line"]),
         option({ value: 'northern' }, ["Northern line"]),
         option({ value: 'bakerloo' }, ["Bakerloo line"]),
         option({ value: 'central' }, ["Central line"]),
         option({ value: 'district' }, ["District line"]),
         option({ value: 'circle' }, ["Circle line"]),
         option({ value: 'victoria' }, ["Victora line"]),
     ]),
     h3("#selectedLine", [selectedLine]), 
     renderTrainsData(results[1])
   ]);
}

Just to give you an idea, I brought the entry function that generates the application view, after defined few static elements like the dropdown and few title elements, I’m going to call another function that is returning the results to display in the main view.
In renderTrainsData function I’m returning the elements splitting the different domain objects across 3 other functions:

function getTrainData(data){
   return li(".train", [
      div(".train-data", [
        p(".stationName .col", [span("station: "), data.stationName]),
        p(".platform", [span("platform: "), data.platformName]),
        p(".current-location", [span("current location: "), data.currentLocation]),
        p(".arrival-time: ", [span("expected arrival time: "), moment(new Date(data.expectedArrival)).format("HH:MM - Do MMM YYYY")])
      ]
   )])
}

function getDestinationStation(data){
   return div(`.destination-station .${data.lineId}`, [
       h2(data.destination),
       ul(".destination-trains-available", data.trains.map(item => getTrainData(item)))
   ]);
}

function renderTrainsData(data){
   return div(".all-stations", data.map(item => getDestinationStation(item)));
}

As you can see is very easy to understand and the code becomes very readable for anyone, in particular when we are writing meaningful function names.
I’ve created also some simple CSS IDs and classes defined as first parameter of each HTML element just for the curiosity to see a basic integration between hyperscript and CSS.

Wrap Up

Cycle.js is showing a new approach to the Javascript community with a lot of good ideas and a growing community that is following and improving the framework.
I can’t say that would be the most used framework for the next year considering how much React+Redux and Angular 2 are succeeding in the front end scene, but I believe that with Cycle you can still create great applications often with less and well structured code compared to other frameworks.
I’ll definitely continue to go ahead with it and possibly to contribute as much as I can to this project and Rx.js as well, because I strongly believe in the future of reactive programming paradigm and the people behind it.

 

Advertisements

2 thoughts on “Cycle.js a reactive framework

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s