Ascending Functional Reactive Programming 1/7
Why is Reactive Programming so Complicated?
The adventure began long ago, with the rise of the browser and the birth of JavaScript. Being a Web developer has been fun since the early days, mastering the always evolving power of these emerging technologies to build ever more exciting applications. The thrill of programming is like the thrill of climbing, the higher, the more frightening. Reaching the top of a summit only satisfies for a brief moment, always seeking the horizon in an endless quest for the grail. Let me chronicle my ascent of Functional Reactive Programming…
Part 1/7 Why is Reactive Programming so Complicated?
Part 2/7 Functional Programming to the Rescue?
Part 3/7 Why is Functional Programming so Controversial?
Part 4/7 Functional Reactive Programming: Simple and Unanimous?
Part 5/7 How did Functional Reactive Programming Originate?
Part 6/7 Where is Functional Reactive Programming Now?
Part 7/7 Which Functional Reactive Programming is the Grail?
Disclaimer: if you are looking for a quick answer to the question “What is Reactive Functional Programming?”, you might be better off finding another source of information. I have put in this series loads of things I found, wandering the web during my long yet incomplete quest on the subject so, if you follow me, get ready for a very long journey. Alternatively, in case you are in a hurry, you can still take your chance with these posts and skip paragraphs using your gut feeling. Notably, you may skip code snippets to stay focus on the concepts. The goal of my explanations is for you to answer the question: Should I care or should I not?
1. What is Reactive Programming
My quest starts right here, right now, at the very nature of reactive programming since this is my every day job.
The Wikipedia article “Reactive programming” seems very different from what I describe here (except for the paragraph “Similarities with observer pattern”) because the Wikipedia article exhibits solutions where I exhibit the problem. Here is my own definition of reactive programming which stresses an inversion of programming paradigm:
“In traditional programming, your program calls the framework while in reactive programming, the framework calls your program”
I reckon this definition is not ideal because it needs the word “framework” to be precisely defined. Instead, I will use the most obvious example: JavaScript in the browser.
For this article, we will consider that a script downloaded by the browser can be sum up to 3 types of statements (caution: this is not official, it’s just the way I want to present it): global variable declarations, function declarations, immediate statements.
1.1. Global variable declarations
Bad: avoid global variables (by the way, this is official)! We will come back to the matter later on, in the third article of this series.
1.2. Function declarations
This is typically the major part of your script.
Here is an example of function we will use in just a moment:
function focusEmailAddress(){
// set the focus to the input element the user needs to type first
firstdocument.getElementById("emailaddress-input").focus();
}
Note that you can use variable declaration and function expression for the same purpose:
var focusEmailAddress = function(){
// set the focus to the input element the user needs to type first
firstdocument.getElementById("emailaddress-input").focus();
};
I will not go further into all possible variants offered by the JavaScript language.
1.3. Immediate statements
Although this part may be restricted to a minimum, your script would be useless without it since defining variables and functions does nothing by itself.
By immediate instruction, I basically mean any JavaScript code that is not a declaration and is outside of all function declarations. We will see some typical examples in the following sub-sections.
It is recommended that immediate statements be limited to calling one of the defined function.
I distinguish 3 cases of immediate statements:
1.3.1. Tweaking the HTML page through the DOM API
You typically want to keep this to the minimum and download an HTML page which initially fits the user.
Here is an example that might still make sense (calling the previously defined function focusEmailAddress):
// set the focus to the input element the user needs to type first
focusEmailAddress();
1.3.2. Defining event handlers
This is where the reactive programming comes into play.
In the following example, we want the defined function “login” to be called when the user clicks the HTML button with the “login-button” id:
document.getElementById("login-button").onclick = login;
This attaches the onclick event handler of the login button to the login function.
We may say that the button is the source of the event and that the login function is an “observer” of the button.
There are other noticeable ways to define event handlers:
1.3.2.1. <button id=”login-button” value=”login” onclick=”login()”/>
This event handler definition is very simple (it is pure HTML and requires no JavaScript).
Some consider that this way of programming is not truly reactive: the source of the event has to manage its observers (tight coupling).
1.3.2.2. document.getElementById(“login-button”).AddEventHandler(“click”, login);
Using AddEventHandler is recommended notably in case of several event handlers.
Some consider that this way of programming is truly reactive: the source of the event does not have to manage its observers (loose coupling).
Also for the record, do note that the login function above is called a “callback” function (go figure!).
I am aware that most readers already know all about this but those of you who did not may stop reading now an go tell all your colleagues and friends that you have discovered something really incredible.
Should I care or should I not?
Do not overreact to reactive programming!
2. Simple Reactive Programming?
Although reactive programming is simple to explain (as I hope I did in the previous chapter), we will see that a reactive program may end up being not as simple as one would expect.
2.1. Spaghetti theory
Caution: not an official theory! Yet!
As soon as your requirements go beyond a trivial web application, reactive programming can quickly become a real mess.
While it is easy to get a spaghetti dish with traditional programming, it is even easier with reactive programming to get a spaghetti dish, up-side-down.
Note that the observer pattern where the source of the event does not have to manage its observers (explained previously) may greatly help organizing the code and limit coupling.
2.2. Chaos theory
Caution: this is an official theory but the following statements have no official proof! Yet!
The Cynefin model distinguishes obvious, complicated, complex and chaotic systems.
Let a real world applications with complicated requirements, what kind of program will we manage to write, obvious, complicated, complex or chaotic?
In traditional programming, calling a function which calls other functions, in turn calling other functions, etc… generates… an obvious system (thanks to abstraction) or may be a complicated system (in case you want to understand the full call stack).
In reactive programming, passing a callback function, to a callback function of yet another callback function which is called by other callback functions, in turn calling other callback functions, etc… generates… a complex system (sometimes referred to as “callback hell”) or most probably a chaotic system (when bugs manage to creep in).
2.3. Asynchronous programming vs synchronous programming
Reactive programs are inherently asynchronous since events typically occur any time depending on sources outside the system (the user, the remote server, …).
An asynchronous system is at least one level of complexity higher than the corresponding synchronous system (my conjecture is that complexity gets exponentially higher).
Various attempts have been made to make asynchronous systems… synchronous… with various downsides:
2.3.1. Blocking
The easiest way to make a asynchronous system synchronous is to block the program until it gets the reply to any request.
Downsides: the program does nothing but waiting, the GUI freeze, not mentioning the cases where the reply never comes.
2.3.2. Threads
To avoids the downsides of blocking the program, each requests gets its own execution thread so other things can continue concurrently.
Downsides: if there is one thing more complex than an asynchronous system, it is surely a concurrent system (actually both systems may be considered equivalent, at best).
2.3.3. Promise, generator and async/yield
Recent versions of JavaScript (ECMAScript 6) provides the Promise object as well as two other related mechanisms (generator and async/await).
Downsides: although the syntax may enhance the formalism of the programs, the inherent complexity is still there, waiting (no pun intended) for the next level of simplification. Why does the word “derisory” comes to mind?
2.4. Disparities
In the first chapter of this article, I used DOM events (such as mouse clicks) as an example to introduce reactive programming. Actually, in a real world Web application, there are many event types to deal with: keyboard events, mouse events, HTTP download, AJAX results sent back from the server, timers, smartphone and tablet specific events, …
One of the challenges of reactive programming is to provide an abstraction modeling all the existing event types in a consistent way, even those that will be invented in the future. Check out one of the following posts in the series dealing with the Stream abstraction.
Should I care or should I not?
If you are reading these post and you have reached this point, I assume you are involved somehow in writing complex real world reactive programs, so I assume you care about keeping things as simple as possible.
My quest continues with the next post in the series, Functional Programming to the Rescue?
Thanks
I would like to thank my colleagues at Esker-Labs for their kind “adwises” (wise advises).
About the author
Nicolas Roumiantzeff is a developer team member in one of 10 R&D scrum teams at Esker, a French SaaS company, where he designed and implemented several client-side JavaScript frameworks for highly customizable Web applications.
He likes music, JavaScript (he might already have told you that) and planet Earth.
His tech superheroes are:
Albert Einstein who showed that you could achieve astonishing findings with an extremely cheap experiment, long before the browser console is at your (F12) fingertips,
Andrew Wiles who showed that you could reach your most inconceivable dream even if your first attempt fails,
Alan Turing who showed that you could prove the unprovable,
Grigori Perelman who showed that being skilled in rocket science does not prevent you from being skilled in rocket lifestyle,
Brendan Eich who showed that such a big huge impact could come out of such a tiny little thing.