# Modularization learning journey
In this learning journey you will learn about modularization, and the modularization strategy used
to create the modules in the Now in Android app.
## Overview
Modularization is the practice of breaking the concept of a monolithic, one-module codebase into
loosely coupled, self contained modules.
### Benefits of modularization
This offers many benefits, including:
**Scalability** - In a tightly coupled codebase, a single change can trigger a cascade of
alterations. A properly modularized project will embrace
the [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) principle. This
in turn empowers the contributors with more autonomy while also enforcing architectural patterns.
**Enabling work in parallel** - Modularization helps decrease version control conflicts and enables
more efficient work in parallel for developers in larger teams.
**Ownership** - A module can have a dedicated owner who is responsible for maintaining the code and
tests, fixing bugs, and reviewing changes.
**Encapsulation** - Isolated code is easier to read, understand, test and maintain.
**Reduced build time** - Leveraging Gradle’s parallel and incremental build can reduce build times.
**Dynamic delivery** - Modularization is a requirement
for [Play Feature Delivery](https://developer.android.com/guide/playcore/feature-delivery) which
allows certain features of your app to be delivered conditionally or downloaded on demand.
**Reusability** - Proper modularization enables opportunities for code sharing and building multiple
apps, across different platforms, from the same foundation.
### Modularization pitfalls
However, modularization is a pattern that can be misused, and there are some gotchas to be aware of
when modularizing an app:
**Too many modules** - each module has an overhead that comes in the form of increased complexity of
the build configuration. This can cause Gradle sync times to increase, and incurs an ongoing
maintenance cost. In addition, adding more modules increases the complexity of the project’s Gradle
setup, when compared to a single monolithic module. This can be mitigated by making use of
convention plugins, to extract reusable and composable build configuration into type-safe Kotlin
code. In the Now in Android app, these convention plugins can be found in
the [`build-logic` folder](https://github.com/android/nowinandroid/tree/main/build-logic).
**Not enough modules** - conversely if your modules are few, large and tightly coupled, you end up
with yet another monolith. This means you lose some benefits of modularization. If your module is
bloated and has no single, well defined purpose, you should consider splitting it.
**Too complex** - there is no silver bullet here. In fact it doesn’t always make sense to modularize
your project. A dominating factor is the size and relative complexity of the codebase. If your
project is not expected to grow beyond a certain threshold, the scalability and build time gains
won’t apply.
## Modularization strategy
It’s important to note that there is no single modularization strategy that fits all projects.
However, there are general guidelines that can be followed to ensure you maximize its benefits and
minimize its downsides.
A barebone module is simply a directory with a Gradle build script inside. Usually though, a module
will consist of one or more source sets and possibly a collection of resources or assets. Modules
can be built and tested independently. Due to Gradle's flexibility there are few constraints as to
how you can organize your project. In general, you should strive for low coupling and high cohesion.
* **Low coupling** - Modules should be as independent as possible from one another, so that changes
to one module have zero or minimal impact on other modules. They should not possess knowledge of
the inner workings of other modules.
* **High cohesion** - A module should comprise a collection of code that acts as a system. It should
have clearly defined responsibilities and stay within boundaries of certain domain knowledge. For
example,
the [`core:network` module](https://github.com/android/nowinandroid/tree/main/core/network) in Now
in Android is responsible for making network requests, handling responses from a remote data
source, and supplying data to other modules.
## Types of modules in Now in Android
```mermaid
graph TB
subgraph :core
direction TB
:core:data[data]:::android-library
:core:database[database]:::android-library
:core:model[model]:::jvm-library
:core:network[network]:::android-library
:core:ui[ui]:::android-library
end
subgraph :feature
direction TB
:feature:topic[topic]:::android-feature
:feature:foryou[foryou]:::android-feature
:feature:interests[interests]:::android-feature
:feature:foo[...]:::android-feature
end
:app[app]:::android-application
:app -.-> :feature:foryou
:app -.-> :feature:interests
:app -.-> :feature:topic
:core:data ---> :core:database
:core:data ---> :core:network
:core:database ---> :core:model
:core:network ---> :core:model
:core:ui ---> :core:model
:feature:topic -.-> :core:data
:feature:topic -.-> :core:ui
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
```
📋 Graph legend
```mermaid
graph TB
application:::android-application -. implementation .-> feature:::android-feature
library:::android-library -- api --> jvm:::jvm-library
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
```
| Name | Responsibilities | Key classes and good examples |
app
|
Brings everything together required for the app to function correctly. This includes UI scaffolding and navigation. | NiaApp, MainActivityApp-level controlled navigation via NiaNavHost, NiaAppState, TopLevelDestination
|
feature:1,feature:2... |
Functionality associated with a specific feature or user journey. Typically contains UI components and ViewModels which read data from other modules. Examples include:
|
TopicScreenTopicViewModel
|
core:data
|
Fetching app data from multiple sources, shared by different features. | TopicsRepository |
core:designsystem
|
Design system which includes Core UI components (many of which are customized Material 3 components), app theme and icons. The design system can be viewed by running the app-nia-catalog run configuration.
|
NiaIcons NiaButton NiaTheme
|
core:ui
|
Composite UI components and resources used by feature modules, such as the news feed. Unlike the designsystem module, it is dependent on the data layer since it renders models, like news resources.
|
NewsFeed NewsResourceCardExpanded
|
core:common
|
Common classes shared between modules. | NiaDispatchersResult
|
core:network
|
Making network requests and handling responses from a remote data source. | RetrofitNiaNetworkApi
|
core:testing
|
Testing dependencies, repositories and util classes. | NiaTestRunnerTestDispatcherRule
|
core:datastore
|
Storing persistent data using DataStore. | NiaPreferencesUserPreferencesSerializer
|
core:database
|
Local database storage using Room. | NiaDatabaseDatabaseMigrationsDao classes
|
core:model
|
Model classes used throughout the app. | TopicEpisodeNewsResource
|