What is reactive programming?
Reactive programming is a programming paradigm, or model, that centers around the concept of reacting to changes in data and events as opposed to waiting for an event to happen.
An event in computing refers to user or system actions that trigger a specific response within a program. These events are best visualized as “streams” that can flow through multiple processing elements, be stopped along the way or fork into a parallel processing activity. For most cases, this processing is time-sensitive, meaning that the applications require a different programming style, which is how reactive programming came about.
Reactive programming relies on asynchronous programming logic to handle real-time updates to otherwise static content. This means that a program can start a long-running task while, at the same time, still being responsive to other events.
Reactive programming lets developers handle asynchronous data streams and events in a more intuitive way by simplifying otherwise complex event-driven scenarios. It, in essence, is a way to create software that responds to events rather than soliciting inputs from users. Using this programming model, developers can create responsive and efficient event-driven applications.
Early applications of reactive programming to business applications were largely confined to things such as monitoring the state of networks, servers, and software as well as signaling database conditions, such as inventory levels. This focus is changing with the advent of the internet of things (IoT), smart buildings and cities, and public cloud computing.
IoT has made the reactive model important in facilities management, industrial process control and even home automation. The cloud has introduced both a style of componentizing software — functional computing and microservices — and a movement to shift many reactive applications to the cloud for its scalability and reliability benefits.
How does reactive programming work?
Reactive programming is all about streams, which are time-ordered sequences of related event messages. Data streams used in reactive programming are created on a continual or near-continual basis. These data streams are sent from a source — a motion sensor, temperature gauge or product inventory database — in reaction to a trigger.
That trigger could be any of the following:
An event, such as software-generated alerts, keystrokes or signals from an IoT system.
A call, which is a function that invokes a routine as part of a workflow.
A message, which is an information unit that the system sends back to the user or system operator with information about the status of an operation, an error, failure or other condition.
Any asynchronous operations can also act as a trigger.
Reactive programming and the reactive systems it deals with also consist of a combination of observer and handler functions. The observer function recognizes important conditions or changes, and then generates messages to signal they’ve happened. The event handler is what deals with those messages appropriately.
A given stream will generally start with an observer. This can be either a segment of code in an application that watches for a condition related to the application or a device such as an IoT sensor that generates an event. A stream is sometimes diagrammed as an arrow — left to right — that starts with the observer process and flows through one or more handlers until it’s completely processed, terminates in an error status or forks into derivative streams. Reactive programming is about building those observers and handlers as well as threading the stream as required.
Device-generated streams are easily understood. But streams generated by software-inserted observers are a bit more complicated. Normally, these elements work either in cooperation with the processing work done by an application or they run periodically to monitor a database element. When this software element recognizes a condition, it generates an event in the stream.
An event stream is steered either by the handlers themselves where work is dispatched to a specific next process, or by a message bus such as an enterprise service bus or message queue that carries the message to designated bus listeners. The message handling process determines whether a message is broadcast to multiple handlers or to a single handler. It is also normally responsible for load-balancing among multiple parallel handlers or providing spare handlers in the case of a failure.
Each handler must either pass the message along, determine that the stream process has ended and “eat” the message, or generate an error. The handler may decide whether to fork a message to multiple streams or to generate a new stream. These fork conditions are often used to separate tasks in message handling; for example, a message might generate a local response to open a gate as well as a message to a transaction processing system.
The presumption in reactive programming is that there’s no control over the number or timing of the events, so the software must be resilient and highly scalable to manage variable loads. Instead of writing more simple sequential code, developers must write everything as callback functions.
In “The Reactive Principle,” the follow-up to “The Reactive Manifesto,” Jonas Bonér et al. defines the eight principles an application must embody to be considered reactive:
Stay responsive. Always respond in a timely manner.
Accept uncertainty. Build reliability despite unreliable foundations.
Embrace failure. Expect things to go wrong and build for resilience.
Assert autonomy. Design components that act independently and interact collaboratively.
Tailor consistency. Individualize consistency per component to balance availability and performance.
Decouple time. Process asynchronously to avoid coordination and waiting.
Decouple space. Create flexibility by embracing the network.
Handle dynamics. Continuously adapt to varying demands and resources.
The Reactive Principles refer to eight different principles that an application must consider when it comes to being reactive.
Benefits and challenges of reactive programming
The primary benefits of reactive programming techniques are their ability to do the following:
Provide better control over the response times associated with the processing of events.
Enable consistency in software design for real-time systems to reduce development, maintenance costs, and effort.
Support load balancing and resiliency to improve the quality of experience.
Make the concept of a stream or event flow explicit, improving overall management of compute elements and processing resources by making them more visual.
Handle asynchronous and non-asynchronous code. This provides developers with the flexibility to write code that can handle multiple tasks at the same time without having to cease a main thread from executing.
These benefits come with challenges, however:
Adding observer processes to current software might be difficult or impossible depending on source code availability and staff programming skills.
Reactive design is a major mindset shift for developers, and efforts will present a learning curve during which more validation and supervision of design and coding might be required.
Reactive systems can easily accumulate delay through an excessive number of processes linked to the stream.
Debugging an application that uses reactive programming is more complex due to the code’s event-driven and asynchronous nature.
Still, modern web apps and mobile apps can be highly interactive, making use of many data events. Reactive programming is a way to make these applications respond in real time in a scalable manner.
Adopting reactive programming
There are several different approaches reactive programming can take. For example, reactive programming can be integrated with imperative, actor-based, rule-based or object-oriented programming. Developers will also have to choose the reactive programming framework. For example, reactive programming in Java includes frameworks such as the following:
RxJava. This is a functional reactive programming library used for Android.
Akka. This is a toolkit and runtime for building applications on the Java Virtual Machine.
Vert.x. This is another toolkit for building reactive applications on the Java Virtual Machine and is structured as an event-driven and non-blocking architecture.
Spring Framework 5.0. The Spring Framework is a reactive programming framework that uses Reactive Streams to communicate between libraries and any asynchronous elements.
The Java Virtual Machine interprets bytecode and converts it to machine language that is platform specific.
Good reactive programs start with a clear diagram of the event stream, one that includes all the specific handler processes and their role in processing, terminating or error generation. When this is done, the hosting platform — edge, cloud or data center — is selected and designated on the stream diagram for each process, avoiding any back and forth across hosting platform boundaries. Development can then begin.
The following best practices should be observed while building reactive programming applications:
Where an event stream must trigger a real-world response, such as opening a gate, keep the control loop short by moving the responding process closer to the front of the stream and hosting it near the event source.
Avoid using programming languages and techniques that create stateful components that store data with the software to ensure that components can be scaled and replaced easily.
Review the location and implementation of any databases needed by any of the handler processes to ensure that database access doesn’t add latency or cross-cloud boundaries, generating additional costs.
At every step in development, reference the work done back to the event stream diagram to ensure it’s maintained, up-to-date and accurate.
What are reactive streams?
Reactive Streams is a specification founded in 2013. It defines the interfaces and classes that are used to create applications through reactive programming. The aim of classes Reactive Streams is to specify interfaces, protocols and frameworks for reactive programming while also defining a standard for asynchronous stream processing with non-blocking backpressure.
Asynchronous stream processing with non-blocking backpressure refers to the processing of data streams asynchronously, meaning that receiving systems can handle the flow of data without getting overwhelmed.
Libraries and frameworks such as RxJava, Akka and Spring Framework 5.0 were created using the Reactive Streams specification, for example.
Reactive programming use cases
The primary use cases for reactive programming include the following:
IoT applications where sensors create events that then control real-world process steps, create business transactions or both. This is the fastest-growing application of reactive programming techniques, though not the traditional target.
Applications that gather status information from networks or data processing elements through inserted software agents to monitor activities or data elements. This is the first classic reactive programming application, but one converging with IoT.
Any application that requires highly interactive user-to-user interface handling, especially where each keystroke must be processed and interpreted. This is the other classic reactive programming application, and it now includes gaming, web apps and some social media applications.
Signaling between applications, particularly between what could be called foreground applications and background applications, that perform statistical analysis and database cleanup. This use case will normally involve a daemon process that monitors for changes and activates an event stream when one is detected.
Coordination between functional AWS Lambda cloud processing and back-end data center processing, where an event will trigger the execution of a back-end process. This facilitates some forms of hybrid cloud development.
Real-time data streaming and big data analysis. Reactive programming is ideal for handling large amounts of real-time streaming data.
Looking to move your apps to an event-driven architecture? Learn how with these five design tips.