Wednesday, June 24, 2015

Rx.js Session at DevNation

I presented a Session on Rx.js at DevNation this year. My goal was to impress upon the audience how Observables can be interpreted as a collection-in-time. This analogy was very well described by @jhusain his Async Javascript at Netflix talk that initially got me excited about Reactive Functional programming. My contribution to this idea is to present it in a visual way.

To visualize both a "regular" collection, as well as a collection-in-time, I used the d3.js library to visually present a collection of javascript objects that each represent a shape with a given size, color, and shape-type. In my presentation I embedded these visualizations using as Codepens, which I’ve included in this blog post below.

The slides from my presentation are available at:

A Collection

Here is the visualization of a Collection. With a "regular" collection we can get a reference to every object in the collection at any given point in time. Go ahead, "grab" a shape with your mouse!

See the Pen Collection | Iden by Brian Leathem (@bleathem) on CodePen.

An Observable

And here we have the visualization of an Observable as a Collection-in-time. An Observable is different from a "regular" collection in that we cannot grab a reference to every object at any given point in time. The objects stream past us as time progresses.

See the Pen Observable by Brian Leathem (@bleathem) on CodePen.

Reactive Extensions

In the session I then proceed to use these visualizations as basis for describing some of the tools we use for manipulating Collections/Observables:

Map

With the map function we can operate on each item in the collection. In our example mapping function we map each shape into a new shape of the same size, but of type square and color green.

.map(function(x) {
  return {
    id: x.id
  , color: 'green'
  , size: x.size
  , type: 'square'
  };
});

Collection map

Here we have the above map function applied to a "regular" Collection:

See the Pen Operating on a Collection by Brian Leathem (@bleathem) on CodePen.

Observable map

The above map function applied to an Observable:

See the Pen Map an Observable by Brian Leathem (@bleathem) on CodePen.

MergeAll

The mergeAll function is used to "flatten" a 2-dimensional collection into a 1-dimensional collection. In this code sample we map each shape into a pair of shapes which we return as an array. The resulting "array of arrays" is then passed to the mergeAll function where it is flattened.

.map(function(x) {
    var y = _.clone(x);
    y.id = y.id + 80;
    y.color = 'green';

    var z = _.clone(x);
    y.size = y.size / 1.5;
    z.size = z.size / 1.5;

    return [y, z];
  })
  .mergeAll();

Nested Collections

This visualization shows the above mapping without the mergeAll applied. Notice how the resulting collection consists of object pairs. We do not have a flat collection. Try to grab one of the shapes with your mouse and see for yourself!

See the Pen Map a nested Collection by Brian Leathem (@bleathem) on CodePen.

Nested Collections mergeAll

With the mergeAll function applied to the Nested collection we now have a flattened collection, which we can continue to operate on with our tool set.

See the Pen MergeAll a Collection by Brian Leathem (@bleathem) on CodePen.

Observable mergeAll

The mergeAll function applied to a 2-dimensional Observable.

See the Pen MergeAll an Observable by Brian Leathem (@bleathem) on CodePen.

FlatMap

It turns out the mapmergeAll combination is a pattern we apply so often that we created the flatMap function as a shorthand. We can then rewrite the above transformation as:

.flatMap(function(x) {
    var y = _.clone(x);
    y.id = y.id + 80;
    y.color = 'green';

    var z = _.clone(x);
    y.size = y.size / 1.5;
    z.size = z.size / 1.5;

    return [y, z];
  });

Reduce

A common use case for analyzing collections is the reduce function, where one iterates over a collection and "accumulates" a value for each object in the collection. In this code sample we are accumulating the size of each shape, and using that to create a new shape of the accumulated size.

var outputData = inputData
  .reduce(function(acc, x) {
    return {
      id: x.id
    , color: 'green'
    , size: acc.size + x.size
    , type: 'square'
    };
  }, {size: 0});

Collection reduce

The above reduce function applied to a collection:

See the Pen Reduce a Collection by Brian Leathem (@bleathem) on CodePen.

Observable reduce

The reduce function applied to an Observable:

Note

You will want to click the RERUN button that appears when you mouse-over this codepen. Then wait until the input Observable terminates to see the reduce result.

See the Pen Reduce an Observable by Brian Leathem (@bleathem) on CodePen.

Zip

The last function we will look at is the zip function which is used to combine many Observables into a single observable. It accomplishes this by taking each Observable as a parameter, followed by a function that is used to "combine" the object retrieved from each Observable.

In the following code sample we combine our shapes by creating a new shape with the color of the first shape, but the size and type of the 2nd shape.

var outputData = Rx.Observable.zip(
  input1Data,
  input2Data,
  function(x1, x2) {
    return {
      id: x1.id
    , color: x1.color
    , size: x2.size
    , type: x2.type
    };
  });

Observable zip

See the Pen Zip an Observable by Brian Leathem (@bleathem) on CodePen.

The rest of the talk

In the remaining slides I discuss creating and subscribing to Observables, and went through a number of use cases and examples. I ended with a preview and brief code walk-through of the Red Hat Summit Middleware keynote demo, that I wrote using Rx.js. But that is a topic for another post.

The slides are available at:


blog comments powered by Disqus