This is the first post from a series where I would like to share my experience working on a huge Android application and the process of moving from a monolithic and untestable codebase to a cleaner, easier to maintain and scalable app. In other terms: Cleaning Legacy Code
Legacy Code is code without tests.
First I want to make it clear that this is a very long and tough process. Sometimes we learn a new pattern and we try to apply it everywhere in our app, and this is the first mistake. In such big applications with tons of legacy code, patience is your best friend. Try to apply your ideas and improvements step by step, in small sections and most importantly, with the agreement from all your developer colleagues.
… (working with legacy code) is about taking a tangled, opaque, convoluted system and slowly, gradually, piece by piece, step by step, turning it into a simple, nicely structured, well-designed system.
If you have ever worked on an already started project, then you know what legacy code is. And you also know that you can find almost anything in there. But this is a normal process tied to software development.
What you write today, will be legacy tomorrow
For me this is a very interesting quote and in my opinion we shouldn’t blame the legacy code and their authors, since most probably you would have written the same at the time that code was written. The developers, the languages, the patterns and methodologies evolve, and thanks to that legacy code we can learn and improve our software.
Until recently we were developing Activity/Fragment-based applications. Everything was there! From the view logic to the network requests and error handling. That was the way Google taught us in their trainings and documentations, and that is how we were coding. Therefore nowadays we can still find in Legacy Code many God Activities
As was said before, it would be suicide to refactor such a monster in just one iteration for many reasons, the most important being the lack of tests. These kind of classes usually have no tests due to the high coupling to the Android framework and the difficulty of mocking all the dependencies.
“It’s just 6 lines”
To illustrate it with an example, we are going to add a very simple feature. It is about changing the Activity title depending on a value we get from the intent extras. To do this the old way would be very obvious:
Easy, or? You could say: “It’s just 6 lines of code, it is not worth it to invest more time on that!”. But the truth is that this is not just 6 lines. It is 6 lines in a class with probably more than 500 lines, and even worse, they aren’t going to be tested. New Legacy Code was just born…
Now, let’s forget about this, and let’s do something for the common good, something decoupled and testable: let’s create The Presenter!
A Presenter is one of the components inside the MVP pattern. This pattern is one of many patterns we could use in our applications to decouple the code. I chose MVP because it is the one I am using in my daily work and IMHO fits perfectly with Android.
Creating a Presenter is very straightforward. You just need a new class and a good name. Our convention is to link the View name with the Presenter name. Therefore if our View is called AddressActivity, the Presenter will be called AddressPresenter. Now that we have the Presenter, we can add the logic for our feature there:
We now have this small piece of code isolated in another class which we can very easily Unit Test because it is totally decoupled from the Android Framework. But this is just the beginning, we get even more!
Extras for Free
The best part of creating a Presenter are the extras we get. By convention the Presenter never talks directly to the Activity, it talks to the View interface which is implemented by the Activity. We can create our View interface inside the Presenter.
With just this simple step, we now have a place to write new code or move existing code from our God Activity. And, what is most important, the code in the Presenter is -and must be- decoupled from the Android Framework, which allows us to easily write tests!
This technique is called Sprout Class and is described in the book Working Effectively with Legacy Code. We should be happy, we have just completed our first step towards Clean Architecture and Testable code.
If we are always complaining about Legacy Code and about how hard it is to add or change something in it, then let's do something to improve it. Most of the time it may seem easier to just write 10 more lines to the existing Activity to add that new feature, but in the long run it is going to lead to more problems and bugs, and we will need to invest precious time fixing them.
Force yourself to create a Presenter for that God Activity and you will get, for free, a clean place to add your new, shiny code and what is even better, it will be testable!