Introduction to Reactive Programming


As programmers, many of us have to deal with handling a response data that comes from an asynchronous callback. At first, that seems to work just fine, but as the codebase gets bigger and more complicated we start wondering if there is a better way to handle that response data and surely if there is a better way to unit test it.

Such a better way exists and it’s called Reactive Programming.

In this post, we will present a brief introduction to reactive programming and examine how it can help us build more robust applications.

What is Reactive Programming

According to wikipedia, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.

Well, that may sound a bit complicated and doesn’t really help us understand what Reactive Programming really is.

So in order to keep it sharp and clear, we can describe reactive programming as programming with asynchronous data streams that a consumer observes and reacts to them.

For sure, this is a much easier way to perceive it. However, we should elaborate on a small but crucial detail that differentiates this type of programming; the data streams and their meaning.

In a few words, streams are a sequence of events over time. That’s it, so simple.

For example, a stream could be a user’s action to fill a form on a website. Each keypress is an event that provides us with information on what the user is typing.  A submit button click is an event that notifies us when the user submitted his form and consequently when the stream completed.

Why Reactive Programming

Reactive Programming has gained a lot of popularity in recent years. You probably have read articles or attended lectures on conferences or local meetups about it. You may, though, still wonder why to use it and how it would help you?

The basic concept of Reactive Programming is that everything can be a stream of data. An API response, a list of rows from a local database, an Enum state class, even a button click can be represented as a stream of data able to be observed by a consumer. This stream can be filtered, transformed, combined with another stream or even shared with multiple consumers. Every stream runs on its own non-blocking thread, allowing us to execute multiple code blocks simultaneously, turning part of our application into asynchronous.

How to use Reactive Programming

Reactive Extensions or Rx is an implementation of Reactive Programming principles following Observer pattern, Iterator pattern and Functional Programming. In this way, Rx abstracts away any concerns about threading, synchronization, thread safety or concurrent data structures.

The two key components of Rx are Observables and Subscribers, or Observers. An observable is a class that emits the stream of data. A subscriber is a consumer that subscribes, receives and reacts to the data emitted by an Observable.

We can think observables as event emitters, that emit three events: onNext, onComplete, onError. The common flow of an observable is to emit the data, using the onNext method, and then call the onComplete or the onError method, if an error has occurred. When an observable calls onComplete or onError, it gets terminated. Observables are grouped by hot and cold observables; you can read more about it here.

A subscriber is a class that can observe these three events, by implementing these methods and then calling the subscribe method on the observable.

Rx Operators

By this point, Rx seems quite simple and may not sounds useful enough to start using it. However, this is where the interesting part begins! The Operators. One of the most important features of Rx is Operators. An operator is a function that takes one observable as its first argument and returns another observable. An operator allows us to take an observable, transform it and change its behavior according to our needs. Using an operator we can filter, map or cache the data emitted by an observable, combine two or more observables, chain different observables, specify the scheduler on which an observer will observe an observable, create, delay, repeat or retry an observable and many more. As we can see the true power of Rx comes from its operator. Here you can view the whole list of Rx’s operators

Show me some code

Let’s dive into some code to discover, through a real-world example, the true power of Rx.

In our example, we will borrow the paradigm of a shopping application. When the user enters his shopping cart the flow, described below,  must be executed :

  • Request to API to get user’s cart items
  • Show loading indicator
  • Filter the items that have zero availability
  • Show items to the user
  • Request to API to calculate total price from filtered items
  • Show total price to the user
  • Hide loading indicator

In the code below, we can see how we can execute that flow, with few lines of code, using Rx.

apiManager.getCartItems()
  .doOnSubscribe { showIndicator() }
  .flatMap { items -> Observable.fromIterable((items)) }
  .filter { item -> item.availability > 0 }
  .toList()
  .flatMap { items ->
      showItems(items)
      apiManager.calculateTotal(items)
  }
  .doAfterTerminate { hideIndicator() }
  .subscribe({ price -> showPrice(price) }, { error -> showError(error) })

Looks pretty cool, isn’t it? Well, now imagine creating this with the use of old school callbacks. What a nightmare would be in case any debugging would need!

Overview

Rx is a very powerful tool that helps us write clean, robust and scalable applications plus it tends to be a must for mobile and frontend engineers. Someone may support that familiarizing with this technology may take some time. It is though undeniable that once you reach that point, there is no way back.

How we use it

At ORFIUM we use Rx all over our new mobile applications. Rx is a big part of our new music player, leveraging the abilities of hot observables. Using subjects we can emit the latest state of media player, allowing our views and classes to observe it and react according to its state, without the need to have a reference to the media player itself. Excited as of how helpful Rx proved to be for us and the products we develop, we decided to share our experience with the community and open source a part of our music player in Android and iOS. Stay tuned for our next posts where we ‘ll further elaborate on it!


The article was written by Dimitris Konomis.