Demystifying Reactive Programming — The Overview

Answering What, Why, When, and How?

Srishti Kohli
Walmart Global Tech Blog
6 min readAug 10, 2021

--

The goal as a company is to have customer service that is not just the best, but legendary.” — Sam Walton

We at Walmart are constantly working towards improving our quality of service to enhance customer experience. With our ever-increasing customer base, it’s imperative to build fast and robust applications for better performance and improved UX. That’s where reactive programming comes into the picture.

Let’s begin by answering the question —

“What is Reactive Programming”?

Reactive programming is a declarative programming paradigm concerned with asynchronous data streams and the propagation of change.

Well, that’s a statement cluttered with jargon. Let’s go under the hood to understand more.

Asynchronous

Imagine your application becoming unresponsive because your main thread issued a call to the database and is now blocked while the customer awaits. What next? Your customer defects to your competition and gets their job done. With the reactive approach, a database call does not block the calling thread and instead returns immediately. The program is structured as an asynchronous stream of events. Simply put, you instantly move to the next task after having initiated some background effort to deal with the previous task. That’s being asynchronous!

Data streams

Streams to reactive programming are what Chandler Bing is to Friends. That’s right — The Backbone! Now consider a water tank and a connected pipeline. This tank holds the data(water), hence resonates with a data structure. However, the pipeline doesn’t hold water but transports it. Datastream is more of a pipeline of methods applied to the data as it passes through.

Propagation of change

Reconsider the above example. What is the other end of the pipeline connected to? You — the consumer. Similarly, the streamed data has to be propagated to a consumer. Here ‘change’ refers to the transformation of data that passed through the stream. This changed or transformed data is consumed by observers who subscribed for this change.

The reactive approach involves 4 interfaces:

Publisher-Subscriber Communication

Publisher: It is the data emitter and is also referred to as the Observable.

Subscriber: It subscribes to the observable to consume data and can identify all the emitted events including errors! If the subscriber is slow, it can be easily outperformed by the producer. To deal with this, subscribers or observers can leverage a powerful mechanism called backpressure for controlled throttling of the observables.

Subscription: It’s a session between emitter and subscriber that can be canceled when no more data is needed.

Processors: These consume data from the publisher, apply some operation(eg. map, filter, etc) and produce it to the subscriber. Hence, they can be thought of as a combination of the two — publisher and subscriber.

Notably, this end-to-end system is lazy i.e it doesn’t materialize until subscribed to by a consumer.

Why Reactive Programming?

With the exponential increase in data being handled and an increasing number of concurrent users, there are new specifications that need to be met by a software in order to be competitive. These requirements can be summarised by the four principles of Reactive Manifesto which state that Reactive Systems are:

Message Driven

With the increasing complexity of applications, developers have turned from the traditional monolithic approach to microservices architecture. These loosely coupled services interact with each other and exchange data in form of messages. Reactive systems employ asynchronous message communication between components to delegate both data as well as failures.

Responsive

CRUD applications with blocking IO operations not only result in inefficient utilization of the system resources but also higher latencies and poor performance. Consequently, there’s a wastage of your money and your customer’s time — that’s the last thing an organization wants! The user expects results in the blink of an eye. To cater to this requirement, reactive systems focus on providing quick and consistent response times.

Elastic

It is absolutely critical for a system to be able to scale under varying workloads. Elasticity is the ability to scale up or scale down resources allocated to a service based on the load to stay responsive.

Resilient

Failure is inevitable. What matters is how you recover from it. Having the whole application impacted because one module is down is inelegant. The system needs to remain responsive even in face of failure. Resilience is nothing but failing gracefully.

Source

Reactive Programming empowers you to build reactive microservices. It’s noteworthy that reactive programming is not synonymous with reactive systems. It is not mandatory to use reactive programming to build a reactive system. However, it’s a good idea and one of the easiest ways to abide by the reactive manifesto.

When to use Reactive Programming?

Reactive programming is most often the more elegant solution in a multi-user environment or when dealing with huge volumes of data. That’s when you need asynchronous processing to make the application more responsive. There is no merit in adhering to this paradigm completely when it can be seamlessly incorporated just as a component that needs to be made ‘reactive’ instead of changing the coding style of the entire application. It is needless to introduce additional complexity when the same performance is achievable with a simpler approach.

As an industry leader, Walmart is expected to keep its services running seamlessly at all times. For improved scalability and performance, we adapted modern event-driven architecture crafted to operate with many more concurrent processes and end-users without requiring supplementary computing power.

Some real-life solutions going reactive in retail and e-commerce:

  1. Catalog view- Suppose you search for “jeans” on an e-commerce website; immediately the page fills up with the result. You scroll down infinitely only to realize there is no more data. Instantly, the page fills up with more data. Why? Because that data was brought upfront only when it was required. As an outcome, we saved our servers from unnecessary load while delivering highly interactive UI.
  2. Product Listing- Consider a seller who wants to sell their inventory on an e-commerce website. They upload and list their items one at a time. Item listing being a latency-bound event is executed asynchronously. Thus the seller is not blocked from setting up the next item. Seller Experience++;
  3. Shipment tracking- A classic example of streaming data is data from GPS signals changing with time. It’s likely that the downstream observer may choke up and a bottleneck is created. That’s where we can employ the backpressure strategy for flow control.

How to go Reactive in Java?

There are a number of implementations of reactive programming in Java.

  1. RxJava — library for composing asynchronous and event-based programs by using observable sequences.
  2. Project Reactor — reactive library, based on the Reactive Streams
    specification, for building non-blocking applications on the JVM.
  3. Reactive Streams API — Introduced in Java 9, it’s an initiative to provide a standard for asynchronous stream processing with non-blocking backpressure.

It is going to take a good amount of experience and time before getting used to this coding paradigm. Let’s get our hands dirty with a simple implementation using Reactor as the reactive programming library.

Consider a trivial publisher that emits integers every second and a subscriber that consumes twice the even integers emitted.

Reactor Example

The above code produces the following output before the main thread times out:

The Crux

To sum up, reactive programming is a coding style involving asynchronous data streams. It provides simpler means for working in distributed asynchronous nonblocking ways. So is reactive programming the future? Although this is a strong statement to make, it is evident that we are already branching towards the world of asynchronous programming to build fast and fault-tolerant systems.

References

--

--