Modular Architecture with Android Gradle Plugin 3.0

I hate Android
4 min readJan 13, 2018

--

Here the first part of this series

Multi-Module Project doesn’t mean necessarily Instant App, you can build a MMP and have many benefits in your regular App. I’ll focus mainly on two aspects: Build Speedup and Encapsulation

Build Speedup

To understand why a MMP improve the build time we have to understand why the build time is slow and which improvements Android Gradle Plugin 3.0 brings to solve this issue.

Jerome Dochez (Tech Lead Build system Android Studio) gives a detailed explanation in this talk. I’ll focus on the following two quotes.

It sounds very easy, modularity is not easy, I can guarantee. It's gonna be painful if you wanna do this ... However it has a lot of improvement with it

Jerome explicitly says that it will be painful but is worth for all the improvements we can get. Then starts talking about Annotation Processors

javac is in theory incremental ... Some Annotation Processors want to see the world.

Dagger wants to see all the injection points, so if you change only one class we have to recompile everything

If you split javac in multiple modules, none of them will be incremental, but since they are smaller they are faster

You will never get as much parallelism as if you are using multi-module projects

Let’s try to understand what he’s saying. javac is the gradle task that actually compile your java code, and in theory is incremental; that means: a single line edit should not trigger a full compilation, but just compile that line and dependent code . In this way the first cold build is slow, but next hot builds are faster.
Now the problem with Annotation Processors: some of them like Dagger2 needs to see all the injection points, gradle has to turn off the incrementality to feed the AP. This will result in a full build for a single line edit.
You will have the same problem with spaghetti code, since everything depends on everything else, also a single line edit could trigger a full build.

The solution is parallelism, if you split your project in independent modules they can be built in parallel using your multi-core CPU and only changed modules needs to be built.

Following an article to explain how to use Dagger2 in a MMP.

Encapsulation

MMP could enforce feature encapsulation. This is not useful only as a generic best practice for maintainability and readability. In a fast growing company with cross functional teams, each team could own a feature or a module. In this way each team is completely independent having access to java/kotlin code, resources, build.gradle, proguard.config and so on.

Let’s see an example of module decomposition

Base Module: contains code and resources shared among all features, like MyApplication class and AppTheme resoruce

Components Module: like a base module but is common to only few features; an example is the recipe-browser being used both in the home-feature to display all the recipes, and in the profile-feature to display favorite recipes for that user

Features Module: represent user features, like the login screen or the recipe screen. Potentially each screen/activity could be a different feature.

Installed Module: is the regular app module that contains no code, but just a dependencies to all the feature to build the apk

Instant Module: like the Installed module, containing only the features for the instant app

As you can see, an higher level module can depend only to lower level modules; and modules in the feature layer cannot depend each other. This allow to substitute or remove any feature module with a different implementation.
In our instant app we decided to show the full app installation dialog when a user try to make an action that requires authentication; i.e favorite a recipe. Usually that will trigger the login activity present in the login module, but in the instant app we can substitute the login module with a login-dummy module that will show the full installation dialog.
The implementation details will be available in another article.

We just built a plugin system at build time. It really helped us when a company asked to release an sdk containing our app with a different home module. We just had to create an home-custom module.

There are two kinds of problem to consider when trying to achive this architecture: one direction vertical dependencies and no horizontal dependencies.

We will see a new article examples of both.

--

--