Scala Reactive Programming

4.3 (4 reviews total)
By Rambabu Posa
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Started with Reactive and Functional Programming

About this book

Reactive programming is a scalable, fast way to build applications, and one that helps us write code that is concise, clear, and readable. It can be used for many purposes such as GUIs, robotics, music, and others, and is central to many concurrent systems. This book will be your guide to getting started with Reactive programming in Scala.

You will begin with the fundamental concepts of Reactive programming and gradually move on to working with asynchronous data streams. You will then start building an application using Akka Actors and extend it using the Play framework. You will also learn about reactive stream specifications, event sourcing techniques, and different methods to integrate Akka Streams into the Play Framework. This book will also take you one step forward by showing you the advantages of the Lagom framework while working with reactive microservices. You will also learn to scale applications using multi-node clusters and test, secure, and deploy your microservices to the cloud.

By the end of the book, you will have gained the knowledge to build robust and distributed systems with Scala and Akka.

Publication date:
February 2018
Publisher
Packt
Pages
499
ISBN
9781787288645

 

Chapter 1. Getting Started with Reactive and Functional Programming

In recent times, the word Reactive has gained popularity far and wide. We can see this word in all IT books, magazines, blogs, tutorials, videos on YouTube, and so on.

Almost all programming languages, tools, IDEs, and platforms already support the Reactive architecture and the rest will move to it soon.

Here are some terms that are commonly heard in the Reactive world:

  • Reactive, Reactiveness, Reactive Manifesto, and Reactive Streams
  • Reactive programming (RP), Function Reactive Programming (FRP), OOP RP, Imperative RP, and Reactive Engine
  • Reactive system, Reactive applications, Reactive microservices, and Reactive Web Applications
  • Reactive Architecture, Reactive Design Patterns, and Reactive principles
  • Reactive tools, Reactive Platform, and Lightbend Reactive Platform
  • Reactive Extensions (Rx)—Rx Scala, Rx Java, Scala, Akka, Play Framework
  • Java Reactive API and Spring Reactor project

Are you really curious to know what Reactive is? Do you have the following questions and more in your mind—What is Reactive programming? Why do we need it? How do we write RP? Why is FP good for RP? What are the benefits of RP?

If yes, this book is for you. I'll introduce you to the Reactive World in a simple and easy way. I like a Diagram/Example-driven approach to learn new concepts and I feel you will like it too.

We can develop Reactive applications using a wide variety of languages or technologies. However, we will use Lightbend Reactive Platform in this book to develop our Reactive microservices.

Welcome to the Reactive World! Let's understand the Reactive World now. In this chapter, we will discuss the following topics:

  • What is Reactive? What is RP and FRP? What are the benefits of RP?
  • What is the Reactive Manifesto and what are its main goals?
  • Why is FP the best fit for RP?
  • What is the Java Reactive Streams API?
  • A discussion on the Flow API
  • What are Reactive Extensions?
  • What is the difference between Reactive and Observer Design Patterns?
  • What are RP Operators?
  • Marble diagrams for RP Operators
 

Introduction to Reactive


Before diving into the Reactive Manifesto, Reactive Streams Specification, or Java 9 Flow API, and Functional Reactive Programming (FRP), we will first understand the meaning of Reactive and Reactive programming in this section.

What is Reactive?

Reactive means reacting to changes in a timely manner or responding to changes in a timely manner.

Here, in the Reactive World, we can represent a change as an event. So we can also define Reactive as reacting to events in a timely manner. This change can occur on data or data elements.

Whenever a change occurs in our system, the system should react to those changes immediately in a timely manner. In the current world, users expect a response from an application (website, web application, mobile application, and so on) quickly and in a timely manner. If the system or application does not respond to the user (or customer) in a timely manner, the user will look for some other option and our application will lose its users.

