iOS: Simplifying Dependency Injection with the Facade Design Pattern
If we are working in an app with too many modules and so too many dependencies in each one, it can be massive to count all of them in order to inject in each class they are relied on. Imagine, for instance, that you have a layer in your application that deals with network calls. For that, you certainly need a JSONDecoder, some DispatchQueue objects to handle with threads and concurrency, maybe a feature flag manager object and so on. Imagine how complex an initializer for this class may become since you need to pass all those instances and even more, in order to make it testable, all of them should be mockable.
Fortunately, there is a useful solution to simplify too many dependencies to be passed to a class and even better: it can be divided into smaller ones if not all of them are needed. Let's discuss that further:
First things first, let's introduce the Facade design pattern and explain how it works. After that, you shall comprehend why it's so important to our solution. Imagine you have some classes which one with a single proposal, but those tasks together form a bigger one. I will present as an example the first use case where I learned this pattern: A washing machine.
There are many steps that compose the job of a washing machine, and each one is performed by an individual component: there is a bomb, a valve and a motor. But all of them are single steps for the same purpose: washing clothes.
In order to organize all of them inside a single bigger class that relies on those instruments, there is a class that holds one instance for each class, therefore simplifying in a single place where to find each tool to perform the job. Think of that as a Swiss army knife!
So, if a class depends on multiple contents that are kept inside the Facade, why not passing the Facade class itself? It's like a toolbox that your class may access.
Facades and Dependency Injection
Imagine now an application where classes have their dependencies injected and there are classes that rely on the same dependencies and others depend on different ones. Let's simplify that and create a Facade to hold all possible dependencies for our project. This way we make it much easier to access them when needing to perform tasks:
When you need any of those dependencies, just call the DependencyFacade:
Actually, when we are working in a huge project that is divided into so many modules, the idea is to keep a Dependency Facade for each one since each module may have its own necessities, resulting on different dependencies, but the inner classes may have very common ones.
Ok, we defined a single place for all the possible dependencies in our project/module, but we are not considering something yet: What about if we have a type that actually relies on one single dependency? Injecting the whole DependencyFacade would be passing everything into that and it's not actually necessary. It's like we had a heavy toolbox that some staff needs to bring to some place where he actually just needs a small hammer. There should be a way of picking the specific tools out of the box and bringing only what we really need.
For that, we are splitting our big class into separated components by implementing a protocol for each dependency it holds that confirms to us and its client that the box contains that specific instrument(dependency). Take a look at our solution:
Now, instead of passing the whole box into the class, let's pass just a smaller version of it that contains only the required tools. Let's say our class just needs the first two dependencies to be injected:
You can see now that we defined a custom type via typealias saying that we can only see Dependency1 and Dependency2, therefore having access to a simpler type than our whole DependencyFacade(passing this concrete type by default). This provides a much clearer view to whoever is developing this component.
Now, we created a flexible type reuniting all possible dependencies and a way of injecting only what is really important to that context.
It's not necessary, but a good practice I like to adopt is to define one last protocol for when we don't have any dependency. It's semantic, we are telling that our class could have some dependency injections, but in this case, there is no one we actually need. It's just a pattern:
Don't forget to make your DependencyFacade to conform to it.
Don't forget to make everything testable
In order to follow the SOLID principles and make your class testable, don't forget that is a great practice to create a contract for each dependency inside the Facade in order to let it be mockable:
When you need to test a class, create a new class as a DependencyFacadeMock, and provide the corresponding mock for each object it hold, not interfering with the unit tests:
Now check what to do when unit testing:
Don't forget to provide a mock for each dependency inside the Facade!
This article provides you a great combination of two design patterns(Facade and Dependency Injection) in order to one simplify the other. With the power of protocols, we created a way of dividing our Facade into smaller types, allowing each class of our application to bring inside just the tools it needs to perform tasks. With it, this is very easy to mock a single type, since technically each class has just one dependency, and them make the unit tests. I hope you enjoyed ;)