Intro to App Modularization

Mario Sanoguera de Lorenzo
ProAndroidDev
Published in
4 min readAug 29, 2018

--

The Lego Batman Movie

Hello everyone! đź‘‹ In this story I want to give a brief introduction to App Modularization, some thoughts around it & first steps you can take to achieve it.

First of all, what is App Modularization?

App Modularization is the process of applying Modular Programming to our Android App.

Modular programming is a software design technique to separate functionality into independent, interchangeable modules, so that each contains everything necessary to execute a specific functionality.

We can achieve this through the creation of Feature Modules.

Why should I Modularize my app?

  • Faster build times.
  • Fine-grained dependency control.
  • Improve reusability across other apps.
  • Improves the ownership & the quality of the codebase.
  • Stricter boundaries when compared to packages.
  • Encourages Open Source of the newly created libraries.
  • Makes Instant Apps & Dynamic Features possible (improving discoverability).

When should I Modularize my app?

When it makes sense but always having in mind that the goal is to separate functionality into independent, interchangeable modules.

The sooner, the better. This is to avoid higher amounts of refactoring later on. A similar experience that we might all have is jumping to our initial god activity projects and adding Presenters/Repositories into it.

How does a Modularized App look like?

What kind of modules are there above and what do they do?

app → Empty Application module that only launches features.

Feature Modules → (login, home, atmfinder, transactions, settings).

Shared Modules → (useraccount).

Base Modules → (network, auth, cache, presentation).

** Auth & Network are Kotlin Modules.
** Atm Finder & Spaces are Dynamic Feature Modules.

Loading only the active module you are working with.

Right-click into any folder in AS > Load/Unload Modules.

This IDEA feature will unload the modules that you aren’t using, skipping & avoiding their compilation. In the example above, app depends on the feature module atmfinder which, in this case, depends on all of the base modules.

Atm Finder is just a feature that displays the nearest ATMs based on your location. This module helps encapsulate google maps dependencies, location permissions & Google Maps api key.

This enables something like Android’s Dynamic Features but for the development environment, taking build times close to a sample project & increasing development speed by saving build time.

Feature Modules: Keeping it Clean.

Feature Modules → (login, home, atmfinder, transactions, settings).

All of these Feature Modules are user-facing functionality. The same way we don’t have package names like activities/fragments/adapters we shouldn’t fall into the same mistake when creating these modules. Each module should contain its own presentation, domain, data & data sources layers (if they require it).

Remember, keeping modules Clean improves testability and eases future refactoring in case it needs to be shared between multiple user-facing features. (useraccount is a shared module used by login & settings in the example above).

Base Modules: Avoid a single Base Module.

Base Modules → (network, auth, cache, presentation).

All of these base modules will never be user-facing and will only be used by 1 or multiple Modules. There is an interesting dependency of Network depending on Auth due to the Retrofit Client having to authenticate calls before being sent.

Presentation contains mostly View/Keyboard extension functions & some goodies for ViewModel like the SingleLiveEvent from google samples.

A single base Module with a generic name such as Base or Core can be a clear indicator of a module that is not defining well enough what its responsibility is.

My advice is to stay away from a single Base/Core Module. Don’t be afraid of splitting the base functionality of your app so feature modules can pick which base functionality they need. This will also avoid the transition from a monolithic app to a monolithic base/core scenario.

How to deal with multiple build.gradle files?

With App Modularization we want to gain fine-grained dependency control but we also need to make sure we don’t end up maintaining multiple configuration files.

The following common-android-library.gradle is applied to every feature module I create with apply from: "$rootDir/common-android-library.gradle".

For Dynamic Feature Modules I use the following:

To end with, for Kotlin only libraries I use:

These common gradle files are very useful for shared configurations, plugins & dependencies across different modules but it can also be a double-edged sword if overused. Having unused dependencies propagated to some modules that aren’t making use of them.

Let’s see how does the gradle from the Login Feature Module looks like.

As you can see thanks to the common gradle files we ended up with a concise and small login.gradle.

My only advice when Modularizing is to use common sense trying to take only the near future into consideration.

That’s it! Hope that you were able to get some of my ideas regarding App Modularization through this story. 👏

For more, check out my personal test project which has already been feature-modularized! 👇

Remember to follow, share & hit the 👏 button if you’ve liked it! (:

GitHub | LinkedIn | Twitter

--

--