In the Merriam Webster dictionary, Reactive means being readily responsive to a stimulus (check out https://www.merriam-webster.com/dictionary/Reactive).

Note

In the Reactive World, a change is an event. In Reactive systems, we represent that event as a message. We will discuss why we need to represent an event as a message in detail in subsequent sections.

What is Reactive programming?

Unlike imperative programming (IP) or (Object-Oriented Programming) OOP, where we write our code in terms of the order of lines or statements, in Reactive programming (RP), we write the code or programs in terms of events.

In simpler words, RP means writing programs using events, or RP means writing programs that define how to react to events. As we discussed, events are changes in the state of the program or application. So we can also define RP as follows:

Reactive programming is a kind of programming paradigm to that propagates changes.

Let's discuss one of the important and frequently used RP examples (almost all books or tutorials use the same scenario). Consider the following example of a spreadsheet application:

Observe that the A3 cell has a formula =A1+A2, that is, A3 is the sum of the values of the cells A1 and A2.

Initially, A3 has a value of 0. When we change the value of cell A1 or A2, or both, the spreadsheet updates the value of A3:

We can observe that the cell A3 is updated with 3 automatically; this is Reactive programming.

What is a data stream or stream?

In Reactive programming, we write programs to work on a sequence of events. For instance, in a spreadsheet, we can observe the following events in a sequence:

  1. The user enters a value 1 into cell A1. When the user inputs data into cell A1, the value in cell A3 is updated to 1.
  2. The user enters a value 2 into cell A2. When the user inputs data to cell A2, A3 is updated to 3.

In the Reactive World, this sequence of events happening over time is known as a stream, events stream, or data stream. The following diagram shows how a sequence of events forms an events stream. It also shows how a Publisher sends events to an event stream and how a Subscriber receives events from that event stream: 

A stream or data stream is a sequence of ongoing events ordered in time.

In RP, the Publisher sends events to a Stream, and the Subscriber consumes those events from the Stream.

To react to events, we should monitor them. In RP, the process of monitoring events is known as listening to events or subscribing to events.

We can also define RP using this data stream:

RP is a programming paradigm to do programming with asynchronous data streams.

Note

Event stream = A sequence of events

RP versus Reactive systems versus Reactive architecture

A Reactive system is a set of components that communicate with each other reactively. By combining those individual components into one, we can form a modern distributed system. We can develop a Reactive system by following a set of architectural design principles.

Reactive system components work as a single system and they react to changes in a timely manner.

Reactive systems or Reactive applications have the following features:

  • Responsiveness: They react to users in a timely manner
  • Elasticity: They react to load
  • Resilience: They react to failures
  • Message-Driven: They react to events or messages

We will discuss these components of Reactive Streams in detail in the Reactive Manifesto section. Reactive Architecture is a technique or a process of designing Reactive systems.

We can develop Reactive systems using many techniques. However, RP or FRP are the best tools to build Reactive systems.

The core principle of a Reactive system is developing its components using a Message-Driven approach, whereas RP is all about writing programs using events, which means it follows an Event-Driven approach.

As we said, a Reactive system is a set of components. We use RP at the component level, which means that we develop each component using RP. We use a Reactive system at the system level.

Event-Driven versus Message-Driven

The core principle of RP is the Event-Driven approach, whereas the core principle of a Reactive system is the Message-Driven approach.

RP gives us the benefits at component level only because events are emitted and processed locally. They cannot work across the network in a distributed system.

Reactive systems give us the benefits at the system level, because messages are processed and communicated across the network in a distributed system.

We cannot get the full benefits just with RP; we should use the combination of RP and the Reactive system.

In a Reactive system with RP, generated events are represented as messages under-the-hood, and they are processed as messages.

Benefits of Reactive systems with RP

We will get more benefits when we use RP as a programming paradigm to develop the components of a Reactive system. The combination of RP and Reactive systems gives us the following benefits:

  • Self-healing: As per the Reactive Streams specification, RP should support Resilience. This means we can write Reactive systems in a way that they have some technique to recover from failure and continue working to give responses to the clients. This is known as self-healing. A client will not know about this, and they will never see those failures.
  • Highly available systems: As per the Reactive Streams specification, RP should support Elasticity (scale up/down and scale out/in). This means we can write Reactive systems in a way that they are always available. They support 100% up time.
  • Highly Scalable to support heavy loads.
  • Loose coupling.
  • Utilizes system resources (both hardware and software) efficiently.
  • Provides better responsiveness.
  • Provides real-time behavior or data streaming.
  • Easy to perform distributed data processing.
  • Supports Location Transparency.
  • Low latency.
  • Better performance.
  • Ease of maintainability.
  • No need to use anonymous callbacks (so no more callback hell).
  • Easy to address and handle failures.
  • Easy to reason about failures.

We should also understand the things that are forcing us to develop and use Reactive systems:

  • IoT (Internet of Things)
  • Cloud environment or services
  • Big data systems
  • Real-time fast data streaming
  • Mobile architectures
  • Communication between heterogeneous systems
  • Multicore hardware architecture

Note

Here, Reactive systems means Reactive Web Applications, Reactive applications, and Reactive microservices. In my point of view, all have the same meaning.

So far, we have discussed Reactive World, that is, RP. Now, it's time to enter the Functional World, that is, functional programming.

 

Functional programming


So far, we have discussed RP. Now it's time to move to FP (Functional Programming). Before discussing FRP, we should understand what FP is. We will discuss what FP is, its principles, and its benefits in this section.

What is functional programming?

Like OOP (Object-Oriented Programming), FP is a kind of programming paradigm.

It is a programming style in which we write programs in terms of pure functions and immutable data. It treats its programs as function evaluation.

As we use pure functions and immutable data to write our applications, we will get lots of benefits for free. For instance, with immutable data, we do not need to worry about shared-mutable states, side effects, and thread-safety.

It follows a Declarative programming style, which means programming is done in terms of expressions, not statements.

For instance, in OOP or imperative programming paradigms, we use statements to write programs where FP uses everything as expressions.

Principles of functional programming

FP has the following principles:

  • Pure functions
  • Immutable data
  • No side effects
  • Referential transparency (RT)
  • Functions are first-class citizens
  • Functions that include anonymous functions, higher order functions, combinators, partial functions, partially-applied functions, function currying, closures
  • Tail recursion
  • Functions composability

We will discuss these principles or properties of FP in brief here because we have a dedicated chapter on these concepts. Refer to Chapter 2, Functional Scala, to understand these concepts in-depth with some simple examples.

A pure function is a function that always returns the same results for the same inputs irrespective of how many times and where you run this function.

We will get lots of benefits with immutable data. For instance, no shared data, no side effects, thread safety for free, and so on.

Like an object is a first-class citizen in OOP, in FP, a function is a first-class citizen. This means that we can use a function as any of these:

  • An object
  • A value
  • A data
  • A data type
  • An operation

In simple words, in FP, we treat both functions and data as the same.

We can compose functions that are in sequential order so that we can solve even complex problems easily. Higher-Order Functions (HOF) are functions that take one or more functions as their parameters or return a function as their result or do both.

For instance, map(), flatMap(), filter(), and so on are some of the important and frequently used higher-order functions. Consider the following example:

map(x => x*x) 

Here, the map() function is an example of Higher-Order Function because it takes an anonymous function as its parameter. This anonymous function x => x *x is of type Int => Int, which takes an Int as input and returns Int as its result.

An anonymous function is a function without any name.

Refer to Chapter 2, Functional Scala, to understand these concepts very well. I have provided a useful description and also some simple and easy-to-understand examples.

Benefits of functional programming

FP provides us with many benefits:

  • Thread-safe code
  • Easy-to-write concurrency and parallel code
  • We can write simple, readable, and elegant code
  • Type safety
  • Composability
  • Supports Declarative programming

As we use pure functions and immutability in FP, we will get thread-safety for free.

One of the greatest benefits of FP is function composability. We can compose multiple functions one by one and execute them either sequentially or parentally. It gives us a great approach to solve complex problems easily.

Functional Reactive programming

The combination of FP and RP is known as function Reactive programming or, for short, FRP. It is a multiparadigm and combines the benefits and best features of two of the most popular programming paradigms, which are, FP and RP.

FRP is a new programming paradigm or a new style of programming that uses the RP paradigm to support asynchronous non-blocking data streaming with backpressure and also uses the FP paradigm to utilize its features (such as pure functions, immutability, no side effects, RT, and more) and its HOF or combinators (such as map, flatMap, filter, reduce, fold, and zip).

Note

Refer to Chapter 7, Working with Reactive Streams, to know more about backpressure.

In simple words, FRP is a new programming paradigm to support RP using FP features and its building blocks.

FRP = FP + RP, as shown here:

Today, we have many FRP solutions, frameworks, tools, or technologies. Here's a list of a few FRP technologies:

  • Scala, Play Framework, and Akka Toolkit
  • RxJS
  • Reactive-banana
  • Reactive
  • Sodium
  • Haskell

This book is dedicated toward discussing Lightbend's FRP technology stack—Lagom Framework, Scala, Play Framework, and Akka Toolkit (Akka Streams).

FRP technologies are mainly useful in developing interactive programs, such as rich GUI (graphical user interfaces), animations, multiplayer games, computer music, or robot controllers.

Types of RP

Even though most of the projects or companies use FP Paradigm to develop their Reactive systems or solutions, there are a couple of ways to use RP. They are known as types of RP:

  • FRP (Functional Reactive Programming)
  • OORP (Object-Oriented Reactive Programming)

However, FP is the best programming paradigm to conflate with RP. We will get all the benefits of FP for free.

Why FP is the best fit for RP

When we conflate RP with FP, we will get the following benefits:

  • Composability—we can compose multiple data streams using functional operations so that we can solve even complex problems easily
  • Thread safety
  • Readability
  • Simple, concise, clear, and easy-to-understand code
  • Easy-to-write asynchronous, concurrent, and parallel code
  • Supports very flexible and easy-to-use operations
  • Supports Declarative programming
  • Easy to write, more Scalable, highly available, and robust code

In FP, we concentrate on what to do to fulfill a job, whereas in other programming paradigms, such as OOP or imperative programming (IP), we concentrate on how to do. 

Declarative programming gives us the following benefits:

  • No side effects
  • Enforces to use immutability
  • Easy to write concise and understandable code

The main property of RP is real-time data streaming, and the main property of FP is composability. If we combine these two paradigms, we will get more benefits and can develop better solutions easily.

In RP, everything is a stream, while everything is a function in FP. We can use these functions to perform operations on data streams.

 

Reactive Manifesto


Reactive Manifesto is a manifesto that describes how to design and architect Reactive systems according to your needs. It describes the four traits of Reactive systems. As of now, we are using Reactive Manifest v.2.0, which was initially published on September 16, 2014.

As per Reactive Manifest 1.0 (initial and old version), Reactive systems are Responsive, Scalable, Resilient, and Event-Driven.

As per Reactive Manifest 2.0, Reactive systems are Responsive, Scalable, Resilient, and Message-Driven.

We can find the manifesto on GitHub as a repository, available at https://github.com/reactivemanifesto/reactivemanifesto.

Need of Reactive Manifesto

We need to understand what the main need of Reactive Manifesto is, so that we will get clear picture about it.

The main needs or goals of Reactive Manifesto are as follows:

  • Users or customers need responses in a timely manner. They don't like slow responses and they don't use slow systems. If they don't get quick responses as needed, they will look for other options.
  • We should have an API to support asynchronous streaming data with non-blocking backpressure.
  • API for Reactive Technology (frameworks, tools, languages, IDEs, and so on) implementors.
  • Heterogeneous Reactive systems should work in an interoperable way.
  • We should have a better approach for consumers to avoid buffer overflow issues.

Principles of Reactive systems

In this section, we will discuss what the four traits or principles of Reactive systems are that we should follow to develop Reliable, Flexible, Scalable, Distributable, and Resilient applications.

Reactive Manifesto defines the following four principles:

  • Message-Driven
  • Elastic
  • Resilient
  • Responsive

This preceding diagram is copied from Reactive Manifesto. These are design and architectural principles. They are also known as the Four tenants of Reactive Streams or Four core building blocks of Reactive Streams.

We will pick up each trait one-by-one and discuss it in detail in subsequent sections.

Message-Driven

The core or base principle of the Reactive systems is Message-Driven architecture. It is the foundation principle or method for the rest of the three principles—Elasticity, Resilience, and Responsiveness.

This means a Reactive system depends on asynchronous message-passing between its components to use the benefits of Message-Driven architecture for free.

In simple words, Message-Driven = React to messages.

Even though RP represents the system's changes in terms of events, a Reactive system converts them into messages under the hood.

One more important point to note is that in a Reactive system, even failures are represented as messages, so it's easy to perform failure handling.

So, in a Reactive system, all of its components communicate with each other by sending messages. The Message-Driven approach gives us the following benefits:

  • Messages are immutable by design
  • They share nothing, so are thread-safe by design
  • They provide loose coupling between system components
  • They can work across the network, so they support Location Transparency
  • They support scalability
  • They support Resilience because they avoid single-point-of-failure using partitioning and replication techniques
  • They support better throughput
  • They provide easy-to-apply backpressure

So in RP, we write code in a stream of events, and then Reactive systems convert them into a stream of messages.

Elasticity

Elasticity means scalability. Our system should support scale up/scale down and scale out/ scale in. Our Reactive system should support scale up/scale out so that it responds to the users in a timely manner. It should also support scale down/scale in order to save our organization cost.

In simple words, Elastic = React to load.

This means our system should respond to users in a timely manner even at a heavy load.

With this property, a Reactive system can allocate and/or deallocate resources for every component dynamically and automatically to match demands.

If our Reactive system follows the Message-Driven approach, it supports Elasticity easily:

Elasticity = Scale up/down + Scaleout/in

Scale up: When the load increases, a Reactive system should be able to easily upgrade it with more and more powerful resources (for instance, more CPU Cores) automatically, based on the demand:

Scale down: When the load decreases, a Reactive system should be able to easily degrade it by removing some resources (for instance, CPU Cores) automatically, based on demand:

Scale out: When the load increases, a Reactive system should be able to easily extend it by adding some new nodes or servers automatically, based on the demand:

Scale in: When the load decreases, a Reactive system should be able to easily sink it by removing some nodes or servers automatically, based on the demand:

Resilience

Resilience is not just fault-tolerance, it's beyond fault-tolerance. A Reactive system should fully recover from failure; this is known as self-healing.

In simple words, Resilient = React to failure.

Resilience means a Reactive system should respond to users even in the event of failures, by recovering itself. This is possible by isolating the failure handling to a different component. In a Reactive system, all failures are converted into messages and then processed.

For instance, in Akka Toolkit, Akka Streams (one of the popular Reactive Streams implementations) uses the supervision technique to do this failure handling.

Refer to Chapter 4, Building Reactive Applications with Akka, to understand this Supervision technique.

Note

In a Reactive system:

  • Failures are messages
  • Events are messages

Responsiveness

The last but very important trait is responsiveness. In Reactive systems, Responsive means reacting to the users or customers in a timely manner. Here, we should understand this point—a user should get a response when needed, otherwise they will lose interest and go for other options. In the current Reactive World, the following two things are the same:

  • Not giving response to users when needed or in a timely manner
  • Not giving any response to users at all

Even though our system does give a response to the user at a later time, the user does not need it then. Our system loses the users and ultimately, we lose our business.

In simple words, Responsive= React to users.

After going through these four traits of a Reactive system, we should understand the following things:

  • The main goal of a Reactive system is responsiveness
  • The core method that a Reactive system should follow is Message-Driven
  • The core principles of a Reactive system are Elasticity and Resilience:

The core method of a Reactive system, that is, the Message-Driven approach, will give us Elasticity and Resilience for free:

These three traits of a Reactive system (that is, Message-Driven, Elasticity, and Resilience) give us the main goal or value of that Reactive system—responsiveness.

After going through the Reactive Manifesto, we can represent it in a pictorial form, as shown here:

Why Reactive Streams specification?

In this section, we will understand, first of all, why we really need the Reactive Streams specification. We will also answer a few more questions, like—What is the use of this specification or standard, and who really needs this specification?

RSS (Reactive Streams Specification) is a standard or specification. It explains how to develop frameworks, tools, toolkits, languages, libraries, IDEs, data stores, servers, and so on, which work in Reactive.

Are we getting any benefits by following this specification? Yes. That's why we need this specification.

The main goals or benefits of this specification are as follows:

  • To support reactiveness
  • To support interoperability:

If we observe the preceding diagram, we can understand that many applications are using many Reactive technologies. If they follow their own approach to develop their Reactive systems, then it is a bit tough for them to talk to or work with each other. It is possible to implement some kind of adapters or interfaces to fill the gap and make them work with each other. However, it is not only an old and tedious approach, but also outdated and obsolete.

If we have a specification or standard or API similar to the Reactive Streams Specification and everybody develops their tools, frameworks, and so on, by following this, then there will be no need for extra tools, such as adapters. They can work with each other without using any adapters and without any issues.

This means it enables heterogeneous Reactive systems to work with each other, that is, work in an interoperable way.

As a Java or Scala developer, we know what the use of an API is, why we need it, and who needs it. So, we need a Reactive API or standard or specification to implement or develop Reactive libraries, Reactive servers, Reactive languages, Reactive databases, Reactive tools, Reactive applications, or systems.

Initially, a set of developers from top companies such as Lightbend, Netflix, Pivotal, Redhot, and Oracle Corporation worked together on this area and prepared a specification to develop Reactive systems (or applications) easily. This is known as RSS (Reactive Streams Specification). They requested Oracle Corporation introduce an API to develop Reactive systems easily in a way that they should work interoperably. Finally, Oracle Corporation introduced a Reactive Streams API as part of JEP-266 in JDK 9 (Java SE 9). This API is known as the Flow API.

In the next section, we will discuss this Flow API in detail.

Note

From my point of view, specification, standard, API, interface, abstract, and blue-print are all the same. They have the same meaning.

Why is Play Framework the best for Reactive systems?

Play Framework is the best full-stack web framework available in the current market to develop Reactive Web Applications, Reactive systems, Reactive architecture, Reactive microservices, or Reactive libraries using both FP and RP paradigms, that is, FRP.

The following are the reasons to clarify why Play is good for RP:

  • Play Framework is built on top of the Akka Toolkit
  • By design, the Akka Toolkit supports Reactive Architecture using an Actor Model and Akka Streams
  • Akka Streams is the best Reactive API to develop Reactive data streaming
  • Play Framework has an integrated module for the Akka Streams API
  • Play Framework is written in Scala (a JVM language) and supports both Scala and Java programming languages
  • Both Scala and Java run on JVM
  • Scala supports FP very well
  • FP is the best programming paradigm for RP
  • The latest Play Framework has moved from Iteratees to Reactive Streams
  • It is a full-stack web framework for Reactive programming

Reactive systems versus traditional systems

In this section, we will see the main differences between a Reactive system and non-Reactive system, that is, a traditional system.

The first and foremost difference is that a Reactive system takes a user or customer request as an event or message, and then reacts to those events in a timely manner. Once it's done, it continuously looks for the next event, as illustrated here:

On the other hand, a traditional system takes input(s) from a user, performs an operation based on inputs, and sends an output or response to the user; that's it:

In a Reactive system, the RP model eases the development. As a Reactive system supports abstraction at a very high level, it is easy to develop the applications because we need to concentrate on only our application business logic. Meanwhile, in a traditional system, we need to take care of the application business logic while writing some low-level logic, as it does not support high-level abstraction.

In a Reactive system, changes are propagated automatically. For instance, in a spreadsheet, we have a formula at cell A3, A3 =A1+A2. When we change the value of A1 or A2 or both, then all their references will be updated automatically. This means A3 will be updated automatically. It is not possible in a traditional system or non-Reactive system.

In Reactive systems, we concentrate on the flow of control, whereas in traditional systems, we concentrate on the flow of data.

 

The Java 9 Flow API


Oracle Corporation has introduced a new API for library or API developers to develop Reactive systems, Reactive libraries, Reactive data stores, Reactive servers, and so on. This API is also known as the Flow API.

It defines a set of interfaces to support developing Reactive systems, so it is also known as the Reactive Streams API. This API is defined under the java.util.concurrent package name.

The Java 9 Flow API mainly contains the following components:

  • Publisher
  • Subscriber
  • Subscription
  • Processor
  • Flow

The following diagram shows the main five components of the Java 9 Flow API:

Let's discuss these components of the Flow API one by one in detail in the following sections.

Flow API – Publisher

As its name suggests, Publisher is a component that works as a Producer of data, which means it emits the data. It acts as a source of data, so it is also known as Producer, Source of data, or emitter:

In the Java 9 Flow API, this Publisher is an interface with the subscribe method and is defined with the following signature:

public interface Publisher<T> {   
  public void subscribe(Subscriber<? super T> subscriber);   
}       

Here, the subscribe() method is taking a single parameter of type Subscriber, which is another component of the Flow API. One publisher can subscribe one or more subscribers to it. It is defined within another class as a static component. We will see it in the following section.

Publisher uses this subscribe() method to subscribe or register its subscribers, as shown here.

Go through the following pseudo-code for Subscriber.subscribe() function usage:

Subscriber sub = Receive a Request from a Subscriber 
Publisher pub = ... 
pub.subscribe(sub) 

Publisher receives a request from a subscriber and executes pub.subscribe(sub) to register that subscriber with it. Once that subscription is created, the publisher sends data to those registered parties.

For instance, we can use a data store, file, collection, server, and more, as a source of data to emit data for subscribers.

Flow API – Subscriber

As its name says, the Subscriber is a component that works as a consumer of data. This means it consumes the data from a producer. It acts as a destination of data. So, it is also known as a consumer or destination of data:

In the Java 9 Flow API, this Subscriber is an interface with a set of methods and is defined as follows:

public static interface Subscriber<T> {   
  public void    onSubscribe(Subscription subscription);   
  public void    onNext(T item);   
  public void    onError(Throwable throwable);   
  public void    onComplete();   
}       

It has a set of methods:

  • onSubscribe(): This creates a new subscription. It is invoked prior to invoking any other Subscriber methods for the given Subscription.
  • onNext(): Once a Subscription is created, this is invoked to receive the next data, item, or element from the Publisher.
  • onError(): This is invoked upon an unrecoverable error encountered by a Publisher or Subscription, after which no other Subscriber methods are invoked by the Subscription.
  • onComplete(): This is invoked when there is no requirement to invoke any further Subscriber methods on that Subscription that is not already terminated in error, after which no other Subscriber methods are invoked by that Subscription.

It is also defined within another class as a static component. We will see it in the next section.

Flow API – Subscription

In the Flow API, a Subscription works as a mediator or interface between two other important components, Publisher and Subscriber. It connects those components and works as a message controller or channel so that a Publisher can emit data into a Subscription and one or more subscribers who subscribe to that Publisher and receive data from that Subscription:

In the Java 9 Flow API, this Subscription is an interface with a set of methods and is defined as follows:

public static interface Subscription {   
  public void    request(long n);   
  public void    cancel() ;   
}   

It contains the following two methods to control the messaging between Publisher and Subscriber(s):

  • request(): This is used to add the given n number of items to the current active Subscription between Publisher and Subscriber(s)
  • cancel(): This is used to cancel or stop the current Subscription between Publisher and Subscriber(s) so that there is no communication happening between them

One Subscription is dedicated between a Publisher and a single Subscriber or a set of Subscribers. Once it's stopped by making a call to the cancel() method, Publisher cannot send data to it or Subscriber cannot receive any messages from it.

It is also defined within another class as a static component. We will see it in the next section.

Flow API – Processor

In the Flow API, Processor is a special kind of component. It works as both a Subscriber and Publisher. We can use it as a source of data, that is, a Publisher, or a destination of data, that is, a Subscriber.

In the Java 9 Flow API, this Processor is an interface with no methods and is defined like this:

public interface Processor<T,R> extends Subscriber<T>, Publisher<R> {   
}  

It is also defined within another class as a static component. We will see it in the next section.

Flow API – Flow

In the previous sections, we discussed the components of the Flow API one by one in depth. They are all interfaces and are defined as static components within another component of the Flow API. This component is Flow.

In the Java 9 Flow API, this Flow component contains the rest of the four components' static components, as shown here:

Flow.java:

package java.util.concurrent; 
 
public final class Flow { 
 
    private Flow() {}  
   
    @FunctionalInterface 
    public static interface Publisher<T> { 
        public void subscribe(Subscriber<? super T> subscriber); 
    } 
 
    public static interface Subscriber<T> { 
 
        public void onSubscribe(Subscription subscription); 
 
        public void onNext(T item); 
 
        public void onError(Throwable throwable); 
 
        public void onComplete(); 
    } 
 
    public static interface Subscription { 
 
        public void request(long n); 
 
        public void cancel(); 
    } 
 
    public static interface Processor<T,R> extends Subscriber<T>,
     Publisher<R> { 
     } 
 
    static final int DEFAULT_BUFFER_SIZE = 256; 
 
    public static int defaultBufferSize() { 
        return DEFAULT_BUFFER_SIZE; 
    } 
 
} 

This is so that we can access other components as Flow.xxxx, which means if we want to access a Publisher, we should use it like Flow.Publisher.

When we combine or connect all these components in a working system, we will see them as follows:

When we connect the Flow API components in this way, we can observe that a flow is going from source to destination. That's why they have named this API as the Flow API.

We can represent the Java 9 Flow API's Publisher/Subscriber complete communication as shown in the following diagram. This communication can end either successfully or in failure:

 

Implementations of Reactive Streams


In this section, we will discuss the most important and popular Reactive Streams Specification implementations, Reactive Technologies, and so on.

Lightbend's Reactive Platform

Lightbend's Reactive Platform is one of the popular technology stacks that support the FRP paradigm. Lightbend is one of the initiators of the Reactive Streams Specification. This platform has a Reactive microservice framework known as the Lagom framework.

The Lagom framework uses Scala, Play, and Akka Toolkit to develop Reactive systems, Reactive Web Applications, or Reactive microservices. It is a pure FRP Solution.

The Akka Toolkit has an API known as the Akka Streams API, which implements the Reactive Streams Specification.

In this book, we will use this technology stack to develop our Reactive system. Go through subsequent chapters to understand how to easily develop data streaming applications using Akka Streams and how to develop Reactive microservices using the Lagom framework.

Pivotal's Reactor project

The Pivotal team has developed a new module to support RP features, which is known as Reactor. They have released it as part of Spring Framework 5.x.

The Spring Framework is a Java framework to develop web applications, microserivces, and more. Its 5.x version is built on the Reactor module and also supports the API to develop Reactive applications. This module builds directly on the Reactive Streams Specification, so we don't need to use any bridge or adapters. Spring Framework has another module known as Reactor IO, which provides wrappers around low-level network runtimes, such as Netty and Aeron.

Microsoft's Reactive Extensions (RX)

Microsoft has implemented one Reactive Solution for C# (.Net platform) known as Reactive Extensions. It supports Reactive programming very well.

Reactive Extensions, Rx, or ReactiveX is a library to support asynchronous event-based programming, which has become a base library for other Rx libraries.

Netflix's RxJava

By following Microsoft's Rx library, Netflix has developed their own Rx library for the Java programming language, that is, RxJava.

RxJava stands for Reactive Extensions for Java. It became a base library for other JVM (Java Virtual Machine) languages. Many people have developed some adapters on top of this library.

For instance, RxScala is an Rx library for the Scala programming language. We will discuss Rx and the RxScala framework further in Chapter 5, Adding Reactiveness with RxScala.

Eclipse's Vert.x

Vert.x is an Eclipse Foundation project to support an Event-Driven paradigm on the JVM. Reactive support in Vert.x is similar to Ratpack. Vert.x allows us to use either RxJava or Eclipse native implementation of the Reactive Streams API to develop Reactive systems.

The Eclipse Vert.X website can be found at http://vertx.io/.

We can find its source code at https://github.com/eclipse/vert.x.

Ratpack

Ratpack is a set of Java libraries for building modern high-performance HTTP applications. It provides a basic implementation of the Reactive Streams specification. However, it is not designed to be a fully-featured RP Framework or toolkit.

We can get more information about Ratpack at https://ratpack.io/.

 

How are Reactive Streams born?


So far, we have discussed many things, such as Reactive programming, Reactive Manifest, the Reactive Streams API, the Java 9 Flow API, and finally, Reactive implementations, in detail in the previous sections.

It is useful to understand how they are all related and why they are required. I prefer a simple diagram to explain it instead of a lengthy description.

Take a look at the following diagram:

I hope you understood well how the Reactive Streams API was born. In my point of view, there are four phases or stages of the Reactive Streams API.

 

Marble diagrams


In this section, you will learn what Marble diagrams are, why we really need them or what their benefits are, and the rules we need to follow to draw these Marble diagrams?

We will also discuss some of the important FP operators using Marble diagrams in the following sections.

What is a Marble diagram?

A Marble diagram is a diagram used to visualize an FRP Data Transformation in a very nice and easy-to-understand form. (Refer to the next section to understand what an FRP Data Transformation is.)

Using these diagrams, we can understand the following things very well about an FRP Data Transformation:

  • A data element or a set of data elements are emitted or produced from a source (Producer, Publisher, or a data stream)
  • A data element or a set of data elements flow in that data stream, that is, they are produced from the source and flow through that data stream
  • What data transformation is happening in that data stream?
  • How that data stream is picking each element and how it is performing that data transformation for each and every element or only a set of elements
  • The way it is preparing the final results after performing that data transformation
  • How that data stream is sending the final results to the destination (another Producer, Publisher or a data stream, or maybe a Consumer or Subscriber)

Before starting the discussion about some sample Marble diagrams, I feel it's good to know what an FRP Data Transformation is. Let's define it now.

Data transformation

A data transformation is an operation (or operator), which is applied on a set of source data elements or all data elements in a data stream and produces resultant data elements to send to another data stream:

As we use this data transformation to represent a functional operation, Reactive operation, or both, we also call this as an FP operator or RP operator, or FRP operator. It is also known as a Reactive Stream operator, Functional Reactive operator, or Data Flow operator.

Some of the FP operators are map, flatMap, reduce, fold, and filter. They are also known as combinators in the Scala World. Refer to Chapter 2, Functional Scala, to understand what a Scala combinator is.

We will pick up some of the important and useful FRP operators and discuss them with Marble diagrams in subsequent sections.

Benefits of Marble diagrams

The following are the benefits of Marble diagrams in the Functional and Reactive World:

  • They represent a simple or complex FRP operation in a simple and easy-to-understand way
  • Pictorial representation of an FRP operation explains better than a text description
  • They help us in understanding and solving complex problems in Functional and Reactive ways
  • Even FRP beginners can understand those FRP operations easily
  • It is easy to design source, data streams, and destinations
  • It is easy to understand how to compose and use multiple FRP operations

Rules of Marble diagrams

To draw a Marble diagram to represent an FRP operation in a pictorial form, we should follow these rules:

A horizontal line represents a data stream:

That horizontal line represents a duration or time from left to right to perform that data transformation operation.

Some symbols (such as circles, diamonds, and rectangles) on top of that horizontal line are used to represent the data elements coming from a source data stream or resulting data elements on the destination data stream:

We can use any symbol to represent the data elements in a Marble diagram:

The big rectangular box in the center of a Marble diagram represents the actual data transformation (or functional operation, Reactive operation, or FRP operation) logic:

The top horizontal line represents the Source Data Stream, and the bottom horizontal line represents the Destination Data Stream (or resulting data stream):

The vertical line (|) on top of the horizontal line represents the data stream completing successfully:

A cross mark (X) on top of the horizontal line represents that the data stream is completed with errors:

We can say that these are the properties of a Marble diagram. We will explore these rules with some useful examples in subsequent sections.

Important FRP operators

We will draw Marble diagrams for the following important and frequently used FPP operations:

  • The map() function
  • The flatMap() function
  • The merge() function
  • The filter() function
  • The reduce() function
  • The concat() and sorted() functions

As a Scala developer, I hope you are clear about how these functions (or operations or operators) work. If you are new to these functions, refer to Chapter 2, Functional Scala, which explains these functions in detail with some simple examples.

Let's start with the map() function first.

FRP – the map() function Marble diagram

In Scala, the map() function performs the following steps one by one:

  1. Take each element from the source container.
  2. Apply the given function.
  3. Create a new container of the same type as the destination container. Here, container means any data structure that can hold more than one element; for instance, a Collection, Option, Either, and so on.

In the Reactive World, we can call this container a data stream, as it emits or consumes the data (or data elements).

Here's the Scala sample code for the map() function:

scala> val numList = List(1,2,3,4,5) 
numList: List[Int] = List(1, 2, 3, 4, 5) 
 
scala> val squaredNumList = numList.map( x => x*x ) 
squaredNumList: List[Int] = List(1, 4, 9, 16, 25) 

Here, the map() function picks up each element from a number list, squares it, and creates a new list with the resultant numbers. Let's represent this map() functional operation in a pictorial form using a Marble diagram:

Here, the source data stream is a List (1,2,3,4,5) and the destination or resulting data stream is also a list with the squared value, that is, List (1, 4, 9, 16, 25).

The data transformation or functional operator is map( x => x*x ).

FRP – the flatMap() function Marble diagram

We use the flatMap() function when we want to map a data stream of data stream elements into a plain data stream element.

For instance, List[List[Int]] to List[Int], as illustrated here:

scala> val numList = List(List(1,2,3),List(4,5),List(6)) 
numList: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6)) 
 
