Being Flexible With Responsibility Chains

The key word behind using third-party libraries and components is reuse. Before setting out to write software from scratch, people usually browse for ready to use solutions for their problems. This helps reduce development time and allocate resources to other areas.

Sometimes, we find that some of our needs are better served by a combination of third-party components instead of a single one. Especially when relying on an online service to provide some core functionality in our app, we need to make sure that a backup mechanism is in place and ready to react when the service is not responding.

We will illustrate the above situations better with a real world example taken from an application developed a few years ago. In that app, at some point end users were offered the choice to pay for a product in the currency of their choice.1

For the exchange feature, the app communicated with a Restful service to get the rates. Everything was running smoothly, until one day it didn’t work at all. When asking to pay in a currency other than the default, customers were met with “Sorry, this feature is not available right now. Thank you!”. What had happened? The exchange rate API provider had simply stopped …. providing the service.

In the meantime, the company owners had decided that the monthly amount they had to pay for the conversion service was high and they would rather go with the free plans many providers offered (usually with a cap imposed on the number of requests allowed for free per month). 2

 

The Problem

So, the problem is twofold:

  1. We need to have at least one backup service, so that when the default is not available the feature is still available to the end user. In other words, we need to make sure that a request gets handled but we don’t really care (from the client’s point of view) which service is going to handle it.
  2. We want to drop the cost of the feature to zero (or as close to zero as possible).3

The situation before the problems came up, looked like this:

Chain_Of_Responsibility_Before

Our view controller class knew about the exchange rate api and communicated with it directly. When the service stopped working, the code specifically targeted to that particular service had to be replaced with code talking to a new api. This tactic of course is not resistant to change, since the same thing would happen if WHEN the new api would stop working. 4

func Double requestRates(fromCurrency: String, toCurrency String)
{
    //this line as well as any reference to "exchangeRateService"
    //has to be modified every time we need to replace the service
    //provider
    return exchangeRateService.requestRates(fromCurrency, toCurrency);
}

This could of course be avoided by using an abstraction for the service instead of writing code targeted to one specific service only. Then, for switching to a new service all we would have to do is wrap the new service inside an Adapter.

While this solution is valid, it doesn’t take into account the possibility that the service won’t be available when we need it (i.e. we would have to recompile the source code and issue an update, not exactly an immediate solution; especially if the problem occurs during non working hours). There is a huge number of cases when we need a request to be processed no matter what, by at least one service provider/class/whatever like in the exchange rate scenario.5

One solution would be to include conditional logic in our application’s code that routes the requests based on which service is cheaper, on the number of ‘free’ requests available for use by the app for a particular service, on whether a service is online/available at the moment of the request etc.

This way though, the view controller code is vulnerable to modification, every time a new service is introduced or a business rule dictates changes, we have to dive in the view controller and modify it. Trying to make one’s way through dozens of nested if-else statements is not only error prone, but tedious and tiresome as well.

 

The Solution

 

Chain Of Responsibility Design Pattern

 

In the above diagram, the client (CheckoutViewController) holds a reference to an ExchangeRateService object and directs all requests that have to do with rates there.

Depending on implementation specifics, the ExchangeRateService then either asks for the “right” service to do the work or simply plays the role of the first service in the chain (MainService), which either handles the request or passes it on to the next “backup” service in the chain. 6

The interesting part is the recursive aggregation (“successor” in the diagram) which means that every concrete service holds a reference to the next service in the chain. This way, if the MainService cannot for whatever reason handle the request, it then calls the returnRate method on its successor and this keeps going until the request gets handled.7

You can think of the Chain Of Responsibility as a pipeline, the client object provides a request and is entirely oblivious to the whole chaining action taking place under the hood:

 

Chain Of Responsibility - Pipeline Example

 

By using this pattern we have addressed both problems:

  1. CheckoutViewController asks for the exchange rate but does not know which service actually handles the request. This way, we can add and remove services based on business decisions without modifying the core app.
  2. We can add a threshold for every service depending on how many more free requests are left. If for example MainService only allows for 10000 requests per month, we can configure MainService to forward the requests to its successor in the chain when we run out of free requests. This is obviously really useful when we are asked for solutions on cutting costs (and that’s a really popular request, especially among people in managerial positions).

 

