Reactive Aggregate State Pipeline

Maxim Volgin
3 min readAug 5, 2018

--

I’ve been a mobile app developer since 2011. Once I made a switch to reactive programming with Rx somewhere in late 2014, I still had a feeling that some of the complexity peculiar to - or at least very prominent on - mobile platforms is still not resolved (although most of it was!). The kind of complexity I am talking about is the problem of combining state from different asynchronous sources on a regular basis, and keeping a valid snapshot of it at all times. This is a rather common scenario when combining location updates with augmented reality, keeping in sync with an external MIDI-device via SysEx messages, performing a long sequence of webservice calls while taking care of possible network- or service failures and retries, or even when progressively building a piece of rich UI containing interdependent elements. I attended a few talks about unidirectional data flow, and read about Flux and Redux, and later MVI. All of it made a lot of sense conceptually, but all practical implementations I have seen required a lot of boilerplate code and most importantly did not play particularly well with Rx. That is when I decided to write my own implementation having two goals in mind: it must be very concise and require the very minimum of boilerplate code, and it must play well with Rx. I called it RASP (Reactive Aggregate State Pipeline) which essentially is fancy name for an expression ‘.merge(allSortsOfEvents).scan(initialState, reducer)’ with some syntactic sugar around it.

So far so good, I’ve got myself a standard way of combining of asynchronous events arriving at very different intervals from different sources into a single state snapshot which contains the latest update from all those sources, a sort of ‘.combineLatest()’ on steroids. Now what? Question one is how many different elements to stuff into a single state so that I do not propagate one single God-state thought the entire app on every slightest move of the camera in AR-session, for example. Question two is how much data (as in bytes) to store in a state so that it does not affect memory and performance more than necessary, the answer to which is clearly ‘as little as possible’. And question three is whether to pass the state by reference or by value, which is something I decided to solve straight away by using Swift ‘struct’ with mutating methods.

The right answer to the first question is probably to define states per domain, scope and lifecycle. That is, for a location-aware AR-session the state should be app-wide and permanent, and contain only location- and AR-related data. When progressively building a complex piece of UI where elements depend on each other, a state will probably contain a builder object that will be updated from different relevant sources until all data is collected, and that will produce a model view to be displayed on every update.

I’ve been using RASP for slightly over a year now, and even put it on GitHub — https://github.com/maxvol/RaspSwift . It has proven to be a convenient architectural cornerstone for about a dozen of iOS apps I have developed since then, some of them in the AppStore. Hopefully RASP can start serving a broader audience now ;)

--

--