scala> numList.map(x => x) 
res9: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6)) 
 
scala> numList.flatMap(x => x) 
res10: List[Int] = List(1, 2, 3, 4, 5, 6) 

In this case, the map() function does not give us the expected results, so we only use flatMap(). We can represent this flatMap() function in a Marble diagram as follows:

FRP – the merge() function Marble diagram

Suppose we have a code like this to merge two data streams of the same type:

scala> val list1 = List(1,24) 
list1: List[Int] = List(1, 24) 
 
scala> val list1 = List(1,2,4) 
list1: List[Int] = List(1, 2, 4) 
 
scala> val list2 = List(3,5) 
list2: List[Int] = List(3, 5) 
 
scala> list1 ++ list2 
res0: List[Int] = List(1, 2, 4, 3, 5) 

Alternatively, we have a user-defined function, merge(), as shown here:

scala> def merge[A](list1:List[A], list2:List[A]): List[A] = list1 ++ list2 
merge: [A](list1: List[A], list2: List[A])List[A] 
scala> merge(list1,list2) 
res1: List[Int] = List(1, 2, 4, 3, 5) 

If we want to represent this merge() function's Marble diagram, we can do so as follows:

Here, Input Data Stream1 is list1 and Input Data Stream2 is list2. When we make a call to the merge() function with them, we will get the resulting (or output) data stream.

