Skip to main content

Modularizing your Android app, breaking the monolith (Part 1)


Inspired by a Martin Fowlers post about Micro Frontends, I decided to break my monolithic app into a modular app. I tried to read a little more about breaking monolithic apps in Android, and as far as I got, I felt confident to share my experience with you. This will be some series of blog posts where we actually try to break a simple app into a modularized Android app.

Note: You should know that I am no expert in this, so if there are false statements or mistakes please feel free to criticize, for the sake of a better development. 

What do you benefit from this approach:
  • Well, people are moving pretty fast nowadays and delivery is required faster and faster. So, in order to achieve this, modularising Android apps is really necessary.
  • You can share features across different apps.
  •  Independent teams and less problems per each.
  • Conditional features update.
  • Quicker debugging and fixing.
  • A feature delay doesn't delay the whole app.
As per writing tests, there is not too much difference about being in a monolith or having a modularized Android app. So we will skip tests on this series. Just make sure that each test stands in the right module which corresponds to the chosen feature.
 Now, there is a small benefit if you are thinking Android specifically:
  • Significantly reduces APK size. Which means more installs (according to some 🌚)

 A small introduction:
The app actually is pretty simple. Is built with Architecture Components and has only one Activity. Each fragment has some dependencies but they are Singletons, like database reference, or Picasso and the Retrofit API interface.

So basically, this is my application schema:


All my fragments are pulling dependencies from my Application level. Except from one of them. That fragment is totally unrelated to the other part of the app. It just shows some hardcoded values in the RecyclerView. That really looks like a nice way to start.

Note: I also have an AlarmManager and 2 WorkManagers both pulling dependencies from the application layer, which will be covered later.

But first things first, let's set up gradle for a multi module project. What I mean is that there is no need to reimplement dependencies over and over again when I add a new Android module for some new feature. Instead, we can just put all of our external libraries and dependencies inside the project level gradle and let all the other modules gradle inherit from it. That would bring better management when library updates occur. A smart thing I found in this YouTube video:

This would keep all your build.gradle files super clean. Now you don't have to require a new dependency and manage the updates because you deal with it only once. And this is how you call them after:



Note: You must apply plugin : 'kotlin-kapt' when creating a new module.

Basically, this is all what my new module needs. And now let's break something.

Create a new Android Module and just move all your new features classes over there. Don't forget layouts, strings, dimens, drawable and all resources that are unrelated to other fragments. Get them too. For the current case, there will be no errors because I inherit nothing from any of my app components.

All I have to do now, is just apply this feature to my app/build.gradle level.

Note: The nav graph should break because moving fragment outside the module would bring to unresolved element, but not to worry, we will fix this right now:

Done. The application schema now would look like this:


Now, my feature_6_module is installed as an "external library" to my app module.

Conclusion

This was part 1 of breaking a monolithic app into a modularized app in Android. Next part will be all about Dagger and core dependencies.

Stavro Xhardha

Popular posts from this blog

From Gson to Moshi, what I learned

There is no doubt that people are getting away from GSON and I agree with those reasons too. The only advantage GSON has over other parsing libraries is that it takes a really short amount of time to set up. Furthermore, the most important thing is that Moshi is embracing Kotlin support.

First let's implement the dependency:
implementation("com.squareup.moshi:moshi:1.8.0") It's not a struggle to migrate to Moshi. It's really Gson look-a-like. The only thing to do is annotate the object with @field:Json instead of @SerializedName (which is Gsons way for JS representation):

data class User( //GSON way @SerializedName("name") val name: String, @SerializedName("user_name") val userName: String, @SerializedName("last_name") val lastName: String, @SerializedName("email") val email: String ) data class User( //Moshi way @field:Json(name = "name") val name: String, @field:Json(name = "user_name…

Modularizing your Android app, breaking the monolith (Part 2)

This is part 2 of a series of articles about modularizing Android app. If you haven't yet read the first article, you may find it here.

On our first article we just moved some classes outside the application and applied as an independent module. But what if we have dependencies pulled from the application level? This could be a small challenge. First of all, we want to clarify on how are we going to modularize the app. And depending on the previous article, I chose the by feature version of modularization. First of all, let's show some dependencies that are going to be needed in the whole app.

Note: I'm using Dagger for handling dependencies but manual DI or any dependency tool should be fine to understand this part.

So, this is my dependency schema:


Well, it's not that bad, but this isn't what we want to transform to when trying to modularize the app. If you think about it, modules that don't need a dependency, can get it quite easily. For example: A FeatureXVi…