Building a Chain of Responsibility with ReactiveSwiftCaio SymBlockedUnblockFollowFollowingMar 14Ok, so you’ve played around with ReactiveSwift a bit and if you are like me it has probably opened you eyes to this amazing world of possibilities.
Another thing that we may have in common is that when I first started doing reactive programing I got a bit too dependent on chaining the flatMap and flatMapError operators.
So today I’d like to talk about how we can leverage some of the less used operators along with good old design patterns to get the most out of our reactive streams.
The Setup:This post will revolve around modelling a game that takes place in a small store.
We’ve been specifically tasked with programming the various NPCs that visit this store in search of food.
Our store has a very simple API for querying what items are available.
It takes the name of the item we are looking for and returns a SignalProducer that emits a single StoreItem or an error if the item is not in stock.
This is what the code looks like:getItem returns a SignalProducer because actually finding the items in the store usually takes a while.
Our very first NPC.
The first task we have been given is implementing the behavior of an NPC named Bob.
Bob is a man of simple habits.
Everyday he goes to the store and searches for the same things in the same order until he finds something that is in stock.
First, he looks for some delicious “Chicken Jalfrezi”.
If that is not in stock his back up option is a “Hot Pocket”.
If he cannot find either of those he settles for an unappetizing “Sandwich”.
If the store is out of all 3 items Bob starves.
Like I said, he is a simple kinda guy…Given the above requirements, we quickly write the code for Bob.
It looks somewhat like this:Nice and simple.
what could possibly go wrong.
Our first paying customers.
Just as we are done coding Bob, we get the spec for our second NPC, Ted.
Ted behaves very much like Bob, except he first looks for a “ceasar salad”, followed by some “tomato and basil soup”.
“Peanuts” are his last resort.
Our product team has also come up with some additional requirements for our NPCs.
It turns out that in order for our game to work properly our NPCs need to pay for things.
So we’ve also been asked to adapt the code for Bob and Ted so that they will treat an item as out of stock if they don’t have enough cash in hand for it.
We spend some time brainstorming how to adapt our code and figure we might as well make use of flatMap alongside with flatMapError.
This has the unfortunate side effect of forcing us to duplicate some of the getItem calls.
It’s not an elegant solution, but its reasonably readable.
Yikes!.We’ve omitted the refactored code for Bob for brevity.
Can we add some more items?The code works and every one is happy.
It looks a bit ugly but its just short enough that we can live with it without wanting to gauge our own eyes out.
Our face grows pale when the product team describes our next NPC, A guy named Max who will browse the store for 100 different items before giving in to starvation.
Turns out he is a real survivalist…It also turns out that we need a new way of tackling this problem unless we feel like doing a lot of copy pasting.
The first thing that comes to mind is writing a helper function to get rid of some of that repetition.
Maybe we can create a Person class and have all our NPC’s inherit from it…This looks better, but we still don’t like the prospect of writing 100 calls to “compose”.
Not to mention that even if we find an item we can afford in our first try we still end up comparing the price to cashInHand 100 times.
That’s not good!On a surface level all of our NPCs behave the same way.
So shouldn’t we be able to abstract that behavior somehow?Some inspiration from Object Oriented codeNow, you’ve read the title for this article so you know it has to mention the Chain of Responsibility design pattern at some point.
So what is it in the first place?Chain of Responsibility is a behavioral design pattern often used when we have a series of objects which may or may not be able to handle a request and we’d like to control the order in which they will attempt to handle the requestA potential file reader chain of responsibilityIn traditional object oriented design, this is usually accomplished by declaring an interface adopted by all of the concrete handler classes and having another class which also adopts said interface but that internally delegates to a each of the concrete implementations until it gets a successful response.
The class diagram would look more or less like this:ChainReader is a Reader that contains an array of delegate readersOk, but how does this look like when we are dealing with reactive streams?For our example, SignalProducer<StoreItem, StoreError> will serve as the analogous to the reader class above.
We know that getItem is able to generate handlers for every item name so if we have a list of all Item names we can then generate and chain the various producers as follows:Our NPCs can now all be easily instantiated!In conclusionSo what did we learn today?While there is certainly a lot flatMap can accomplish, there is a whole array of less known operators at your disposal that can be more suited to the problem at hand.
Design Patterns are still relevant in the Reactive world.
It certainly pays to brush off on them once in a whileDon’t be afraid to go meta!I hope this article was helpful or at least as fun to read as it was to write.