FRP – the filter() function Marble diagram

In FP, a filter() function is used to filter a data stream (or a set of elements—containers) with a condition (this condition is known as a predicate). For instance, we have a list of numbers and want to filter and return only even numbers, as demonstrated here:

scala> val numList = List(1,2,3,4,5,6) 
numList: List[Int] = List(1, 2, 3, 4, 5, 6) 
scala> numList.filter(x => x%2 == 0)  
res8: List[Int] = List(2, 4, 6)  

We can represent this filter() function as shown here:

FRP – the reduce() function Marble diagram

Now we will see another important and frequently used functional HOF, that is, reduce().

It takes each element from the data stream (or container) and applies the given function. Let's do it with List (almost all containers have this function):

scala> val numList = List(1,2,3,4,5,6) 
numList: List[Int] = List(1, 2, 3, 4, 5, 6) 
 
scala> numList.reduce((x,y) => x +y ) 
res22: Int = 21 
 
scala> numList.reduce(_ + _) 
res21: Int = 21 

The following diagram shows the Marble diagram for the reduce() function:

Note

If you are new to HOF, refer to Chapter 2, Functional Scala, for more information.

FRP – the concat() and sorted() functions Marble diagram

So far, we did simple Marble diagrams, which apply only one function at a time. However, we can compose functions one by one in a sequential order to solve some complex problems easily and in an elegant way.

