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.