You probably just read the words “reactive programming” and immediately checked out. Even though it is a rather complicated topic, you need not worry about it. By the end of this tutorial, you will gain some solid knowledge regarding this topic.
Remember, a healthy dose of struggling is essential for the learning process. So sit back, relax, and enjoy the ride. Let’s begin.
Back to the Beginning
Take a look at the expression below.
If the variables “b” and “c” were both five, then what would “a” equate to? Hopefully, you were able conclude that “a” would equal 10. Now, what would happen if we changed the value of “c” to 6? Mathematically speaking, the correct answer would be 11. We changed one of the variables, and therefore the outcome changes immediately. Makes sense, right?
Funnily enough, there are a few quarks that occur when we bring the example above into the world of programming. Let’s take a look at our little algebraic expression using imperative programming.
What do you think “a” will be this time? If you answered “10”, you are correct! In imperative programming, the evaluation of “a” would never change after it is run, even if we attempted to change the variables to affect “a”. This is imperative programming at its very essence. In order to change “a”, we would need to run another statement explicitly telling the program to change the variable “a” to another value.
Conversely, in reactive programming, we are creating variable evaluations by changing their dependencies. In the case of “a = b + c”, “a” reacts to the changes happening with “b”, “c”, and the particular type of operation we are doing.
Give Me a Real Life Example!
Fair enough. Open an Excel spreadsheet on your computer. Now, enter a simple formula into one of the cells.
If you changed the values of B1 and/or C1, all the cells affected by this formula would be changed instantly. They reacted to a shift coming from the numerous potential values that can be inserted into the original formula. Pretty cool right? As you can probably imagine, reactive programming is extremely powerful. For example, it can be very useful when creating responsive user interface and animations.
Are you still confused? Don’t worry. Here’s another example showing off the power of reactive programming.
What if the excel formula was replaced with a function which maps an air pollution graph that changes depending on a user’s selected location? Thanks to reactive programming, we are able to see the graphical interface change in response to user interaction even as the app is running! Something is changing in our graph function which immediately invokes a response.
You’ve made it this far! Give yourself a pat on the back! You should now understand the basic differences between imperative and reactive programming. Go make some tea, and do some pushups, because we’re about to dive into some of the core concepts surrounding reactive programming.
Degrees of Explicitness
Up to this point, we had been using very basic examples showing reactive programming in action. Our “a = b + c” expression is a very explicit form of reactive programming, because we are literally pushing the flow of changes in one direction.
Our excel example had a bit more complexity, since our cell formula dictates the output of every single cell specific to that formula. Here’s an easier way to imagine the evaluation of the excel cells. Imagine each of the cells as little delivery boxes, and our entire spreadsheet as a factory. For each of the delivery boxes in our factory, we are going to call on our formula to do something with that box. We can change the contents of the box, label the box, or even put the box into a bigger box. The possibilities are endless. Here is some pseudo code for what I just described.
Our formula is acting upon all the boxes inside the factory, and doing something with each of them. We end up with a single formula pointing to a number of boxes, all with varied outcomes. Pretty cool, right?
But wait! There’s more! You can even become more implicit with the direction of transformations using reactive programming. What if we wanted to find a certain group of boxes, or even a specific box? In reality, we would need to go over each of the boxes, find the desired ones, and put them in a separate container. Then, we would need to take that container and find the specific box. We can see that this particular example is much more implicit than the previous examples.
Static and Dynamic
This concept is quite simple. Static reactive programming conveys data flows that are set up statically without any form of dynamic input during runtime. Our first example “a = b + c” is static, because we are literally assigning values to “b” and “c”.
A dynamic reactive program can change its data flows during run time. If you’ve ever worked in Photoshop, and created custom colors, you will notice that the color preview changes as you drag the cursor around the color wheel. This is a great example of dynamic reactive programming, because the data flows are being updated as the application is running.
Higher-order Reactive Programming
Higher-order reactive programming sounds like some kind of crazy, advanced terminology. Fear not! This concept is simply stating that data flows from one reactive evaluation can be used to determine the data flow for another evaluation. We actually went over a basic example of higher-order reactive programming in our example with the factory and the boxes.
Let’s get a little more specific. For this example, we will work with a big box full of movies. What if we wanted to find the most expensive movie that was made before the year 2000? Think about the actual steps you would take to physically accomplish that task.
We would need to filter out all the movies that were made before 2000 and put them aside. Now that we have a pile of movies made before 2000, we can then compare prices until we find the highest priced movie. Below is the scenario in pseudo code.
This is seriously cool stuff. You can see that the data stream we get from filtering the movies is then used to find the highest priced movie. We can chain various actions together, using a multitude of data streams to achieve the desired results. Does your head hurt yet?
Differentiated Reactive Programming
Computers are fast and furious. They process large amounts of data with ease, almost in an instant. However, there are times when we need to specify the order of evaluation for data streams. Remember higher-order reactive programming? What if a certain data stream was not processed on time, but needed for another reaction to happen? Bug alert.
Here is where data flow differentiation can come in use. We can allow for the evaluation of the certain data streams to occur first, before setting off the evaluation of other data streams.
If this is still confusing, think about that time when you had to follow a recipe. Did you take all the ingredients you got from the supermarket and toss them all into the pan at once? Obviously not. There is a very specific set of instructions that you must follow, one after the other. You might have to chop up the onions before tossing them in the pan, and you might have to do that only after the oil is sizzling in the pan. It’s a data stream full of onions! Perhaps at some point, you are allowed to toss in multiple items, but these actions are still carried out under guidance from a very explicit set of instructions.
When data is changed in reactive programming, that change will pulse outwards towards all data obtained partially or completely from that original data. Unfortunately, a naive implementation of reactive programming may be problematic for certain data structures. There are data structures where the time it takes to process each data flow compound exponentially. This is not something we want.
A solution to this problem is the proper utilization of differential reactive programming. By controlling the timing of data flows, we can simply tell the program to evaluate when a certain variable is needed.
We use this programming paradigm with a host of other paradigms, including imperative, object-orientated, and functional programming. We’ll save functional reactive programming for another time, but we can talk about imperative and object-orientated reactivity.
Imperative programming is used to act upon reactive data structures, creating one-way data flow constraints. Think of a data graphic that changes depending on other streams of data. Once the data is changed, we can use then utilize imperative programming to recreate a new data graphic.
Creating reactivity within object-orientated programming is quite different. Instead of methods, objects possess reactions that re-evaluate when other reactions have changed. It’s quite powerful. Imagine each and every status update from your Facebook used as a data stream to invoke a series of reactions. Perhaps the status that has the most “likes” from your friends will have higher priority on your newsfeed.
The Facebook Feed
Above is a non-reactive model of the Facebook feed. How do we get data from this feed? We need to loop through the array of comments until we reach the end, and then utilize the information that we get from the traversal. Is there a better way to keep track of new comments in the feed?
Now check out our model as a stream using an Observable. As it receives streams of information, it can perform individual transformations on the streams.
In a reactive model, the data source contains all the concepts and behaviors that it needs to determine when it has new data, when an error happens, or when it completes.
An Observable is simply RxJs’s way of representing a reactive data source. A reactive data source produces data over a period of time, and at some point will either error out, complete, or never complete until the process is terminated. Whenever an Observable gets data, it produces a result.
You can also attach many pipelines of transformation, called subscriptions, to a particular Observable. For example, you could pipe the new data into a particular format and then display it on a web page.
Once subscribed to an Observable, all subscribers will receive an update when the Observable receives new data.
Let’s tie in this new knowledge to better understand the two models of the Facebook feed above.
In the first example, we are pulling data from the model by iterating through it, getting the information, and then doing something with that information. In the second example, the data is being pushed to us without any further instructions. We then subscribe to that data, receive new streams of updates as they come, and then do something with that update.
The second reactive model represents a uni-directional data flow, because our data source become a kind of entry point for our application and our business logic depends on the data source as well. Notice how we don’t need to do anything until the data changes. Hence – reactive programming!
RxJs in Action
We’ve been talking very theoretical about this library, so how it actually works when writing the code.
In the example above, we are getting an Observable that produces new values every time a tweet comes in. We filter out the tweets that do not contain the word “Greetings” in them. The next step is particularly interesting. The flatMap method takes a function that returns a promise or an Observable, and merges it into the stream. After we get the information from our getUserAvatar function, we map our return value to a new image element. Finally, we subscribe to the entire pipeline, and the result of that pipeline is an $avatar object.
When using reactive programming, you need to think in three important steps. What data do we want, what transformations we want to apply, and what we want to do with the final result at the end of all the transformations.
You’ve made it to the end! Hopefully, you now have a grasp on some of the basic concepts of reactive programming! They say that the journey of a thousand miles begins with a single step. Congratulations on taking the plunge into this new programming paradigm. There are many more articles, tutorials, and videos for you to scour and devour. Maybe you’ll even go on to build a reactive app!