Now, we will draw Marble diagram for the concat() and sorted() functions. Let's consider some Scala code using these two functions:

scala> val hello = "Hello" 
hello: String = Hello 
 
scala> val world = "World" 
world: String = World 
 
scala> hello.concat(world) 
res17: String = HelloWorld 
 
scala> hello.concat(world).sorted 
res19: String = Hwdellloor 

We can represent them as a Marble diagram, as follows:

Note

In the same way, we can represent any Functional or Reactive or FRP function as a Marble diagram to understand it well.

Observer pattern versus Reactive pattern

In this section, we will try to differentiate between the Observer pattern and Reactive pattern. As we have already discussed, the Reactive pattern gives a lot of benefits to our systems or applications.

The Observer pattern is a widely used OOP design pattern to solve some of the problems, and it mainly has two kinds of components—Subject and Object (where Subject is Observable and Object is Observer).

It gives us the following benefits:

  • Separation of concerns into two distinct components—Subject and Object
  • Clear abstraction and encapsulation between these two components
  • Loose coupling between the Subject and Object components
  • We can change a component without affecting others
  • We can add more Objects or Observers at any time

Even though the Observer pattern solves most of the problems, it still has the following drawbacks or issues:

  • It is not thread-safe
  • It may cause leaking if we forget to unregister any Observers
  • It does not support the backpressure technique
  • It does not support composability, which means we cannot compose multiple small components to solve large or complex problems
  • It does not support asynchronous non-blocking communication with backpressure

