New project with legacy code – seriously?
One day I learned that I am going to work on a new Android project. I was full of enthusiasm, excited and curious about how my work will look like over the next months! Then I learned about some facts that seemed disappointing to me.
It turned out, that the project was developed some time ago by other developers, who I don’t know, and it is written in Java (Kotliners know what I mean). One look at the code and I already knew I am going to work on a legacy code.
First, I thought Oh no, seriously, do I have to work on that shit?!
But after a cup of calming tea, I pulled myself together and changed my mind. I started thinking of this situation as a challenge. I told myself: Come on man, you can tame the monster. It can be a nice adventure!
If you facing a similar situation keep reading. I hope you will find some pieces of advice that can help you.
Look at a Gradle file
So, you have got the Android project code base and you are about to start working on it but you do not really know what things are ahead. Good point to start discovering your project is to look inside a Gradle file – build configuration script that contains a bunch of useful information giving you a good project overview.
✔️ External dependencies
It is worth to look at external dependencies along with the versions they are using. They will tell you what technological stack was used and familiarize you with concepts used in the code you will work on. Other words, they will help you to understand why the code is written the way it is.
If you are quite new in Android development some of the external dependencies can surprise you or can be new for you if you had no opportunity to work with them before. For example, you can encounter RxJava 1 which reached his end-of-life (EOL) by March this year, Event Bus (very popular some time ago), or even MaterialEditText library not maintained since 2016. Or GCM (Google Cloud Messaging) recognized by Google as deprecated. In some cases, migration to a new technology will be necessary.
✔️ API level requirement
The Gradle file is also a good place to make sure we meet the Google Play’s target API level requirement. Google Play requires that apps target at least Android 8.0. So probably you will have to make some changes to the project before the next app release.
Especially you have to make sure if your UI flows provide affordances for granting Runtime permissions. Wherever possible, your app should be prepared to handle rejection of permission requests. For example, if a user declines a request to access the device’s GPS, your app should have another way to proceed.
Next potential source of issues can be the Support Library used in the app which can be outdated. So in case, you would like to update it, don’t be surprised if some things won’t work as you expected. Support Library Revisions can be helpful.
Check a Manifest file
It is worth to look at Manifest file and analyze the information important for us.
The Manifest file provides you with information about permissions used in the application. Among them, you will find permissions which are granted automatically and those which need to be granted while using the app. The second ones are Runtime permissions – how to take care about them I wrote above.
✔️ Deep link schemas
Manifest file contains also deep links schemas. If within the app there is an excellent mechanism to handle deep links and launch Activities related to them, then it’s nothing to worry about. Otherwise, it is worth to know by which Activities we have to be careful.
Write tests if they are missing
Writing a code is what we are paid for so let’s dive into the depths of code. When we are working with a legacy code, one of the common tasks is to refactor the code. But how to be sure that if I change something in one place, it will not break down in another one?
Tests should protect you from uncertainty but if there are no tests in the project we should write tests before we start doing changes.
In my case, there was plenty of untested code, and – what’s more – untestable code. One of the helpful tools, in this case, is PowerMock. It provides you with mechanisms to mock static methods, constructors, final classes and methods, private methods, removal of static initializers and more. They can help you to save some time.
Refactor the code using Kotlin
When we have our class tested, we can go forward to refactorization. First I thought that my comeback to writing in Java will be unnoticeable. But I was doing silly mistakes. For example, I was forgetting about semicolons and “new” before a class constructor. I realized how much do I miss Kotlin.
But even if the code is written in Java, we do not have to resign from Kotlin fancy features. As Kotlin language creators say, the language is interoperable with Java. So it means, you can implement new stuff in Kotlin, which will be much more concise than then written in Java.
Kotlin helps a lot in case of refactorization. Some things can take much more time rewriting them clean in Java style. So consider extracting code to new Kotlin class and then simplify it and use it in a Java code.
Why understanding the legacy code is so important?
One could say: Why Gradle and Manifest review is so important? I prefer to get to know the project on the fly than staring on those files and wasting time.
Well, our work is closely connected with business and our clients want to know how much time will it take to provide new functionalities. Having a good project overview and understanding it is crucial to provide accurate time estimations which in turn allows preventing complications in the future.
Working on someone else’s code can be frustrating, but before you start to curse it, try to understand why the code is written in such a way. At first glance, something can seem completely unreadable but diving into it can help you to understand the code and save you from the future trouble.
I can not say that working with legacy code is trivial. Of course, it is much nicer to work with Android Jetpack, write the entire code in Kotlin, with no need to support very old Android System versions. But – in my opinion – what doesn’t kill you makes you stronger.
I have learned a lot about the Android Framework and Support Libraries. What is more, I had an excellent environment and play-ground to apply mechanisms from the “Working Effectively With Legacy Code” book.
If you have faced similar issues and have some advice, please leave a comment.