What If No Service Can Handle The Request?

It is entirely possible that even with a chain mechanism in place a request can go unhandled (maybe for example because of lack of internet connection on the client/app side).

To cover this scenario, the responsibility falls on the developer to make sure that the “last” service in the chain has a way of returning an error message to the client instead of trying to delegate the request to its (nonexistent aka nil) successor.8

 

Where Should The Chain Be Created?

Ideally, chains would be created in the application’s composition root (i.e. the AppDelegate) and injected in the view-controllers/client-classes using it to:

  1. avoid applying the chain creation weight on the client classes and,
  2. maintain a centralised point of change for when we need to add or delete handlers to/from the chain.

 

You Have Been Using This Pattern For Years

Both Cocoa and our beloved Cocoa Touch (as well as most frameworks that handle events) make heavy use of the Chain Of Responsibility pattern.

When a user taps on the screen for example, a UIEvent gets propagated through the view hierarchy until it gets handled by whoever knows how to or is interested in handling it.

All views (UIView) and view controllers (UIViewController) as well as windows (UIWindow) and even the application object itself (UIApplication) inherit (in)directly from UIResponder.

Words like “nextResponder”, “isNextResponder”, “becomeFirstResponder” are spread throughout cocoa projects. “Responder” is essentially Apple’s way of saying “Handler” in a chain. They have actually given this event-handling structure the name Responder Chain.

 

An Object Oriented if-then-else statement

Many people think of the Chain Of Responsibility pattern as an Object-Oriented if-then-else statement or linked-list and that is totally valid. The pattern really is indeed a more powerful and flexible alternative to handling conditional logic and is essentially a linked-list customised for a specific purpose.

 

How Should We Structure Requests?

Requests range from simple method calls with primitive type parameters to complex structured hierarchies wrapped inside objects.

A good approach, from an extensibility’s point of view, is to use a single Request base class as the parameter to a generic handle method and provide different implementations of Request objects via subclassing. This allows infinite options on what an actual request may be. Then, each Handler class can check (via isMemberOfClass for example) if it can handle the particular type of request passed and proceed with handling the request or passing it on to the next Handler in the chain.

For example:

func handle(request: Request)
{
    if(request.isMemberOfClass(ExchangeRateRequest))
    {
        //do something meaningful
    }
    else
    {
        successor.handle(request)
    }
}

This solution is essentially a combination of the Chain Of Responsibility and Command, another GOF pattern. This pattern is essentially baked into Objective-C thanks to the language’s dynamic nature that gives full flexibility and power when it comes to messaging and forwarding requests (using tools like forwardInvocation: for example). What this means is that essentially the language does not need Command.

Swift has (at least temporarily) taken this power away from developers and many people have been really vocal about how they don’t like this.9 This feature is part of the Objective-C runtime so people will probably find ways to work around the limitation or maybe Apple will decide to expose it (in)directly in some way after all.

Command is also very easy to implement in Swift thanks to closures. More on this subject will be discussed in a future article.

 

Summing Up

The Chain Of Responsibility pattern:

  • Promotes loose coupling between the sender and receiver of a request, allowing more than one potential objects to handle a request.
  • Is very useful for fire-and-forget type of requests.
  • Provides backup functionality for requests targeted towards web services that may not respond within an acceptable time frame.

Things to consider:

  • A plan should be in place for when a request cannot be handled by any object in the chain (fail gracefully).
  • Depending on the context, the chain superclass could play a role in deciding the flow of the request through the chain or only provide default implementation(s) for the “handle” method(s).
  • Request representation is crucial for the extensibility of the code base. Plan with potential future changes and needs in mind.

 

There is going to be a section on this website dedicated to the use of patterns throughout the Cocoa Touch framework where the use of the Chain Of Responsibility Pattern is going to be discussed in detail. Keep up to date by subscribing or following us on twitter.

 

Recommended Reading

Books:

Design Patterns: Elements of Reusable Object-Oriented Software (The Gang Of Four Book)

Head First Design Patterns (In my experience, the best introductory book on Design Patterns)

Pro Objective-C Design Patterns for iOS

