REACTIVE PROGRAMMING WITH KEFIR.JS AND REACT

Functional Reactive Programming (FRP) ideas/concepts have almost two decades but more recently they’re influenced a new formulation of reactive programming called Compositional Event System (CES) popular in libraries like kefir,baconjs,RX. Today you can found implementations of these ideas in many popular languages like c#,java,javascript,c++,etc.

This adoption is motived mostly because reactive programing (RP) simplifies the event handling and data flow being particularly useful (but not exclusive) in UI development: everyday you need more complex interfaces, every component needs react to one or many events and change one or many states, soon we end with many variables and maybe could not be clear which event is changing some variable or what happen if you change X state , you can’t even understand where start and finish your running code because those events are so interrelated than it’s not clear how the data flow and you’ll end with a hard to understand and debug app, maybe we would change our tools.

unfortunately it is hard to find a good learning resources for RP and even worse, it’s hard to find articles focused in people with zero or small knowledge in functional programming.

In the next articles we’ll do an introduction to Reactive Programming (from now onwards just RP) using kefir.js and we’ll end building a TODO app with kefir.js and react. Personally I found kefir.js very well suited for introducing RP because it has excellent performance, a clear and simple documentation and a small api with only those necessary methods, more complex functionalities can be build combining existing methods.

Note: this article was written nearly a year ago and today kefir is much more bigger and complex, I’ll talk with the author (which is very friendly and considered) about provide some kefir lite version or include some kind of visual guide displaying the most important methods.

Likewise you don’t need to have a big experience with functional programming, if you’ve used libraries like underscore/lodash or you know the popular higher order functions from javascript like map,reduce,filter… you’re ready for start learning RP.

Advantages of Reactive Programming

1. Simplicity and abstraction:

Maybe at first look this point would be not so clear and appreciate, but using RP tends to be more simple after you know its foundations: that is because we remove variables and events in favor of just one structure (observables), we’ll have many functions which can be applied over this structure returning a new observable, Alan Perlis said once:

It is better to have 100 functions operating on one data structure than 10 functions on 10 data structures.

2. Flexibility:

RP is supported for several languages and platforms like .Net, javascript, java, even iOS development, also it’s enough flexible to use in the backend and frontend , in this sense RP libs are just tools, not a framework, you’ll find many ways of integrate it in your workflow, in the 3rd article we’ll build a small flux inspired framework using RP.

3. Predictable, obvious and less surprise

For me this is the biggest advantage, RP makes your code much more predictable because the data only flow in one way (similar to facebook flux), also you can know all the time what values is stored in every observable (using logs): if your system fails you only need check which observable is causing the bug and fix it, need to make a change or improvement?, find where is the correct place to add/change your observables and you can be sure than it will not break your system.

Developing in RP is like play to be a plumber, you only need to think about how connect the pipes, here these pipes are named observables

You’ll end with a more cohesive, transparent and clear system, this is helps a lot to understand in a simple way how the data flow across the application.

What you need to know?

Not events, Not variables, Not Promises…Just Observables

When many frameworks add new structures and tool at the existing ones, RP has a different approach and choose only one structure named Observable

Observables are a stream similar to movie film: you start recording every frame and every frame correspond to some specific time in your movie, when you play the movie you notice how the image change, even when all these frames are statics: your data is immutable (with all the immutable benefits) but your app is not static and change (like a movie)

As I said before, working with observables is similar to working with water pipes: the data flows across them, then you can connect them and transform the data, combine pipes and get new results or select pipes which only works in special cases. The analogy doesn’t end here: our data will flow only in one direction, similar to the water inside a pipe, this simplifies the development and makes your code less bugs prone.

Lets start with a simple code, open your console paste this and write:

var ones = Kefir.interval(1000, 1).log()

you’ll notice how every second (1000 milliseconds) a number 1 is printed in your terminal (thanks log method!!), the result is similar to have a pipe and every second introduce in one side a number 1 and in the other side get the number again, not impressive but it’s a first step.

1 1 1 1 ======== 1

also you can bind events:

var stream = Kefir.fromEvent(document.body, 'click').log();

with every click the log will print in your console the event

other useful method is emmiter

var channel = Kefir.emitter().log() 
channel.emit(1)
channel.emit("good!")

here you can pass any data in any moment to your channel, remember than you can connect this observable to other ones and transform or process the data, this is only the initial point in our plumb system

Every water system start where the water enter, in RP the start is where the data income to your system, here we’ve several and well suited methods for handle incoming data: as events with fromEvent, periodically with interval, sequentially, more freely by demand with emitter and so on!

Map …the old known method

Probably you know how to use the map method of the javascript standart library or libraries like underscore or lodash and fortunately they works similar in kefir, this is not a coincidence, in functional terms both, array and observable are functors ,functors implements a map method which allow transform its inner values, for example, you’ve a function which convert from A to B : A->B then if you take an Array[A] and apply the function using the map method, you can be sure than you’ll end with an Array[B], Array is a structure, like a container, you take the values inside this container, apply the function and then package the result in the same container

