It has been a while since my last article, I am currently involved in organizing a conference in Zürich (App Builders) that will be held next month, plus I had the beautiful chance to speak during mDevConf and Swift Aveiro in the last month. I talked about RxSwift and how this amazing abstraction/framework can simplify the life when dealing with asynchronous programming, so I decided to write an article about how Reactive Programming can push asynchronous programming into a completely new level.

Asynchronous Programming is hard

Most of the talks and articles related to Reactive Programming are showing how good and amazing are reactive frameworks, “throwing” examples of very complex situations, handled with just few lines of code. Example? Here’s a snippet of a chat app based on RxSwift, that I’ve used while presenting during the talks in The Netherlands and Portugal:


socket.rx_event
    .filter({ $0.event == "newMessage" && $0.items?.count > 0})
    .map({ Array($0.items!) })
    .subscribeNext { data in
        let username = data[0]["username"] as? String ?? "unknown"
        let text = data[0]["message"] as? String ?? "invalid text"
        let message = JSQMessage(senderId: username, displayName: username, text: text)
        self.messages += [message]
        self.finishSendingMessage()
    }.addDisposableTo(disposeBag)

The previous snippet shows how a socket event can be filtered and processed to display messages coming from a certain user during a chat talk.

In the classic imperative way, we would probably end having something like:


    dispatch_async(dispatch_get_global_queue()) {
         
         let socketData = self.loadDataFromSocket()
         let data = self.parseData(data)

         dispatch_async(dispatch_get_main_queue()) { 
            let username = data[0]["username"] as? String ?? "unknown"
            let text = data[0]["message"] as? String ?? "invalid text"
            let message = JSQMessage(senderId: username, displayName: username, text: text)
            self.messages += [message]
            self.finishSendingMessage()
         }
    }

This is what is called “the callback hell”, code is difficult to read and maintain, but why callbacks hell are so bad, except for the fact they are really hard to read? Synchronization becomes painful.

Asynchronous programming is not just about running tasks or perform computation in a separate thread, at some point, we will need to synchronize values across threads and the most common solution is to add locks. As soon as locks are introduced, the complexity of the code raises of at least one order of magnitude and one big new component is added to the complexity equation: unpredictability.

The code now becomes unpredictable in terms of computation, there’s no way to know (for sure) when a single dispatch will be performed and if we access a single value property (using locks) as expected, we might have lost a value or maybe we are processing the same value as before.

So what is really hard in asynchronous programming? Synchronization… that sounds funny, but it’s true.

The Reactive Approach

It’s important to remember that reactive programming is not a young concept as many can think, the root goes back to the Ph.D. thesis of computer science legend Alan Kay titled “The Reactive Engine”, 1969 at the University of Utah… but I am not here to give a history lesson, so let’s see what reactive programming gives as value when dealing with asynchronous code, considering that some concepts are really well established and not experimental as they might seem.

In the Rx world, the fundamental part is the combination of the Observer pattern and the Iterator pattern, both are well known patterns and widely used to handle certain behaviors while writing software. Both, the Observer and Iterator patterns are pull interactions, in both cases the computation is processed pulling the value out of the producer. For the iterator we keep getting values as long as they are available, for the observer pattern, we process the value right after the producer has sent out the notification to all the concrete observers, pulling the data out of it. Pulling is definitely a concrete and established solution and works great as long as everything is processed in the same thread. What happens when the data has to be pulled and processed asynchronously? Well, locks are starting to play a big role and things can get quite difficult really fast.

Imagine…

…to have a very nice application, ready to be shipped in few days, but at some point, during the final tests, some deadlocks and race conditions are happening and the app crashes randomly, with just enough data to assume the problem. Time is limited and the place where the problem might be fairly faster to find than expected, but the solution might not be so simple and quick to develop and deploy. The first thing to remember is that, as soon as the locking strategy is “injected”, the whole code slows down and the unpredictable nature of asynchronous programming might also affect the general app performance. It’s also possible to have order of magnitudes in slowdown, conclusion: this is unacceptable.

React

Reactive is a matter of design, pulling data is definitely something that might be hard to tailor in a short amount of time, so one solution is to flip the action, instead of pulling from a resource, why not let the resource itself to push the value to a subscriber/consumer? That’s exactly what Rx is all about, pushing data to entities that are subscribed to a producer. We produce data somewhere, that data is then pushed to all subscribers and processed accordingly to the needs.

Observer + Iterator + Push = Observable

The math behind Rx is simple, 2 very established entities, combined with a different interaction model, are the root of the Observable entity. This is where the revolution happens, combining old, established concepts in a certain way to create and model a powerful abstraction to help dealing with asynchronous programming without risking to burnout after a week.

The result of the math is an entity called Observable, this object is responsible to process the original data and to push the value to all the subscribers when necessary. The subscribers can have multiples roles, they can be other chained observables, operators or just callbacks. Rx is a very basic, but also very powerful abstraction.

Declare

Using the observable approach requires the logic to be declared when initializing the observables, this means our code becomes tighter and is generally limited into the initializer of the view controller. In the RxChat example, the big part of the logic is declare in the viewDidLoad function:

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        self.setup()
        
        user
            .distinctUntilChanged()
            .subscribeNext() { username in
                self.senderId = username
                self.senderDisplayName = username
                self.socket.emit("addUser", withItems:[username])
            }.addDisposableTo(disposeBag)
        
        socket.rx_event
            .filter({ $0.event == "connect"})
            .map({ _ in return () })
            .subscribeNext { _ in
                self.title = "RxChat (Connected)"
            }.addDisposableTo(disposeBag)

        // [...]
    }

This approach is also known as “Declarative Programming” and reduce the amount of potential bugs we can have, it also makes the code shine when used with MVVM and similar approaches.

What now?

Learning Rx or Reactive Progamming in general is like learning a new language (not a programming one), steps are very similar, we have the phase where we learn the fundamentals and most used sentences, we then learn the rules and semantics and we end up mastering the language, being able to speak even about the most difficult topics.

To keep learning, I suggest the following resources:

Conclusion

This article might seem very short and, in fact, it has been supposed to be short, but it has been wrote with in mind the basics of Rx. Most of the articles and talks around are explaining how to use it and how things work with it, but very few people are talking about the why Rx is so great and why give it a shot. There’s no magic behind/under Rx, all the things used in RxSwift are plain old, established concepts, glued in a smart way to create a great abstraction for asynchronous computation. Don’t spend time writing synchronization strategies for your asynchronous software, invest it in writing the logic.