Your Privacy

This site uses cookies to enhance your browsing experience and deliver personalized content. By continuing to use this site, you consent to our use of cookies.
COOKIE POLICY

Skip to main content

Why ReactiveX Programming Will Improve Code Quality

Why ReactiveX Programming Will Improve Code Quality
Back to insights

What is reactive programming?

Reactive programming is about designing your program based on how inputs are received and turned into outputs. This thought process applies whether you’re talking about a user typing a search term in a textbox and you are displaying search results or a scheduled batch job to migrate data from one database to another, both have inputs and outputs.

We find polling for data incredibly annoying in real life, the kids in the back of the car continually asking “Are we there yet? Are we there yet? Are we there yet?” the answer is “No! I will tell you when we get there!”. This is the way we have become accustomed to handling certain types of interactions in our programs already. We do not constantly ask a button if it has been pressed, we give the button a place to tell us when it has been pressed.

You might be thinking isn’t this Event Driven design? Event driven design focuses on user-initiated events, but does not generally address data models being asynchronously changed and how those changes should be shared with a UI. Reactive programming events are triggered by change events both user driven and data driven. So reactive programming gives you a feedback loop for your UI to know when an underlying model has changed and your user should be updated.

Now let’s look at the definition: reactive programming is an asynchronous programming paradigm oriented around data streams and the propagation of change. So what does that actually mean? Well let’s break it down slowly, “asynchronous programming paradigm” so instead of having things happen in a sequence “I went for a walk and then I read a book”, you do them concurrently “I went for a walk and listened to an audio book at the same time”. Hopefully, this concept isn’t foreign to anyone at this stage. Now we get to the “Wut!?” portion: “oriented around data streams and the propagation of change”. What this portion of the definition is referring to is that a program is a dynamic thing that has input and output, if your program doesn’t have input then you might as well replace it with a constant, if it doesn’t have output then what’s the point of ever running it?

Designing around data streams and change propagation

One of the biggest challenges for people beginning to look at reactive programming is the required shift in mindset to thinking about streams of data. This thought process is actually something that most of us are already familiar with though because we have been dealing with callbacks. We don’t poll for changes anymore, we pass a callback function or delegate so that we can be updated when something happens and REACT to it.

“So why are you writing this intro like reactive programming is something different? You just said I’m already doing it.” The difference is in the interface, and for this part I will be referring to the implementation of Rx. Quick aside; I am a fan of Rx because there is a sizable community behind it and there is an implementation that is fairly uniform in most modern programming languages. This correlation between multiple languages actually helps developers from multiple teams discuss how to solve problems using a common API </aside>. Rx creates a generic interface for handling events, Observable streams. Let’s look at a swifty implementation:

Using target action


import UIKit

class ViewController: UIViewController {

let label: UILabel = UILabel(frame: CGRect(x: 20, y: 150, width: 100, height: 50))

var counter: Int = 0

override func viewDidLoad() {

super.viewDidLoad()

view = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 667))

let button: UIButton = UIButton(frame: CGRect(x: 20, y: 50, width: 100, height: 50))

button.setTitle("Press Me", for: .normal)

// Tell the button to call updateCount when the touchUpInside event fires

button.addTarget(self, action: #selector(ViewController.updateCount), for: .touchUpInside)

label.textColor = UIColor.white

view.addSubview(button)

view.addSubview(label)

}

func updateCount() {

counter += 1 // update the counter

label.text = "Count: \(counter)" // update the label

}

}

Using Rx


import UIKit

import RxSwift

import RxCocoa

class ViewController: UIViewController {

let disposeBag = DisposeBag()

override func viewDidLoad() {

super.viewDidLoad()

view = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 667))

let button: UIButton = UIButton(frame: CGRect(x: 20, y: 50, width: 100, height: 50))

button.setTitle("Press Me", for: .normal)

let label: UILabel = UILabel(frame: CGRect(x: 20, y: 150, width: 100, height: 50))

label.textColor = UIColor.white

button.rx.tap

// keep a running count

.scan(0){ (currentCount: Int, _) -> Int in

return currentCount + 1

// change the type of data in the stream from an Int to a String

}.map { (updatedCount: Int) -> String in

return "Count: \(updatedCount)"

}.subscribe(label.rx.text)

.addDisposableTo(disposeBag)

view.addSubview(button)

view.addSubview(label)

}

}

This is an example of two different implementations of a simple view that has a button and a label that counts the number of times the button has been pressed.

The first implementation adds a callback with addTarget(_:,action:,for:) and in the implementation of updateCount() we update the counter and display the new value in the label. Even though this is a small program you already have symptoms of larger problems that go along with traditional event based target callbacks. The culprits? The variables counter and label. We are forced to have instance level properties and counter is only ever used in one place! (Yes, static function variables are a thing but they don’t exist in Swift and the work around is distracting.) The other property, label, is technically used in two places. It is initialized and added to its superview in viewDidLoad(), the text is then set in updateCount(), however as we see in the Rx example you don’t need to separate these things.

