Day 20 of #100DaysOfCode
How to deal with third-party codebase?
Learn how to deal with foreign code in the cleanest and productive way
The price of working with foreign code?
Many times we are working with some external third party library which we can call Foreign code. We must cleanly integrate this foreign code with our existing Clean code.
Take for example the Map class in Java, it provides you with a lot of methods for creating and manipulating a Map. If you are using it, you cannot restrict any such operations. If you are passing an instance of the map, any class/object can perform any operation on it.
What if you want to store a single type of object in a map? Currently, you can create a map of diverse types of objects which is conflicting with our interests of Clean code.
To fix the issues we will be writing some extra code for casting like:
// Creating a map of sensors
Map sensorsHashmap = new HashMap();// Let's say you want to retrive a sensor
Sensor sensor = (Sensor)sensors.get(sensorId);
This casting will always be required at all the places where we deal with our sensorsHashmap. Hence, the repeated code can’t be considered clean.
The readability of the code can be highly improved by using Generics.
// Creating a map of sensors
Map<Sensor> sensors = new HashMap<Sensor>();// Let's say you want to retrive a sensor
Sensor sensor = sensors.get(sensorId);
But that just solves the readability part of the problem. Wherever ever you pass the instance of the map there is no limit on the number of operations that can be performed. This is one of the ways to do so.
// Creating a class of sensorspublic class Sensor {
private Map sensorsHashmap = new HashMap();
public Sensor getById(String id) {
return (Sensor) sensorsHashmap.get(id);
} public void addSensorToMap(Sensor sensor) {
sensorsHashmap.add(sensor.id, sensor)
}}
Personal Example, I generally use an external library like Glide to display images in Android from web links. I built a complex application where there were hundreds of view classes where I was displaying an image using the external library. What if I want to use a different library? I will have to change the code, again and again, so I built a wrapper class for setting the Image, this class was responsible for Setting the Image, and internally there was only one line of code which was doing it. If needed to change to some other library, I only have to come to one place to make the changes. Also, I was able to restrict each and every class from being able to use Glide directly.
Our end goal is to have a code which is easier to Understand, and harder to misuse.
How to learn and explore third-party APIs without wasting time?
Suppose it is not clear how to use our third-party library. We might spend a day or two (or more) reading the documentation and deciding how we are going to use it. Then we might write our code to use the third-party code and see whether it does what we think.
We would not be surprised to find ourselves bogged down in long debugging sessions trying to figure out whether the bugs we are experiencing are in our code or theirs. Learning the third-party code is hard. Integrating the third-party code is hard too. Doing both at the same time is doubly hard.
Instead of experimenting and trying out the new stuff in our production code, We could write some tests to explore our understanding of the third-party code. Such test cases are called learning tests.
Instead of experimenting and trying out the new stuff in our production code, We could write some tests to explore our understanding of the third-party code. Such test cases are called learning tests.
In learning tests, we call the third-party API, as we expect to use it in our application. We’re essentially doing controlled experiments that check our understanding of that API. The tests focus on what we want out of the API.
Not only are learning tests free, but they also have a positive return on investment. When there are new releases of the third-party package, we run the learning tests to see whether there are behavioral differences with the code we are using.
Once 3rd party code is integrated, there are no guarantees that the third-party code will stay compatible with our needs. With each new release comes a new risk, If the third-party package changes in some way incompatible with our tests, we will find out right away from our investments made in Learning Tests.
How to work with code that doesn’t exist, Yet!
Sometimes there will be scenarios where you have to code a module that is under your control but that module depends upon a different module that is not under your control at all.
It is your responsibility to keep your code clean and as much independent of the third party as possible. It’s better to depend on something your control than on something you can’t control, and let it end up controlling you! 😰
There are two approaches towards the solution,
- We can manage third-party boundaries by having very few places in our code that directly refer to the third-party code.
- We may wrap third party code as we did with the HashMap example above or we may use an Adapter Class to convert/adapt from the third party code with our perfect clean codebase.
Either way, it’s a win for us as:
- Our code speaks to us better
- Promotes consistent usage of third party code within our code
- It has fewer maintenance points when the third-party code changes.
Remember! Good software designs accommodate change without huge investments and rework
Interested to learn more about Clean Code? Make sure to check out the previously written articles on Clean Code.
Thanks for reading, and as always you are awesome ❤