We often hear the terms Reactive Programming, Reactive Extensions, and RXJava and the hype around them, but sometimes we can't get our head around these terms and still need clarification.

In this post, we give an easy and straightforward introduction to reactive programming.

This article is the first among series that will go heavier on the code.  In this article, we'll talk mostly about what reactive programming is, however, why we need it, and where it’s useful.
 

Reactive Programming

y = 10, z = 20
x = y + z
print(x)  //30

//Non reactive code
y = 20
print(x) //30

//Reactive code
y = 30
print(x) //50

In the above example, the variable "x" is non-reactive as it doesn't get updated if any of the variables get changed, but in reactive code, the "x" variable updates itself once the value of "y" or "z" gets changed.

Let's take another example: a switch and a light bulb. This structure exemplifies various GOF Design Patterns, i.e. State Design Pattern, Bridge Design Pattern. As you flip the switch, the bulb gets turned on and off.

example

 

In coding terms, the two components are coupled together. Usually, we don't give much thought to how they are coupled, but let's dig more in-depth.

One approach is to have the switch modify the state of the bulb. In this case, the switch is proactive, pushing new states to the bulb; whereas the bulb is passive, merely receiving commands to change its state. It's nothing but the State Behavioural Design Pattern in which an object changes its behavior based on the state it receives.

Here's a snippet of the proactive solution: the switch contains an instance of the LightBulb, which it modifies whenever its state changes.

public class Switch {
  LightBulb lightBulb;
  
  void onFlip(boolean enabled) {
    lightBulb.enable(enabled);
  }
  
}

The other way to couple these components would be to have the bulb listen to the state of the switch, and then modify itself accordingly. In this model, the bulb is reactive, changing its state based on the switch's state; whereas the switch is observable, and we can observe its state changes.

Here's a sketch of the reactive solution: the LightBulb takes in a Switch that it listens to for events, then modifies its own state based on the listener.

public static LightBulb create(Switch theSwitch) {
  LightBulb lightBulb = new LightBulb();
  theSwitch.addOnFlipListener(enabled -> lightBulb.power(enabled));
  return lightBulb;
}

To end users, both the proactive and reactive approaches lead to the same result, but there are subtle differences in the approaches.

  • The first difference is who controls the LightBulb. In the proactive model, it must be some external component that calls LightBulb.power(). With reactive, it is the LightBulb itself that controls its luminosity.
  • The second difference is who determines what the Switch controls. In the proactive model, the Switch itself determines what it controls. In the reactive model, the Switch is ignorant of what it's driving, since others hook into it via a listener.
  • In the proactive model, modules control each other directly. In the reactive model, modules control themselves and hook up to each other indirectly.

Did you get the sense that the two models are mirror images of each other? If so, you must have realized that reactive programming is all about writing reactive code.

As per Wikipedia, "Reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change."

The device location, system time, list of entries from DB/API, user clicks, and so forth can be a stream of data. We saw propagation of change in the switch bulb example where the state of the switch gets propagated to the bulb.

Why do we need a Reactive Approach?

Earlier most applications were stateless, CRUD-based services in which we read, updated and deleted from databases, but now most applications continuously process streams of data and respond to changes in events. For example, we have weather forecasting applications which continuously process forecasting data and pop up notifications once the temperature gets changed. Similarly, we could have a stock trading application that receives the stock prices for Google and once the price gets lowered by a specific limit automatically purchases shares for us.

Any application that listens to data streams and acts on them will benefit from a reactive approach.

Also, these kinds of applications could be implemented using the imperative approach as well, but implementing such kinds of applications using imperative programming is a real mess as it doesn't have inbuilt support for asynchronous execution, responsiveness, and resiliency.

On the other hand, reactive programming is a subset of functional programming that already handles the above mentioned key factors. If you need more insight into why imperative approaches are not suitable for reactive applications, please review Prefer Reactive model over Imperative.

In principle, Reactive Programming is an asynchronous programming technique that reacts to data in observable sequences. It defines 'structural programming' in which one component emits data and other components which are registered to receive data will propagate those changes. It is premised on the Observer Design Pattern in which the subscriber subscribes to an observable, and the observable pushes data back to subscribers.

Reactive Programming is not new or fancy. Earlier it was called DataFlow computing.

Reactive programming is just an approach, it is a way of doing things whereas Reactivex(Reactive Extensions) is an implementation of the same. Reactivex is an application program interface (API) for Reactive programming Libraries and it has various language adapters as well.

There are two building blocks of ReactiveX:

  • Observables/Data Source — Component that emits data. Observables are the sources for the data. Usually, they start providing data once a subscriber starts listening. An observable may emit any number of items (including zero items). It can terminate either successfully or with an error. Sources may never terminate, for example, a forecasting source or a Twitter stream.
  • Observers/Subscribers — Components that subscribe to observables to get changes. An observable can have any number of subscribers. If a new item is emitted from the observable, the onNext() method is called on each subscriber. If the observable finishes its data flow successfully, the onComplete() method is called on each subscriber. Similarly, if the observable finishes its data flow with an error, the onError() method is called on each Subscriber. For example, a Mobile application that gets subscribed to a forecasting source, or a stock trading server. Here is a simple example:

     

    X = Y + Z
    X is a subscriber here because it subscribes to the result of Y + Z
    Y & Z are observables because it omits the changes.
    

 

Observers

 

Where the Reactive paradigm fits in?

Reactive programming is a significant and logical step ahead of functional programming. It paves the way to eliminating the state and mutability from your code. It follows the practices of function composition, immutability, and lazy evaluation. (We will see all these principles in action later in this series.) Let's take a closer look at a few advantages:

Let’s take a closer look at a few advantages:

 

Error Recovery Mechanism in Reactive Programming

Imperative programming is terrible at handling exceptions and recovery. For example, let's say you're trying to book a flight from xyz website, and you have entered the source, the destination, and the date of travel.

The moment you hit enter, a new thread is created at the backend to serve your request. Next, you'll be waiting for a list of flights to get displayed, but due to some error at the backend, your web page gets stuck. Now, the end user refreshes the page again, and a new thread is created to serve the new request, and it again goes into the error loop. Moreover, this is how multithreading becomes a mess and results in resource wastage.

In imperative programming, we propagate exceptions upstream. We throw exceptions to the caller method until it reaches the root. Here we treat exceptions as a second class citizen which means, if everything is all right, we return the results, otherwise throw an exception. Now, no method wants to take the responsibility to handle the exception, and they pass it to the root function which would again result in unresponsiveness if exceptions are not handled properly, which we just saw in the last example.

 

last example

 

 

Reactive programming treats errors as a first class citizen and gives proper status to them. It sends an error to the downstream, unlike imperative programming. Observables in RP are connected to subscribers through three channels:

  • Data Channel: Observable passes data to the subscriber through this channel.
  • Complete channel: Upon data completion, observable sends the complete signal to the subscriber through this channel and after that, no data will flow through the Data channel.
  • Error Channel: If any error occurs, that will be passed through this channel and after that, no data will flow through the data channel.

 

error channel

 

We hope that the article helped you understand why we need reactive programming and where it fits in. In the upcoming articles, we will explore RxJava, which is the reactive extension for java, and it's operators, in detail. Stay tuned!