Let’s look at the second implementation and try to translate it into English. The chain of calls that starts with button.rx.tap and ends with addDisposableTo(disposeBag) translates as so: Listen to the taps on this button (button.rx.tap), when the button is tapped start with the value of 0 and run the closure that takes the previous value and add 1 to it (scan(0){…}), pass the new value along and save the new value for the next tap, next transform in Int stream type returned from the previous value update into a String (map{…}), now register the label text as the listener to this stream (subscribe(labe.rx.text)) and finally add this stream to the bag of things to throw away when the view controller is dismissed (addDisposableTo(disposeBag)).

This example shows the ability to take an input stream and transform it into what is needed for an output stream. There is no need for instance level variables so there is less of a chance that a teammate will misunderstand the purpose of the variable and use it where they shouldn’t. The local reasoning is also improved because you have one chain of functions for the stream going from input to output.

Observable streams

Ok so observable streams are streams of events or a series of events if that’s easier to think about. There are three types of events that an observable stream can provide onNext, onCompleted(or onDone), and onError. This makes sense if you think about a series of events taking place. Say you are at an all you can eat wing restaurant there are really three events you care about:

onNext – They bring you another basket of wings to devour.

onCompleted – Sorry we aren’t able to serve wings anymore because we ran out.

onError – Everybody run! The kitchen is on fire!

All observable streams have the same three event types that you as the consumer might need to think about. You can stop consuming the events (you get full and can’t eat any more delicious wings) at any point but that does not change the possible outcomes of the observable.

The call to the subscribe function adds on Observer to the Observable stream. An observer is exactly what it sounds like, something that observes an observable stream. An observer knows what to do with the different event types for an observable stream. In the code above I set the observer to the label text, but I could just have easily used a set of closure’s for each event type if the situation required it.

So why should I care?

Reactive programming will push some of the state management you generally have to deal with down into a library that is heavily tested and shared. In the simple examples shared here the management of state was not addressed, but a follow-up blog will show this powerful feature of reactive frameworks. If you choose the Rx framework you will get the benefit mentioned above with being able to collaborate with colleagues who use different languages to help each other create the best solutions possible.

Reactive programming will hopefully expose you to some common operators of functional programming. Starting you down that road will have you asking many more questions about how you design your code.

Next time we will go over more about observable streams, operators for mutating and combining streams as well as a more concrete example that will show how reactive can simplify a code base.

Digging In

  • Software Engineering

    When There’s Too Much to Fix: How Smart Prioritization Unlocks Revenue at Scale

    Every operations team has a backlog. The question isn’t whether you can clear it — it’s whether you’re clearing it in the right order. For most teams, the honest answer is no. And that gap between the order work gets done, and the order it should get done is quietly costing organizations millions. The Volume Problem High-volume exception processing shows up across […]

  • Software Engineering

    Creating Reusable Code Templates to Reduce Client Project Startup Time

    In consulting, one of the least visible but most expensive phases of a project is the beginning. Teams can spend days or weeks setting up repositories, agreeing on structure, wiring basic infrastructure, and solving problems that have already been solved many times before. Code templates are a practical way to reduce overhead while improving consistency. […]

  • Software Engineering

    Player Three Has Entered the Game: How AI Is Finally Bridging the Divide Between Design and Engineering

    As AI begins to become more prominent in our day-to-day lives, I find myself in a unique position. As a practicing software engineer and UI/UX designer, I am genuinely happy to see the introduction of AI tools begin to take shape in our industry. But more importantly, I am happy to start seeing the effects it is having on what has historically been a pretty challenging relationship: the […]

  • Software Engineering

    The Disappearing Middle of Software Work: Why the Bookends – Strategy & Impact – Matter Most Now

    Here’s a question nobody in enterprise software wants to sit with: what happens to the middle? Not the middle of the org chart. The middle of the work. The vast, expensive layer of effort that has defined enterprise software delivery for thirty years—translating what the business wants into working code. The requirements-to-implementation pipeline. The “build phase.” […]

  • Software Engineering

    Zero-Code Telemetry with OpenTelemetry’s OBI

    Full distributed tracing and exception capture for any application — without writing a single line of instrumentation code. View the source code on GitHub → The Premise Observability is essential for understanding what’s happening inside your services, but instrumenting an application by hand — adding trace spans, logging calls, and metric counters throughout your codebase […]

  • Software Engineering

    Building a Consultant in the Trenches: How Playing Offensive Line Shaped My Consulting Career

    People often ask me the same question when they find out that I played college football: “Do you miss it?” On the surface, it’s a bad question with an obvious answer. Yes. However, if I give myself a minute to sit with that question, the answer is more nuanced. Yes, I miss playing football, but […]