iOS Development: Isolate your dependencies.
Handling dependencies is the most important job in an application that uses third party frameworks. Good handling improves the maintainability of the project while bad handling dramatically increases refactor time and makes a project so bind and dependent to a framework which makes it very difficult to remove, even after days of refactoring.
In iOS the most used dependency manager is Cocoapods, there are way too many good things there, ready to be used in just a few minutes. Should you use any open source framework blindly without any organisation ? Of course not, but instead you could learn to use them with the isolation method.
In this post I will show you how to use isolation to improve code quality, maintainability and reduce refactor time. The mentality is very simple, think that every third party framework is a virus that will effect the rest of the code. So you isolate each framework in a quarantine.
A state, period, or place of isolation in which people or animals that have arrived from elsewhere or been exposed to infectious or contagious disease are placed.
A single file which imports a framework and exposes its goods in the rest of the project while not letting the framework effect the rest of the code.
To use isolation follow those very simple set of rules:
- Each framework should be imported in a single file and a single file only
- Each framework should be removed or replaced under maximum 10 minutes regardless the project size
- Each quarantine should be ment for only one framework
Now having those simple rules in your mind let's have a look at this example of a controller that uses GoogleMaps.
Bad sign: a framework imported in a controller which indicates than any new controller will follow this implementation, spreading the framework across the project.
Downside: increases refactor time and makes it very difficult to remove or refactor.
Time to create a quarantine to isolate GoogleMap framework. The file will contain UIView which will privately contain the GMSMapView. In your file you should expose any GoogleMaps functions you use in your project.
Let’s see a basic quarantine with two functions, one to set a marker and one to set the map camera.
SetMarker and setCamera are simple wrapper functions and without them there is no isolation. You should not make mapView property public because you don’t wont to use google properties directly.
And after this your controller should look like this
Upside: No GoogleMaps import, therefore this controller does not use the third party framework directly but uses the classes that wrap the framework’s contents. We can continue with this implementation to any new controller and even after months of development we can change GoogleMaps with AppleMaps in a blink of an eye.
Lets see how
What we want to achieve here is to change from GoogleMaps to AppleMaps by changing one file and one file only. If we fail it means that we didn’t isolate the dependency correctly.
In order to make something so modular we need to use protocols, so lets create one and include the two functions we exposed from GoogleMaps. Also we need to create a Base view which will conform to this protocol.
Now make GoogleMapView inherit from MapView instead of UIView and override setMarker and setCamera.
Now lets check our controller.
Our property is now MapView, and we initialize it with GoogleMapView. Thats great, now lets create the same model but by importing AppleMaps.
We create a new file, import MapKit, and create a MapView subclass named AppleMapView. Override and implement methods and our file should look like this.
Go to your controller, change GoogleMapView with AppleMapView and you are ready. It works because both views inherit from MapView and our controller’s property is MapView 😱.
But if you had 20 controllers with a MapView property, you would have to change 20 initializers, and thats not good…
Simple solution, create a Factory.
So now your controller doesn't initialize a GoogleMapView nor an AppleMapView but instead a MapFactory model is responsible to return the current map type (Single Responsibility Principle) and the controller has all the functions it needs which are added in the MapViewType protocol.
Great now let's answer the previous question, how many changes are needed to remove GoogleMaps SKD ?
Only one property
inside MapFactory, simply change the currentMap case. This is pure maintainability as your project doesn’t depend on any dependency and you can remove GoogleMaps at any time under a few seconds without any compilation error 😎.
Thank you for reaching the bottom of this post, I hope you gained something and improved your skills although the example was very simple. Please feel free to express your thoughts.
What are you waiting for ? Create your first quarantine ☠️.