Modularization by Feature and Layer with Android Architecture Components

Alireza Rafeezadeh
The Startup
Published in
7 min readJul 9, 2019

--

Hello! In this story I want to have a quick look at modular android development in conjunction with android architecture components.

Modular app development got more trendy this year at google IO 2019 (Yigit Boyar and Florina Muntenescu had a great talk I encourage you to watch it). Additionally Android architecture components have become an inseparable part of native android development and more and more developers start using it. However there are many ways that one can (and maybe should) architect an app but using android architecture components makes life and coding a lot easier. Here our goal is to dive into modular android apps and see what benefits we gain from them and then use architecture components along with a modular app which also uses the repository pattern which is another recommended way of architecting android apps.

Modular apps

First what is a modular app? According to android official documentation:

Modularizing your app is the process of separating logical components of your app project into discrete modules.

So modules are parts of our app which hold distinct responsibilities and can interact with each other.

Developers mainly tend to write their apps in a monolithic way. On the other side are modular apps. Developing modular apps requires more effort, so first we should consider why we want to do modular.

Why modular

Modular apps done correctly will have these benefits:

1. Scale and Maintainability

When the code base is getting bigger and specially when our team grows, working on a single module will be a pain. So when there are several people involved in our projects developers can work independent of each other if the project is modular. By separating our app into different components developers can work better and every one has their single territory and no overlapping of work area occurs.

Furthermore looking for a specific class or layout or resource will be very hard in a single module app. Why? It’s clear. You have to look into the whole project, there is no separation. But in a modular app you will find what you are looking for a lot easier.

3. Gradle builds faster

We have faster build times in a modular app. When you change a single file in a monolithic app gradle should build the whole project but in a modular app only the affected parts are recompiled.

4. Smaller APKs

By excluding some features of your app as on demand as part of dynamic delivery your app will be much smaller.

There may be some features that you wish to include later like some paid features or pro features. Those can be feature modules.

Google recently introduced dynamic delivery. You may wish to include some features of your app apart from the base module. Thus delivering features of your app could be conditional depending on the user’s device or needs. This is called dynamic delivery with split APKs.

6. Reusable Code

There are lots of code that we use and repeat on every project. We mostly want to avoid this by writing once and sharing code between projects. By modularizing our code into decoupled sections we could easily share reusable stuff and this will save us great amount of time instead of writing repeated code again and again.

7. Contribute to open source

Leading companies like Uber, Facebook, etc. have open sourced some parts of their projects. This way their potential bugs will be discovered faster and also others who are looking for similar features will take advantage of their code without having to reinvent the wheel. If you do not want to open source your whole project but maybe some parts of it, then why not develop modular?

Start developing modular

So modular apps seems nice right? Then how can we do it? We can modularize an app in two ways: By feature and by layer.Now let’s elaborate on each of them.

Feature Modularization

There are two kinds of modules in android: library modules and dynamic feature modules.

Library modules are built into our app and are essential. Dynamic modules are modules that can be installed on demand and should not include any base features.

We can decouple some parts of our app into separate features, each feature specializes in a specific area.

Library modules are common modules we know and use across our apps. App module will depend on library modules and they provide essential functionalities.

Dynamic feature modules can be used for on demand code loading via dynamic delivery.

Users have the option to remove them later or install dynamic features if they want to. The main limitation of dynamic feature modules is that app module could not depend on dynamic feature modules.

So which modules should be dynamic feature modules? First let’s see different dynamic feature types. Then it will become clear when to use each one.

With the help of dynamic delivery you can customize how and when certain features of your app should be downloaded into user’s devices. There are several delivery options to consider:

  1. At install delivery: the feature is downloaded at install time but the user is able to uninstall it later
  2. On demand delivery : some features require the user showing interest to get installed. Like pro features or paid features. These could be on demand.
  3. Conditional delivery: when you customize a feature based on a specific quality, for instance region or language, then the feature is conditional.
  4. Instant delivery: you can provide some features of your app as an instant access so the user can test them right away without installing. Just hitting the try now button in google play and there you are in the app. Those features are instant delivery.

How can we achieve this feature modularization? What can/should be our features? According to the app nature the answer is different. You can look into some open sourced apps like plaid.

Layer Modularization

We have the option to modularize our app by layer. Each layer has a certain functionality.

Most apps will have these layers: database, network api client, repositories, user interfaces and styles.

Network client module fetches data from web and database layer will persist the data we get from network into a database.Then there is repositories layer where all repositories live.

A repository depends on a network and databases layer and its responsibility is to get data and persist it with the help of those two, it connects database and network layer in a way. And finally we have UIs layer which depends on repositories. We may have a styling library layer too in order to provide custom styles.

There’s also another way of modularizing and it’s a mix of the two above, which here we will make a sample project and showcase it alongside with using android architecture components.

The sample illustrated here sample is going to use jsonplaceholder apis for simplicity.

The structure is as follows. we have three feature modules albums, photos and account.Each album has photos. There’s also one layer module named datasource. All modules are library modules.The account feature does nothing and it’s a layer the app just goes through. First there is login then an album list and clicking on each album navigates to photos.

Although In a real life example feature modules should be more meaningful and comprehensive, simplicity was preferred here.

dependency graph of modules

The architecture components used are these: LiveData, ViewModel, Navigation and Room. Also dagger is used for dependency injection.

Let’s consider albums layer.

In the datasource layer we have CacheInterface, all persistence layers implement it:

AlbumPersist implements CacheInterface

NetworkClient is our base class for retorift and NetworkModule is responsible for providing retrofit and OkHttp stuff

Then our datasource for albums will depend on networkClient and AlbumPersist.

We inject both into AlbumsDataSource with constructor injection:

Navigation in each feature module is easy as expected. But how should we do it when navigating between feature modules? It’s simple with navigation library version ‘2.1.0-alpha03’: We can deep link into it.

In the navigation xml in which you want to deep link into, we add a deep link tag:

Then in the corresponding fragment:

And the complete source code:

Conclusion

There are certain benefits in writing an app modular and using architecture components with them. But it requires more effort and time and you may face some challenges. Therefore, if we are able to dedicate the time, then our app will be more robust, less error prone and hopefully our users will be happier :)

By the way, If you liked it please share!

--

--

Alireza Rafeezadeh
The Startup

Android Developer at @tretton37 and Tech Enthusiast