To solve all these problems, we should go for the Reactive Streams Specification.

The Reactive pattern is more than the Observer pattern. It is the combination of positive points from the Observer pattern, Iterator pattern, and FP.

Note

Reactive pattern = Observer pattern + Iterator pattern + FP

The Reactive pattern or programming is not a single pattern; it is an architecture and gives us a new set of design patterns to develop new kinds of systems or applications (that is, Reactive systems or Reactive applications). We will discuss it in Chapter 12, Reactive Design Patterns and Best Practices.

By design, the Reactive pattern supports asynchronous non-blocking communication with backpressure. If we use Akka Reactive Streams or Play Framework with FP, we will get composability, thread-safety, concurrency, and parallelism for free.

Check out the Benefits of Reactive programming section for more details, which are also the same for the Reactive pattern.

Note

Take a look at Chapter 7, Working with Reactive Streams, to understand backpressure.

Note

Going forward, I hope my readers start thinking functional reactively.

 

Summary


In this chapter, we discussed what Reactive programming is, why we need it, its benefits, and its architecture.

Like Imperative and OOP, RP is a kind of programming paradigm.

We also covered the Reactive Manifesto and the Reactive Streams Specification and why we need RSS. You learned the four principles or tenants of Reactive Streams.

We also explored the Java 9 Flow API and its components in depth. It is defined as an API by Oracle Corporation as part of JEP-266. This API is also known as the Reactive Streams API.