Agile Principles, Patterns, and Practices in C# (Uncle Bob’s seminal book, a must read)

Articles:

Discussion On Chain Of Responsibility


  1. The currencies supported were USD, Euro, and GBP. Also, this was not an iOS app which goes to show that design patterns and object-oriented principles can be applied and transferred to most technologies rather effortlessly.

  2. They were also willing to pay good money to get rid of that monthly expense, so I decided to take the job.

  3. This is definitely not the main motivation behind the pattern. It’s more of a bonus.

  4. Making decisions based on the worst case scenario is usually the safest way to go. Won’t help with your popularity among your ninja “brute-forcing-everything” programmer peers though.

  5. Health and banking apps come to mind.

  6. In the first case, one could argue that we are closer to a Strategy or a Mediator than a chain but that’s not really true since the ExchangeRateService will still go through all the available services sequentially until it finds the one that can handle the request.

  7. Depending on the use case, a request could go through the whole chain or part of the chain even when the concrete classes successfully handle requests. You usually see this in event-driven technologies and error/exception handling solutions provided by frameworks.

  8. Note that nil or “ignore behaviour” is of course acceptable if it is expected as a potential result.

  9. Swift in general has been criticized as a mixed-bag of popular features from other languages without a true vision or goal. I tend to disagree.

Hiding Complexity With Facades

Very often we are involved in a project and asked to use a “new” component/library that provides a rather cumbersome interface. 1

Or maybe we just want to try that cool open source library we found on github that does incredible animation stuff.

When looking for third-party software to use in a project, people often stumble upon code that is “hard to work with”. This usually means that the interface provided is complex (contains too many methods, it’s hard to understand etc). 2

The Problem

So here is our problem defined:

We need to work with a component or library to add some functionality in our app, but the interface it exposes is complicated, possibly contains dozens of methods and is hard to work with in general.

Especially in hastily written projects, third-party components don’t provide a single point of “entry” i.e. they require client code (our application’s code) to work with more than one class, leading to tight coupling between higher and lower level modules.

Suppose we want to use a third party networking library in our application:

Facade_Diagram

Our code has to maintain references to a third-party component’s classes. Suppose there is a MyNetwork class in our project that needs to communicate with the subsystem/third-party. It looks like this:

class MyNetwork
{
    var networkSetup: NetworkSetup
    var networkSwitch: NetworkSwitch
    var networkManager: NetworkManager
}

And in the method that calls for the network system we have to make the right calls to the third-party methods:

func startNetwork()
{
    self.networkSetup.setupNetwork()
     
    self.networkManager.setMaxConnections()
    self.networkManager.setNetworkDelegate()

    self.networkSwitch.on()
    
    ....
    etc
}

What if we need to swap this component for something else? We would have to edit MyNetwork to work with the new library and remove any references to the old one. This approach is of course a violation of the Open Closed Principle and makes the process of incorporating external code much harder.

 

The Solution

What we are looking for is something that can make working with the complex system easier.

That’s exactly the intent of the Facade Design Pattern. With the Facade Pattern we can take the complex component and make it easier to use by implementing a Facade class that provides a trimmed down and cleaner interface.

Facade_After

class MyNetwork
{
    var networkFacade: NetworkFacade
}

The call to start the network will be much simpler now:

func startNetwork()
{
    self.networkFacade.startNetwork()
}

Now we only need to include a reference to the Facade, that exposes an easy-to-use interface.

Any future changes will only affect the Facade object and not our client. This design decouples the client from third-party code and helps us follow the Principle Of Least Knowledge by constraining the amount of dependencies between the two codebases.

 

Things To Note:

  • We can use abstractions to dynamically swap facades (“hiding” different third-party libraries) at runtime to compare libraries (in terms of resource consumption, performance etc).
  • The third-party code is still available for us to work with, the facade does not prevent us from using it directly, it only provides a cleaner way to communicate with it.
  • You might have noticed that Facade looks a lot like the Adapter Pattern. Their difference is in their intent. Facades are used to provide simplified interfaces to third-party (or even our own complex code), while Adapters change interfaces so that they match the ones some other party expects.
  • Depending on the situation, a system might include multiple facades. Careful not to overdo it though, as facades like any other design decisions add extra layers of complexity.

  1. Expect this to happen when you witness CEOs high-fiving each other.

  2. Interface is used in the general “API” sense here.

