[MUSIC PLAYING]
MILOSZ MOCZKOWSKI: Hey, everyone.
This is Milosz from the Android Developer Relations team.
In this video, we will discuss three ways
of modularizing your Android application
and see how they compare.
We'll also talk about three properties
that you can use to describe your module or codebase.
Let's go.
There is no single modularzation strategy
that fits all projects.
Due to the flexible nature of Gradle,
there are few constraints as to how you can organize a project.
One way of doing so is to encapsulate
each architectural layer inside a separate module.
The recommended Android architecture
describes three layers--
data layer, UI layer, and optional domain layer.
In a typical Android application,
we could organize the modules as follows.
The data module contains all the repositories and data sources.
The domain module contains business logic and use cases.
The domain module depends on the data module.
The UI module consists of a user interface
and stakeholders, most likely view modules,
composables, or views.
It depends on the data and domain modules.
So how do we know if this is a good strategy or not?
We can use the three properties of a module or a codebase
to measure the quality of module organization.
And those are cohesion, coupling, and granularity.
A module with high cohesion has clearly
defined responsibilities and consists of code
that acts together as a system.
Architectural layers tend to be cohesive by nature.
They all have well-defined responsibilities and act
as a system.
Cohesion test passed.
Another characteristic of a modular code is coupling.
Coupling measures the degree to which
modules depend on each other.
Modules should strive to achieve low coupling,
meaning they should be as independent as possible
from one another so that changes to one module
have zero or minimal impact on other modules.
Let's see how loosely or tightly coupled
is our layered codebase.
Any change to the UI module will be limited
to the UI module itself.
However, changing the public interface of the domain module
might result in recompilation of the UI layer.
Altering the public API of the data module
might lead to recompilation of all the modules.
In a small code base, that might work perfectly fine.
However, if your modules are growing too large,
you might consider increasing the granularity
of your codebase.
Granularity is the extent to which your codebase
is composed of modules.
In other words, it's the codebase module count
over its size.
It's not measured in any concrete unit
but rather serves as a concept.
A more granular codebase has more smaller modules.
If your modules are growing too large,
you might end up with yet another monolith
and miss the benefits that modularity has to offer.
In a small project, it's OK to put the data
layer inside a single module.
But as the project grows and your modules with it,
you might consider splitting some modules into smaller
and more cohesive ones.
Another way of approaching this problem
is modernization by feature.
Imagine a simple e-book application with three
screens--
books, authors, and reviews.
We could encapsulate each of those screens in a module
and call them feature modules.
Each feature module has distinct responsibility,
acts as a system, and can be developed in isolation.
However, if the book screen wants to show authors
and reviews information, that could mean one of two things--
either that the book module has to implement author-
and reviews-related functionality,
which is already part of other modules--
that means redundancy-- or that feature modules
depend on each other.
This, however, makes coupling too tight
and prevents features from being developed in isolation.
Seems like both solutions have their pros and cons.
How about combining them?
By grouping the modules by layer and feature,
we increase the codebase granularity.
Layers are no longer monoliths, but consists
of multiple building blocks.
Just like with separation by layer,
modules can only depend on other modules from a layer below.
UI modules are part of the UI layer
and can only depend on domain and data modules.
The main modules depend on data modules only.
Data modules do not have access to any modules
in the upper architecture layers.
This ensures that modules are cohesive
because each one is highly specialized and independent.
Modules are loosely coupled so codebase can scale.
Modules are granular, so they can easily be reused.
I hope this video lightened up some modularization
concepts for you.
If you're hungry for more, be sure to check out
the official "Guide to Android app modularzation"
and the Now in Android project.
Cheers.
[MUSIC PLAYING]