Then we introduced another popular programming paradigm known as FP, and discussed why FP is a better fit for RP. Finally, we combined FP and RP into FRP.

We focused on some of the Reactive Streams API implementations, such as Akka Streams, Reactive Extensions (RxJava, Rx Scala), Vert.x, the Spring Reactor module, Reactive Mongo, and more.

I hope you have understood all about what the importance of FRP is in developing Reactive systems.

In this book, we will use the Lightbend Reactive Platform to develop our Reactive applications. The Lightbend Reactive Platform is a set of components, such as Scala, Play Framework, Akka Toolkit, Lagom, and ConductR. So let's start learning about each component one by one in the subsequent chapters.

Once you learn each component, at the end of the book, we will develop our final Reactive systems by following the Reactive Architecture.

 

 

About the Author

  • Rambabu Posa

    Rambabu Posa has been working as Java developer since 2004 and a Scala developer since mid-2015. He loves Functional Programming in the Test-Driven Development way to develop Reactive microservices. He loves teaching and has been giving online training and writing tutorials on both the Java and Scala ecosystems. He loves developing Reactive systems using Lightbend's Reactive Platform Technology stack like Lagom Framework, ConductR, Scala, Akka Toolkit, Akka Streams, Play Framework, and others.

    Browse publications by this author

Latest Reviews

(4 reviews total)
Very poorly written, doesn't seem to have been edited at all. Seems like someone wrote an outline for a book, decided they didn't actually want to write the book, then just turned in the outline. There are coding examples in the REPL that have typos still left in; very lazy.
Good book for reactive patterns using Scala
I have understood many things in Scala and Functional Programming.

Recommended For You

Scala Design Patterns - Second Edition

Learn how to write efficient, clean, and reusable code with Scala

By Ivan Nikolov
Scala Programming Projects

Discover unique features and powerful capabilities of Scala Programming as you build projects in a wide range of domains

By Mikaël Valot and 1 more
Scala Machine Learning Projects

Powerful smart applications using deep learning algorithms to dominate numerical computing, deep learning, and functional programming.

By Md. Rezaul Karim
Modern Scala Projects

Develop robust, Scala-powered projects with the help of machine learning libraries such as SparkML to harvest meaningful insight

By Ilango Gurusamy