How I made my legacy app modular - part 2
Tags: android, multi, module, modularization
Published: 2019-09-09 21:06:45

---
title: How I made my legacy app modular - part 2
published: true
description: A modularization walkthrough of a real Android application
tags: android, multi, module, modularization
---
This is part two of https://dev.to/dbottillo/how-i-have-modularized-my-legacy-app---part1-4mde.

In part 1, I've shown how to move from one big module to three:

![Three modules architecture](https://thepracticaldev.s3.amazonaws.com/i/6x351ek6lxae9fgwagot.jpg)

The idea behind these three modules is that we can start to move our codebase in three directions:
* everything that is shared across modules should be moved to `core` (eg. util extensions, app constants)
* everything that is app level configuration should be moved to `app` (eg. dagger configuration, navigation)
* everything that is related to one feature should have its own module as a sibling of legacy:
![Sibling modules architecture](https://thepracticaldev.s3.amazonaws.com/i/y12xxdn9jljjpjeqeklt.jpg)

The reason behind this approach is that we can move code away from `legacy` which will force us to think about the dependencies of `feature`: being a sibling of `legacy` means that we can't access anything inside `legacy` so we have to move those dependencies either to `core` or `app`.

A good example of this approach of creating siblings of `legacy` is the extraction of a small feature on my own project: the about page of the app.
![App about page](https://thepracticaldev.s3.amazonaws.com/i/89plyqgof3x7ngeils98.png)

It's a small screen with few buttons, a title, some texts and a box with the libraries used inside the app; it makes the perfect example of how to extract it considering that it has very few dependencies on `legacy`.

Let's first create the gradle module for the `about` module feature:

```
feature_about/build.gradle
feature_about/src/main/AndroidManifest.xml
feature_about/src/main/kotlin/com/dbottilo/mtgsearchfree/
```

That's it! The last folder will contain all the logic for the module. To make the module "alive" we need to add its definition to the `settings.gradle`:

```
include ':legacy', ':core', ':app'
include ':feature_about'  <- add this
```

So now syncing the project will make the `feature_about` module available in Android Studio. Let's start moving the `AboutActivity` which is inside the `legacy` module:

```
move 
legacy/src/main/kotlin/com/dbottilo/mtgsearchfree/about/AboutActivity.kt
to
feature_about/src/main/kotlin/com/dbottillo/mtgsearchfree/about/AboutActivity.kt

Move also all the drawables that are used from AboutActivity from legacy to feature_about.

eg: move 
/legacy/src/main/res/drawable-hdpi/library_icon.png
to
/feature_about/src/main/res/drawable-hdpi/library_icon.png
```

Right, so `AboutActivity` is now out of `legacy`, exciting! But this is also where the problem starts: what if you have a drawable that is shared with the rest of the application? or a dimension?

There are two options to handle those cases:
* move the shared resources into `core`
* duplicate the resources from `legacy`

I don't think there is a generic solution that works here, it really depends on the specific use case. I would advice to move dimensions like `base_margin` to `core`, whilst I would prefer to duplicate things like specific drawables so that the module has full control over that.

Right, next step is to update the manifest because the `AboutActivity` is not visible anymore in `legacy`: we can move it from the `legacy` manifest to the about module one:

```xml
File: app/src/main/AndroidManifest.xml

<application>
   ...
   <activity android:name=".ui.about.AboutActivity"/> <- remove
   ... 
</application>
File: feature_about/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="com.dbottillo.mtgsearchfree.about"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity android:name=".AboutActivity"/>
    </application>
</manifest>
```

The extraction is completed! Almost…because probably inside the `legacy` module somewhere we must have something like:

```kotlin
startActivity(this, AboutActivity::class.java)
```

but `AboutActivity` is no longer visible in `legacy` module. Here is where the `app` module comes into play, we need to wire the navigation between modules now. The difficulty comes from the fact that the only module that has visibility to all the features is `app` but we need to find a way to call one module from its sibling. My personal solution around navigation is to define an interface in `core` called Navigator:

```kotlin
file: core/src/main/kotlin/com/dbottillo/mtgsearchfree/Navigator.kt

interface Navigator {
    fun openAboutScreen(origin: Activity)
}
```

which is visible from all the `modules` and have the implementation in `app`:

```kotlin
file: app/src/main/kotlin/com/dbottillo/mtgsearchfree/Navigator.kt

class AppNavigator : Navigator {
override fun openAboutScreen(origin: Activity) {
        origin.startActivity(Intent(origin,
                            AboutActivity::class.java))
    }
}
```

And in each module we can inject `Navigator` whose implementation doesn't really matter at feature module level: the important part is that they have a class to request to move between screens, the actual implementation is at runtime from the `app` module.

We are almost there! I just mentioned "inject Navigator", so how do we achieve that? how does Dagger work? It's actually quite simple!

Let's first create a Dagger module in the about module:

```kotlin
file: feature_about/src/main/kotlin/com/dbottillo/mtgsearchfree/dagger/AboutModule.kt

@Module
abstract class AboutModule {
    @ActivityScope
    @ContributesAndroidInjector(modules = [(BasicAboutModule::class)])
    abstract fun contributeAboutActivityInjector(): AboutActivity
}
@Module
class BasicAboutModule
```

We also need to create an `AppModule` Dagger module to provide the navigator dependency:

```kotlin
file:
app/src/main/kotlin/com/dbottillo/mtgsearchfree/dagger/AppModule.kt

@Module
class AppModule {
    @Provides
    @Singleton
    fun provideNavigator(): Navigator {
        return AppNavigator()
    }
}
```

And now we can add both modules to the app component:

```kotlin
@Component(modules = [
    AndroidSupportInjectionModule::class,
    AppModule::class,
    AboutModule::class])
interface AppComponent : AndroidInjector<DaggerApplication> {
}
```
And that's it! Now Dagger knows how to provide dependencies inside the `about` module. Of course this is a very simple example as it doesn't have any API request or database, so the module is very simple but is a good starting point :)

If you want to see the real commit behind this story: https://github.com/dbottillo/MTGCardsInfo/commit/a9a8059838d2886ed02eb61602953fe83a96c460

As for part 1, in the real code `legacy` module is actually called `MTGSearch` and the complexity of that commit is slightly higher than the one described here.

Happy modularisation!