Leaving Your Options Open With Adapters

Very often, when developing an app, people need to work with code/libraries/components written by someone else. This need introduces the issue of compatibility between existing code and the third-party code we want to “communicate” with.

A few examples of when this situation can come up include:

  • we are required to avoid modifications of the existing application code when introducing a third-party component to our app,
  • we do not have access to the third-party library’s code (we can only communicate through its public API),
  • we do have have access to the third-party library’s code, but we don’t want to modify it,
  • we want to experiment with more than one libraries that all use different interfaces,
  • we have to replace a third-party component with a new one (because the existing one broke after an OS update for example).

In our example, we will be swapping a third-party menu component for a new one that fits our application’s needs better.

 

Example

In our code, we have included a protocol/interface that expects the classes conforming to it to implement the showMenu and hideMenu methods for displaying and hiding the menu respectively. The problem is that the third-party menu component that we want to use, includes two methods named presentMenu and dismissMenu to achieve the same functionality.

adapter

We are in a situation where two classes with incompatible interfaces need to communicate/work together.

To make the above situation work, we would have to change either our existing code or the code on the third-party library’s side (assuming the source code is actually available to us to tamper with). Both solutions violate the [PDF Warning] Open Closed Principle [/PDF Warning] and could lead to maintenance problems. What if we end up using another library with a completely different interface? We would have to resort to modifications, risking breaking something in our application.

But for the two classes to work together, we need to establish some kind of communication between them.

 

Adapter To The Rescue

We will use the Adapter Design Pattern which according to the Gang Of Four allows us to “Convert the interface of a class into another interface the client expects. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”

adapter_2

The code on the client’s side will simply call the respective methods of the Adapter object:

class ExistingCode{
    
    var menuAdapter: Menu
    
    //....
}
func showMenu()
{
     self.menu.showMenu()
}
func hideMenu()
{
     self.menu.hideMenu()
}

The Adapter, in turn, will simply call the third-party’s methods like this:

class ThirdPartyMenuAdapter: Menu
{
    var thirPartyMenu: CoolMenuWeFoundOnGitHub
}
func showMenu()
{
     self.thirdPartyMenu.presentMenu()
}
func hideMenu()
{
    self.thirdPartyMenu.dismissMenu()
}

The two incompatible classes now remain decoupled thanks to the Adapter that essentially plays the role of a middleman between them.

Also note that if we choose to use a different library, all we have to do is write an adapter for the new library while leaving the application code untouched. We can also use the Strategy Design Pattern to swap Adapters at runtime.

 

Things To Note

  • In this example, the Adapter conformed to a protocol/interface . This provides the flexibility to use as many adapters/libraries as we want and switch between them at runtime. This becomes extremely helpful when we want to test various third-party components to find the one that best suits our needs.
  • It is really important that the interfaces used in an application are designed based on the app’s point of view. Very often, developers let third party code take control of their application by letting dependencies sneak into the core of the app. When they decide the third party component needs to be changed, it is usually too late and they need to proceed to major refactoring. Inversion of control is an important topic that will get its own separate article soon.
  • Adapters are everywhere. Many (most?) developers spend their careers writing adapters to provide communication between incompatible interfaces and applications. In enterprise environments especially, mergers and acquisitions lead to the need for integration between software varying in any possible way imaginable.
  • Adapters should not be used in greenfield projects. There, other designs and architectures should be considered. Software adapters, like their material world counterparts, are meant to be used to integrate already implemented solutions that cannot change their interfaces easily (if at all).

Further Reading

Books:

Clean Code: A Handbook of Agile Software Craftsmanship  (One of my favourite engineering books)

Refactoring: Improving the Design of Existing Code (Martin Fowler’s classic)

Working Effectively with Legacy Code (Maintain your sanity when working with code other people wrote, possibly decades ago)

Design Patterns: Elements of Reusable Object-Oriented Software (The Gang Of Four Book)

Head First Design Patterns (In my experience, the best introductory book on Design Patterns)