this image is a great example of functors and map (courtesy of adit.io)

var a = ["1","2","0"] //Array[Strings] 
var StringToInt = function(st){ // String -> Number return Number(st); }
var b=a.map(StringToInt) 
console.log(b)
// [1,2,0]
//Array[Number]
 var square-bus = Kefir.emitter().log("number entered> ")
var squareCalculator = square-bus
.map(function(v) {
return v*v
}).log("squareCalculatorOb > ")
square-bus.emmit(3) square-bus.emmit(4)

you introduce a number in one side of square-bus, this is an emmiter, so it’s only a channel which we can pass values using the emmit method, the other side is connected to squareCalculator which calculate the square number

               square-bus   squareCalculator 3=================3================9 4=================4================16
Classic RP Diagram 
square-bus ---------2------------------------------
map (2*2)
squareCalculator----4------------------------------

REMEMBER

Map allow you access to the inner value(s) from a stream and process them… you can’t handle/manipulate the inner values directly

Scan, like map but with Inner State

Other really useful method is scan, scan is similar to map but it has an inner state, each time its receives a value applies a function and store the result in its inner state, similar to the fold method of javascript but it’s important to remember that we’re not working with arrays but with stream (observables).

When you need store a state in RP it is good idea to start thinking in how use the scan method
var clicks= Kefir.fromEvent(document.body, 'click').log("clicks >"); 
var counterClick = clicks.scan(function(mem,v) {
return mem+=1; },0)
.log("the mem state is> ")
    or in other representation way 
clicks click------click--------click
scan 0+1 1+1 2+1
counterClick 1----------2------------3

There are other useful methods in the kefir documentation for our TODO app we’ll only use scan and map, but filter, take, skip, diff are very useful too and the documentation (and names!!) are pretty clear

Combining Pipes…

Probably we’ll need to combine our observables, remember that in RP we only have observables! Fortunately kefir provide a good collection of methods for combining two or more of them, lets check how they work:

Combine

Combine, as the name suggests, combine two streams applying a function, notice than you use as argument an array of observables

var a = Kefir.interval(4000,1).log("<1>") 
var s = Kefir.interval(500,2).log("<2>")
var combination = Kefir.combine([a,s],function(a,s) { return a + s }).log("combined are ") //combined are 3
        a 
1 1 ======= combination
||============= 3
2 2 ======= a+s
s
-------------using diagram-------- 
a 1-----1-----1-----1-----1
b 2--2--2--2--2--2--2--2--2
combination 3--3--3--3--3--3--3--3--3
notice than combine emit the value both when receive 1 as when receive 2

SampledBy

Probably the most useful combination method is sampledBy, generally you’ll need than your combine method only emit reacting to some specific observable, maybe an event generated observable.

for instance, suppose than we’ve two observables, one is generating a new Date object every second and the second observable is watching the click event, we want alert only when the clickObservable emits and not every second. If we use combine then every second you’ll receive an alert, instead with sampledBy you can choose what observable activate it

var time = Kefir.fromPoll(1000,()=> { 
return new Date();
}).log()
// scared by the new method fromPoll??..you can create it using the // known methods 
var timeAlternative = Kefir.interval(1000,_)
.map((_) => { return new Date() })
var click = Kefir.fromEvent(document.body,"click").log()  
//first argument is an array with those observables that doesn't activate the observable, the second parameter are the observables that activates it 
var message= Kefir.sampledBy([time],[click],(t,c)=> { 
return "you click at position "+ c.x + " , " + c.y + " >>> "+t
}).log()
//onValue will be explained soon 
message.onValue(function(x){ alert(x) })

Subscribing methods…where our pipe system end

Our system received the data, process it and now it needs exit of our RP system, maybe we want display using an alert, appending to the document or using react, always we need use the main observable methods

We have onValue, onError, onEnd depending of which value emit our observable, a good example is the previous one, where we use onValue for alert about the value of our message variable.

All these funcions has side effect, you can’t connect them and they only must be used in the last step of our system for printing the results.

Last considerations

Instead of explain every single method of the kefir api I tried give you a global perspective about what is RP and its more relevant points, RP is not about learn 100 methods and combine them, it’s about a new way of building your apps; learning these methods can be helpful reducing the lines of code than you need write or the time than you spend implementing these.

In the next chapter we’ll apply all this knowledge building the TODO list logic with kefir, maybe you could be a bit lost about how build real apps applying this recent knowledge, don’t be scary, you’ve got all the foundation for build apps using RP and you’ll find that following these concepts the development is pretty logical and clear, even the most sensible aspect about reactive programming: how handle states . Hope you enjoy the article and follow my next articles about this topic…


Please let me know what do you think/love/hate about the article, you can add a note in this paragraph or do a comment, thanks!.

Carlo Medina