The ABC of Modularization for Android in 2021

Christopher Elias
ProAndroidDev
Published in
7 min readJun 3, 2021

--

Photo by La-Rel Easter on Unsplash

Modularization is not a recent topic at all. This concept have been around us for years! but probably there are some folks around there that didn’t saw or heard from it till now. Today, my goal is to make sure you have a better understanding of modularization by the end of this article, and I’ll hope you’ll try it as soon as possible.

Let me divide this blog in 5 sections (Don’t worry, as with my other blogs, I’ll go straight to the point).

Monolithic world 👶

Default monolithic project structure (1 single module)

Yeah… it looks very familiar isn’t it? Yes, that’s the default project structure A.S give you when you create a new project. We don’t have time and start coding. We put networking stuff, repositories stuff, data sources stuff, and any other stuff/libraries you can think off, we just put it all there, in our awesome app module.

What if our app start growing till the point it now has like +60 screens, some of this screens have complex UI, or some of them use specific libraries like Lottie, only some of them have sockets connection, etc…

Let me ask you a question, what do you think is going to happen in your monolithic app on that case🧐? (Take a few seconds and think about it).

What happens when my project start growing 📈?

I’m going to address you some of the things that DEFINITELY gonna happen when your project grows. Let me know in the comments if we thought the same points.

  1. You probably didn’t realize but it is very likely that you have circular dependencies between your features. Something like FeatureA calling FeatureB and vice-versa (I’ll be addressing you why this is bad for your project later).
  2. As I stated before, probably only a few or just one of your features uses certain library, but like we only have one module, and all our features live inside that module, all of them can access to any library that is implemented here, even if they don’t use/need it.
  3. If you modify only one of your features, the whole app module will be recompiled. And believe, if you have thousands of features, uses dagger, etc. That build time can be a looong time.
  4. If there are more developers working on the same project, the probabilities to break something are higher as you all can touch something that is HIGHLY coupled to the rest of the project.
  5. If you are using Kotlin you can’t benefit of modifiers like internal, protected, etc. They are mostly used for hide classes that the modules that implement it doesn’t need to access.

And the list can keep growing and growing, but I think you already understood where I want to go. How can we solve all the problems listed before and even improve our code quality 🧐?

Modularization 🧩

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.

Wikipedia

You can think of modularization like turn some of your packages into small reusable pieces of code across your application.

The modules you are going to create can be android libraries, pure kotlin/java libraries, more app modules, wearable modules, auto modules etc.

Let me show an example of a monolithic and a modularized project (BTW IMHO the monolithic one is very well organized and it’s highly probably to be modularized easily).

Monolithic project on the left, modularized project on the right.

Aren’t they se same 🤔?… Kind off. The differences between them is that the modularized project have no longer the problems we listed above. And even better, it earn some things:

  1. Faster build times, because if there is a change in some module. Only that module will be compiled again. (Also, the modules that implement this module, but the benefit is still there).
  2. Each module now implements ONLY the libraries it uses. Nothing more, nothing less, just what the module need.
  3. You can configure your gradle for cache builds, do parallelism & more!
  4. You can create experimental app modules, and test any new library here before you put it in your real app module.
  5. You can publish some of your libraries and receive contribution of the community. Real case sample? Timber

I copy this class into all the little apps I make. I’m tired of doing it. Now it’s a library.
Jake Wharton

Even the official docs say that you should modularize your project.

How can I start to modularize my project 🪂?

Before we get there, you need to know that there is no only ONE way to modularize your projects. I would say that there are thousand of ways to modularize any project, it just depends.

The most common way of modularization you can find is modularization by clean architecture layer, where you only have:

  1. data— Android library module
  2. domain — Pure Java/Kotlin module
  3. presentation — App Module

I started to modularize my projects following that approach, but after a while I realized that it wasn’t enough… I felt something was missing, somehow that kind of modularization can be even better.

That was my breaking point 🤯, and I started to investigate more & more about modularization and I realize that there is no only ONE way to modularize your project, you have thousands of approaches around there, and is up to you to take the best practices and try it till you have a solid, maintainable, testable, scalable code.

You must remember the goal of modularization

Small reusable self contained pieces of code

My advice for you is to start with the things that have less dependencies on. Probably extracting your networking classes, or some utilities, etc. Once you start extracting those classes into it’s own modules you will realize your code will be getting cleaner and more modular.

But, as everything in life, it comes with a price. Your are going to face some challenges… but I’m sure you will overcome them 🤜🤛.

Challenges 🌊

  1. Gradle — You’ll need to take care of manage your gradle libraries dependencies & android min max SDK versions. You wont like to manage the versions manually for each module, it can get tricky. One of the best practices is to have a base gradle file and use it around your modules.
  2. Circular Dependencies — You have to be aware that your modules depend on each other on a cyclic way, this advice is mostly for your feature modules. Like the sample i listed at the beginning (FeatureA 🔁 FeatureB). You will have a compile error due to circular dependencies and you won’t be able to build the project.
  3. Styles — This LOOKS like if it’s kinda tricky, but is not. All you have to do is move your design system to one module, and implement that module in all your feature modules & app module.
  4. Navigation — Navigation between features it will become a new thing! now your features doesn’t know each other. There are some tricks for this, you can have an interface across feature modules and its implementation be on the app module (your app module will implement all your feature modules at the end) or you can load your classes by qualified name (my favorite), or rely on libraries like the navigation library, personally I wouldn’t recommend it for now because I believe the navigation library is not designed for modularized projects. Check out this blog where I tell my experience on production apps with it.
  5. DI — Dependency injection. For this part, the library you are using for DI will get a big participation. But the principal idea that works for me no matter what library it is, is the following: for my feature modules I build my DI modules graph inside their library modules and then inject those DI modules to the app graph in the app module. For any other modules like utilities, networking, etc, I’ll probably construct it’s DI modules in the app module.

Final thoughts

Sooner or later you will have to face modularization, and that day my friend will be one of the greatest days for your career.

It is not a quick process, I'm not going to lie to you, It will depend on how many effort you put into it. Once you get into modularization, your mind will change forever, even your monolithic projects can be well organized by following modularization principles.

Don’t surprise if you end up with more than +30 modules. I have worked on projects that have +70 modules, between feature modules, pure Kotlin libraries, app modules and more.

BTW, I made a small playground project that follows all the principles I listed above, play with it, don’t forget to smash the star ⭐ button, and file some issues if you find some, generate a pull request, etc.

If you have any doubts, don’t hesitate to reach me out, I’ll be happy to help you as sooner as I can.

--

--