The Duality in Programming
As Engineers, most of us are used to a style of programming we call Imperative Programming. This is largely due to the fact that when the web was simpler, about 10 years back, the interaction was too. In most cases it was as simple as submitting a long form and processing that in the backend. This led to the adoption of a style of programming where we used variables to capture state and process them.
But, everything evolves. Tech evolves. Software evolves. And consequently, programming patterns do too.
This led to what we now call, Reactive Programming.
What is Reactive Programming?
Simply put, Reactive Programming is a programming paradigm that deals with streams of events. In other words, asynchronous data streams.
Think of a keypress on your keyboard as an event:
- Pressing the character
acould define an event stream that might look something like this:
— a –––––––––>
- When multiple keypresses happen, it could look like this:
— y — e — h —>
To help understand event streams, think of a conveyor belt with products continuously in motion:
Event streams are not a new concept to Software. The mouse clicks and key presses from the keyboard that we interact with every day are all processed as event streams. Reactive Programming enforces a model of thinking where event streams could be used to process any kind of data.
Event streams are essentially immutable streams of values that can be operated upon. By which, I mean — using the many operators that are bundled with a Reactive Framework, we’re able to transform a stream into a different stream in-place. This pattern is really powerful and takes advantage of the functional aspects of a programming language.
In short, Reactive Programming brings the following to the table:
- The Reactive Model of Thinking
- Arsenal of Operators to work with event streams
What problem does it solve?
Now that we know what Reactive Programming is, I believe it’s essential to understand why you should be bothered about it.
Let’s assume you had to process a stream of async events, for instance, a stream of tweets that had to do with a hashtag, filter some of them and process them further.
In the imperative style of programming, we would approach this problem by building a model of a tweet, building a networking service that continuously polls and updates the data store, a separate worker that could filter the stream of data constantly and sending it elsewhere to process it further.
Although it’s not impossible to do it this way, there’s a lot of moving parts to this approach — handling state, polling, and updating the view layer could quickly get nasty.
In the Reactive world — we would simply define the tweets as a stream of tweets, process it using one of the many operators and transform it into any format that can act as an input to another stream to process it further. The functional approach to handling async events really shines in this regard.
State of Reactive Programming in iOS
Reactive Programming is not alien to the iOS platform as such. The Rx movement made sure we had a way to do this with iOS using libraries like
The learning curve which largely comprised of enforcing a different pattern of thinking — which is to think in event streams — was one of the primary hurdles for beginners to understand and work with a pattern like RP, but no doubt it was a powerful paradigm since UIs could be tightly bound with the model layer and this led to a simplification of logic.
The reactive pattern in iOS helped introduce a layer of abstraction that moved discussion from the implementation details to thinking about how events worked and depended on one another and how they affected the business logic.
Combine is Apple’s answer to this pattern for iOS. It is simply a framework for processing values over time. Quite an exciting one to be honest.
Callback hell, as I’m sure you’re aware of – is a term that describes nested closures which have become an attribute of processing async values over time.
Combine essentially provides a solution to get around this problem using the pattern we described above. The high-level abstraction that Combine provides enforces a model of thought process that deals entirely in terms of data streams. As long as we train ourselves to think reactively, we could potentially process any kind of values over time —
- User Interface Events
- Network Responses
- Scheduled Events
- And many other kinds of asynchronous data.
In software architecture, the publisher-subscriber model is a messaging pattern where senders of the message (Publishers) do not directly send a message to the receiver and have no knowledge of the receivers even.
Subscribers can opt to receive messages from publishers they’re interested in.
Combine defines three core concepts to adopt this pattern:
Publishers declare a type that can publish values over time. Subscribers declare a type that can receive values from a publisher by subscribing to them. Operators are tools to process and transform values once a connection between a publisher and a subscriber has been established.
Let’s look at this pattern in-depth in another post.