From legacy Android app to a modern app architecture

Optimizing build time, our first step for an ambitious project

Quentin Braet
5 min readAug 7, 2018

Every experienced Android developer has come to this point: you’re working on a big legacy project with a lot of flavors and build types. The codebase is huge, and your dependency tree looks as if it’s inspired by a Node.js project. Sometimes, this just becomes inevitable when a project goes into maintenance mode for some time. Mobile development has evolved rapidly in the past years, the platforms have become more mature and many new architectural patterns and tricks have come up, these are things that you can’t always keep up with during maintenance.

And then, suddenly, it happens, you have the opportunity for a big overhaul of this monolithic beast that you call your app. Deadlines are tight, but you know that this is the moment to do it. But then fear kicks in: where do you start? Well, it’s simple, just do it.

Don’t waste time on builds

It’s not because it’s a valid excuse, that you can’t do something about it. Source: xkcd.com

As the old saying goes: time is money. Business owners are certainly concerned about the last part, but as a developer, it’s probably better to state this differently to keep you motivated: wasting less time is an opportunity to try more awesome stuff. That’s right, time is your greatest resource: of course you want to crush the deadline, but most of all, you want to learn and be proud of the product you build. This also means trying out new stuff and see it end up in the production version of the app. And we want to facilitate this by taking away things that prevent us from using our time optimally.

That’s exactly where our focus is at the start of the project: optimizing build times. Chances are big that for a legacy project, these build times are getting out of hand. So what can you do about it?

Update your Gradle version

Gradle is the beating heart of your build, so at least give it the attention it deserves. First of all, update your gradle wrapper. There’s almost never a good reason to stick with older versions. It’s as simple as using this command.

./gradlew wrapper --gradle-version 4.6 --distribution-type bin

Configure your Gradle properties

Also don’t forget that there is a global gradle.properties file (located in ~/.gradle/) where you can configure your local Gradle setup. A configuration that works well on my machine is given below.

org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

There are a lot of helpful Medium articles which explain how to configure these parameters. But the most important one to note in our story is the parallel option. Of course you have an idea about what this will do, but maybe you didn’t think about how you use it to its full potential: if your project is a big monolith, this option will probably not gain you a lot of time. The best thing you can do to really heat up your processor cores, is splitting up your project in independent modules. We will tackle this more in-depth in one of the next posts.

Cleanup unused dependencies

It might seem logical, but on a legacy project there’s always the danger of dependencies that are still added to your project but are no longer used or only for a small section of the app. Try to clean them up, if you only use them for one method, maybe it’s worth it to just copy that method somewhere in your project instead of compiling the whole dependency.

“I don’t have this kind of dependencies in my apps”, you say? Well, maybe you should check if you still have that bloody multidex library inside your project. Chances are big that you were allowed to drop support for Android 4.4 recently but you forgot that this implied that you could now safely remove this dependency in your project. Hooray!

Gradle Sync and flavors

Ok, so you’ve might have heard of most of the tricks above, but you still have a slow build. This was also true for our case, in fact: our developers almost didn’t dare to cleanup the build.gradle file because every change resulted in a long Gradle sync of multiple minutes.

When researching this, it turned out that this was due to the many flavors (in multi dimensions) we had in our project. But hey, flavors are one of the cool tricks in Gradle, we didn’t want to loose the flexibility of them! We have integrations with multiple services that all have their staging, acceptance and production environments. Often we are requested to deliver a build with a specific combination for all of them.

But think of it: how many times do you really change the flavor during development? Not much isn’t it? So here comes the trick: don’t build what you don’t need. The fact is, that while Gradle is syncing, it has to read the configuration for every combination of flavors, and this takes time.

But here’s the trick: create a dev.properties file in the root of your project containing a variable for every flavor/buildtype.

buildType=debug
service1Environment=acceptanceService1
service2Environment=productionService2

And add this in the buildTypes section of your module build.gradle

The setIgnore method will, big surprise, ignore the flavors that do not match what you’ve specified in the dev.properties file. Make sure that you manually sync your Gradle project via “File > Sync Project With Gradle files” since Android Studio won’t pick up these changes. Oh, and don’t forget to add the dev.properties file to your .gitignore, this way, your CICD system will still be able to build all possible variants.

The only downside of this method is that you can no longer change your variants via the variants tab in Android Studio. But for us, this resulted in Gradle syncs of less than 30 seconds instead of 5 minutes. Let’s say that you do this 10 times a day: you’ve just gained 45 minutes a day. If that isn’t worth it…

What‘s next?

The goal of this article was to give you some insights about what we tried improving during our development cycle. I’m planning to do some other posts in the near future, but we’re talking about an ongoing project so the topics are not set in stone, they will change when we discover new improvements. If you have any topics that you would like me to tackle, please comment below!

Coming up:

  • MVP & our clean architecture approach
  • Keeping iOS and Android development in sync

Want to join our amazing team during our journey to build better digital products? Go to https://inthepocket.com/ and drop us a message.

--

--