MoviesPreview: the Android app project modularization

Juan Peretti
4 min readDec 26, 2019

--

MoviesPreview is a typical Android Application that queries The Movie DB API and presents the data available to the user. The user might do different things with that data, besides browsing it. But mainly, MoviesPreview is an ongoing effort to expose my ideas and to try to stay up to date with the development of Android Applications.

In this post, I expose how the Android project is modularized and the advantages that this modularization has brought to the project.

Why modularization?

First of all, because it is a hot topic - or it was at the moment of this post. You can find a lot of posts and videos of why modularization is good in Android applications. In my personal experience, I always thought that modularizing things (anything) help to understand the logic behind it. Back in the day, it was hard when we worked with Java and Ant in order to build Android projects. But with the migration to the Gradle build system and some other tools, modularization has become a super-easy task.

Having said these things, I think these are the three more important reasons to modularize MoviesPreview:

1 — Decoupling logic: a strong architecture with the correct modularization approach has really helped me to decouple the different structures and data that I use in MoviesPreview. Grouping components based on the type of data they handle and the logic they respond to has had a huge impact on the independence of the software components.

2 — Improving build times: using Gradle correctly to import the different components has improved the build time of the project, compared with the very first version of MoviesPreview that I did a couple of years ago.

3 — Instant apps: I have the plan to implement some small instant app features for MoviesPreview and, by modularizing from the start, I know that I have saved a lot of time to implement this kind of feature in the future.

MoviesPreview modules

MoviesPreview modules

At the lower levels, we find what I call the support modules. They provide multi-purpose support for the upper levels of the project.

  • mpdata is the module that contains the data layer of the application in the form of repositories implementation that provides access to specific data types by API or cache access. This module has dependencies over mpdomain and mpcommon to provide its functionality and it has a dependency over mptestutils in order to be unit-tested.
  • mpdomain is the module that contains the domain classes of the application along with the definition (the interfaces) of the repositories that provides access to the domain classes. Its unique dependency is over mpcommon in order to access certain utilities that it needs. It also has dependency over mptestutils in order to be unit-tested.
  • mpdesign is the module that contains all the design definitions used in the application. Things like styles, colors, string resources, dimensions, and custom views are contained in this module and are used by the features and the application module. The purpose of this module is to provide a way to re-use the UI components by different features. It does not have dependencies over any other application modules.
  • mpcommon provides utilities that are used by different modules. It contains extension functions and base-classes with common functionality that is extended by the feature modules. The only dependency this module has is over mptestutils in order to be unit-tested.
  • mptestutils contains tools that are used to unit-test the code. Sadly, there is no way (or at least I couldn’t find any) to have a Gradle module that is only consumed by test classes. That is why I have this module at the same level as the others. The way I control that the code in this module is not included in the production code is by restricting it to test sources using the @Restrict annotation in all of the files of the module.

This lowe level provides the base to the feature modules and to the application module.

Each feature of the application is self-contained in its own module providing a logical division of limits between each feature. Each feature module contains the Views (implemented as Fragments), the ViewModel (s) and the Interactor (s) to provide the feature defined by it.

Finally, the app module makes usage of all the modules beneath it and provides the glue to allow the application to work as a whole.

--

--