You should modularize your Kotlin Android app, since it's the best way to enforce separation of concerns, but how do you know if you're doing it right? Here's some tips to help.
Am I doing it right?
If you're following one of the great guides out there, you're probably doing it mostly right, but how do you know? Can you measure a difference? Here's a good way to check. Generate a dependency graph for your app. I used APK Dependency Graph Generator. All you need to do is compile the apk-dependency project, point it to an apk, and it will generate an interactive graph like the one below.
Click here to see PositiviTea's dependency graph It's interactive and fun.
This graph demonstrates a way to look for ease of refactoring with two nice examples:
ServerClientin the bottom right provides a complete separation between the api and the rest of the app. The api calls can therefore be refactored easily.
- Lots of classes are reliant on the
TeaBagclass in the middle. A single change there is likely to cascade outward, making refactoring difficult.
Below, an example of a project which is not easy to refactor, update or even debug:
There is no separation of concerns here. This project is in dire need of modularization, but where do you even begin?
Where to begin?
I usually follow these steps:
- Create a module
- Identify one or more classes that should not be accessible outside of a specific context
- Move those classes into the module
- Add the
internalvisibility modifier (or making the class
package-privateif you're using Java)
- Try to compile and get an error
- Fix this error without removing the
internalkeyword. This may involve creating a little bit of boilerplate.
A specific example of this would be the database module. I moved my
data model classes,
DAO classes, and
repository class into the database module. I made everything
internal except for
repository, which provides the API to the database for the rest of the app. After some restructuring and cleanup, I ended up with a nicer class structure.
Okay, I have to admit, it doesn't seem like we made that much of a difference. But here's the real benefit:
The real benefit
When a new developer works in a non-database module and tries to access the database directly, the compiler will stop them.
The two dependency graphs are similar, except that a moment's thoughtlessness can pull everything into spaghetti in the first instance. I have used the
internal modifier in my database module, which means that a developer would be stopped from breaking a delicate separation of concerns with a single function.
If you run into these errors in a project, you know the project is well modularized.
We have looked at two ways in which to analyze the state of your modularization:
- APK Dependency Graph Generator; and
- The prevalance of the
internalmodifier (or lack of