Functional Reactive Programming - Streams on steroids

Wojciech Marusarz
July 4, 2018

What is functional reactive programming at all?

Functional reactive programming is a programming paradigm that connects reactive programming with asynchronous data streams and uses building blocks of functional programming. Just like other programming paradigms, it is not a brand new idea. The concept was introduced in 1997, but it gains in popularity since 2014 when Reactive Manifesto, mentioned later, was published.

Why asynchronous data streams?

Usually interaction with mobile, desktop or web applications is about submitting the whole form to the backend and rendering view to the frontend. Nowadays users expect a more real-time experience. After typing some letters in the search field, the user expects to see search results immediately. This is doable if continuous data flow between UI and backend applications is persisted and that’s where data streams play a crucial role.

With reactive programming, it is possible to create data streams out of anything.

Emitted data is captured asynchronously, and handled by defined function. You can also define another function when an error is emitted, and another function when the stream is completed. Sometimes these last two can be omitted, and you can just focus on defining the function for values.

The “listening” to the stream is called subscribing. The functions we are defining are observers. The stream is the observable being observed. This is precisely the Observer Design Pattern.

Why functional programming

Functional Programming raises the level of abstraction of your code so you can focus on the interdependence of events that define the business logic, rather than having to constantly fiddle with a large number of implementation details which are now hidden layer underneath streams. Functional programming also brings a fantastic toolbox of functions to combine, create, map and filter any data streams.

Reactive manifesto

Reactive Manifesto According to the manifesto, reactive systems are

  • Responsive: the system responds on time if at all possible. Responsiveness also means that problems may be detected quickly and dealt with effectively.
  • Resilient: system remain responsive in case of failure, failures are contained with each component isolating components from each other.
  • Elastic: system stays responsive under changing workload, reactive systems can react to changes in the input rate by increasing or decreasing the resources allocated to services.
  • Message Driven: relies on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation and location transparency.

Reactive systems are thus more flexible, loosely-coupled and scalable. This makes them easier to develop and to allow changes. They are significantly more tolerant of failure and when failure does occur they meet it with elegance rather than a disaster.

Reactive Programming Implementation

Why should I even care?

Typical server side applications are developed in an imperative style based on subsequent calls of operations that are put on a call stack. The primary function of the call stack is to keep track of the caller of a given routine, execute the invoked routine while blocking the caller in the process, and returning control to the caller with a return value.

For event-driven applications call stack is not the main concern. The primary concern is somewhat triggering events by publishers and monitoring events streams by observers. The big difference between event-driven and imperative style is that the caller does not block and hold onto a thread while waiting for a response.

The event-loop itself may be single threaded, but concurrency is still achieved while invoked routines go about their business (and potentially block on IO themselves) while allowing the (sometimes single) threaded event-loop to process incoming requests.

For the sake of example, let’s look at a time-consuming process like search among big data set which returns the whole response as a single batch. However, what about bringing items just after they are found as in the example below. Records are stored in a big collection in MongoDB, so the search for items that contain phrase takes some time. To increase user experience, records appear on the screen one after another without waiting for the whole operation to complete.

Reactive Movies Example

To achieve such effect as presented above you need to use Server-Sent Events (SSE). API code that produces the stream of movies is really simple. Just note response Media Type which is TEXT_EVENT_STREAM

@GetMapping(value = "/search", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Movie> search(@RequestParam String query) {
   return movieRepository.findByQuery(query);
}

At client side, you need to handle Event Stream by listening on incoming messages.

setupStream (query) {
   this.loadingMore = true  //show progress bar
   let eventSource = new EventSource('http://localhost:8080/search?query=' + query)

   eventSource.addEventListener('message', event => {
     let movie = JSON.parse(event.data)
     this.movies.push(movie) //push movie to array observed by VUE
   }, false)

   eventSource.addEventListener('error', event => {
     if (event.eventPhase === EventSource.CLOSED) {
       this.loadingMore = false  //hide progress bar
       eventSource.close()
     }
   }, false)
 }

Simple isn’t it.

Note that Server-Sent Events are not supported by IE, you need to use polyfill to ensure compatibility with your favorite browser.

Reactive programming support

Reactive Programming is supported by a majority of popular languages which implements ReactiveX API like Java, JavaScript, C#, Scala, Kotlin, Python or Go.

For Java, there are two most popular reactive libraries - RX Java 2 and Project Reactor which are very similar. At Nexocode we use Project Reactor for backend since it is used in Spring by default, but there are no obstacles to use RX Java 2 with Spring as well. For front-end application we use RxJS.

Reactor is a fully non-blocking foundation with effective demand management. It directly interacts with Java 8 functional API, Completable Future, Stream, and Duration.

Reactor offers two reactive composable API: Flux and Mono extensively implementing Reactive Extensions. Flux (Flowable in RX Java 2) represents an asynchronous sequence of 0 to N emitted items. Mono (Single in RX Java 2) represents at most one emitted item.

Like other reactive libraries, it brings a ton of useful operators, which you can find in Mono and Flux documentation or you can look at an excellent visualization of stream operators with marble diagrams.

Debounce Animation

Legacy applications

The dream is to write a brand new application without dependencies on legacy databases or legacy APIs. At Nexocode we develop new projects from scratch. Where it is possible, we implement Reactive Programming approach from “top to down” using Reactive Mongo (Spring Data supports MongoDB, Apache Cassandra, and Redis) and WebClient for network communication. Still, we have to communicate with external APIs.

Fortunately, there is a solution for that too. Instead of waiting for external API calls to be completed, reactive libraries bring a set of wrappers, that can create streams over blocking events. That is not a perfect solution since it requires waiting for requests to finish, so it disallows stream processing, but at least the caller’s thread is not blocked, which results in smaller computational consumption.

Any disadvantages?

Generally, I feel that I write more efficient and much more readable code with reactive rather than imperative approach, but Reactive Programming also may have some disadvantages.

First of all, this paradigm is more memory expensive, because it requires to store immutable streams of data most of the time.

From the developer, it requires some effort to change the way of thinking because of different programming paradigm, which is also not described as thoroughly as Object-Oriented programming which is the most popular.

For me, the biggest drawback is that during development, debugging is more complicated, because you need to debug not only your implementation, but also need to take care of correct stream API usage. Furthermore, your implementation is wrapped with stream API.

Conclusion

All of the above scratches the surface of developing reactive applications. It seems that Reactive Programming isn’t just another trend but rather the paradigm for modern software development that encourages writing efficient and readable software that brings user experience on next level.

Regardless of the language or toolkit you choose, putting scalability and resilience first in order to achieve responsiveness is the only way to meet the expectations of users. This will only get more important with each passing year.

Now, let's talk about your project!

We don't have one standard offer.
Each project is unique, rest assured that we will approach the next one full of energy and engagement.

LET'S CONNECT