From 40df54d50f556d719578ee845583b1348b1538e5 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:25:12 +0000 Subject: [PATCH 1/8] Refactor: Simplify modularization docs Removes the general theory of modularization and links to the official guidance instead. Clarifies the structure of feature modules, detailing the split into `api` and `impl` submodules and their dependency rules. Also includes minor heading and formatting updates. --- docs/ModularizationLearningJourney.md | 118 +++++--------------------- 1 file changed, 20 insertions(+), 98 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 5cda61b69..73646acef 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -1,87 +1,8 @@ # 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. - +In this learning journey you will learn about the modularization strategy used +to create modules in the Now in Android app. For the theory behind modularization, check out +[the official guidance](https://developer.android.com/topic/modularization) ## Types of modules in Now in Android @@ -95,7 +16,7 @@ graph TB :core:network[network]:::android-library :core:ui[ui]:::android-library end - subgraph :feature + subgraph :feature direction TB :feature:topic[topic]:::android-feature :feature:foryou[foryou]:::android-feature @@ -142,26 +63,27 @@ visualizing dependencies between modules. The Now in Android app contains the following types of modules: -* The `app` module - contains app level and scaffolding classes that bind the rest of the codebase, - such as `MainActivity`, `NiaApp` and app-level controlled navigation. A good example of this is - the navigation setup through `NiaNavHost` and the bottom navigation bar setup - through `TopLevelDestination`. The `app` module depends on all `feature` modules and - required `core` modules. +### The `app` module +This contains app level and scaffolding classes that bind the rest of the codebase, such as +`MainActivity`, `NiaApp` and app-level controlled navigation. A good example of this is the navigation setup through `NiaNavHost` and the bottom navigation bar setup through `TopLevelDestination`. The `app` module depends on all `feature` modules and required `core` modules. + +### Feature modules +These are feature-specific modules that handle a single responsibility in the app. For example, the `ForYou` feature handles all content and UI state for the "ForYou" screen. Feature modules aren't gradle modules themselves, they are split into two submodules: -* `feature:` modules - feature specific modules which are scoped to handle a single responsibility - in the app. These modules can be reused by any app, including test or other flavoured apps, when - needed, while still keeping it separated and isolated. If a class is needed only by one `feature` - module, it should remain within that module. If not, it should be extracted into an - appropriate `core` module. A `feature` module should have no dependencies on other feature - modules. They only depend on the `core` modules that they require. +* `api` - contains navigation keys +* `impl` - contains everything else -* `core:` modules - common library modules containing auxiliary code and specific dependencies that +This approach allows features to navigate to other features by using the target feature's navigation keys. A feature's `api` and `impl` modules can be used by any app, including test or other flavoured apps. If a class is needed only by one feature module, it should remain within that module. If not, it should be placed into an appropriate `core` module. + +A feature's `api` module should not depend on another feature's `api` or `impl` module. A feature's `impl` should only depend on another featur's `api` module. Both submodules should only depend on the `core` modules that they require. + +### `core:` modules +These are common library modules containing auxiliary code and specific dependencies that need to be shared between other modules in the app. These modules can depend on other core modules, but they shouldn’t depend on feature nor app modules. -* Miscellaneous modules - such as `sync`, `benchmark` and `test` modules, as well - as `app-nia-catalog` - a catalog app for displaying our design system quickly. - +### Miscellaneous modules +For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog` - a catalog app for displaying our design system quickly. ## Modules From 46ca201ab36c3371431b00984268b62f2180e748 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:32:07 +0000 Subject: [PATCH 2/8] docs: Add details about feature API modules Expands on the role of feature `:api` modules in the modularization learning journey documentation. Clarifies that `:api` modules expose navigation keys and functions for inter-feature navigation. Also adds a new `impl` row for the implementation details. --- docs/ModularizationLearningJourney.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 73646acef..8f47adf36 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -108,8 +108,22 @@ Using the above modularization strategy, the Now in Android app has the followin - feature:1,
- feature:2
+ feature1:api,
+ feature2:api
+ ... + + Navigation keys and functions that other features can use to navigate to this feature.
+ For example: The `:topic:api` module exposes a `Navigator.navigateToTopic` function that the + `:interests:impl` module uses to navigate from the `InterestsScreen` to the `TopicScreen` when + a topic is clicked. + + TopicScreen
+ TopicViewModel + + + + feature:1:impl,
+ feature:2:impl
... Functionality associated with a specific feature or user journey. Typically contains UI components and ViewModels which read data from other modules.
From 14b463c5a2583834f415f987226d383e47126c0f Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:33:50 +0000 Subject: [PATCH 3/8] Fix: Render code blocks in markdown The `` HTML tag is used to properly render code snippets within the `ModularizationLearningJourney.md` documentation file. This improves the readability of the examples provided in the table. --- docs/ModularizationLearningJourney.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 8f47adf36..155b2ee0a 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -113,8 +113,8 @@ Using the above modularization strategy, the Now in Android app has the followin ... Navigation keys and functions that other features can use to navigate to this feature.
- For example: The `:topic:api` module exposes a `Navigator.navigateToTopic` function that the - `:interests:impl` module uses to navigate from the `InterestsScreen` to the `TopicScreen` when + For example: The :topic:api module exposes a Navigator.navigateToTopic function that the + :interests:impl module uses to navigate from the InterestsScreen to the TopicScreen when a topic is clicked. TopicScreen
From 9d58c9a36aa745beb8f26771cb4ecd7cee46e4ea Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:34:22 +0000 Subject: [PATCH 4/8] Fix: Correct heading for core modules This commit corrects a typo in the heading for the "Core modules" section in the documentation. --- docs/ModularizationLearningJourney.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 155b2ee0a..09e0100d2 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -77,7 +77,7 @@ This approach allows features to navigate to other features by using the target A feature's `api` module should not depend on another feature's `api` or `impl` module. A feature's `impl` should only depend on another featur's `api` module. Both submodules should only depend on the `core` modules that they require. -### `core:` modules +### Core modules These are common library modules containing auxiliary code and specific dependencies that need to be shared between other modules in the app. These modules can depend on other core modules, but they shouldn’t depend on feature nor app modules. From ed01cfdbde087b26697a0f2699beec62f8fb9758 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:36:25 +0000 Subject: [PATCH 5/8] Fix: Correct heading for core modules This commit corrects a typo in the heading for the "Core modules" section in the documentation. --- docs/ModularizationLearningJourney.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 09e0100d2..f12d801ad 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -85,9 +85,7 @@ These are common library modules containing auxiliary code and specific dependen ### Miscellaneous modules For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog` - a catalog app for displaying our design system quickly. -## Modules - -Using the above modularization strategy, the Now in Android app has the following modules: +## Module examples @@ -117,8 +115,7 @@ Using the above modularization strategy, the Now in Android app has the followin :interests:impl module uses to navigate from the InterestsScreen to the TopicScreen when a topic is clicked. - From d201c76196a65123125ef55a28b678814ba71783 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:36:56 +0000 Subject: [PATCH 6/8] Fix typo in ModularizationLearningJourney.md --- docs/ModularizationLearningJourney.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index f12d801ad..b04f3e2e5 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -119,8 +119,8 @@ For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog - - - -
TopicScreen
- TopicViewModel +
TopicNavKey
feature:1:impl,
- feature:2:impl
+
feature1:impl,
+ feature2:impl
...
Functionality associated with a specific feature or user journey. Typically contains UI components and ViewModels which read data from other modules.
From c4e31880a9421ee027d33fcd84dbddfd6730e6ec Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:44:44 +0000 Subject: [PATCH 7/8] docs: Update ModularizationLearningJourney.md Updates the modularization documentation with the following changes: - Adds an important note about dependency graphs in module READMEs. - Renames several section headers for clarity (e.g., "Types of modules" to "Module types"). - Moves the section on dependency graphs to be after the examples table. --- docs/ModularizationLearningJourney.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index b04f3e2e5..3485a0669 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -2,9 +2,11 @@ In this learning journey you will learn about the modularization strategy used to create modules in the Now in Android app. For the theory behind modularization, check out -[the official guidance](https://developer.android.com/topic/modularization) +[the official guidance](https://developer.android.com/topic/modularization). -## Types of modules in Now in Android +**IMPORTANT:** Every module has a dependency graph in its README ([example for the app module](https://github.com/android/nowinandroid/tree/main/app)) which can be useful for understanding the overall structure of the project. + +## Module types ```mermaid graph TB @@ -85,7 +87,7 @@ These are common library modules containing auxiliary code and specific dependen ### Miscellaneous modules For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog` - a catalog app for displaying our design system quickly. -## Module examples +## Examples @@ -216,11 +218,12 @@ For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog
+## Dependency graphs Each module has its own `README.md` file containing a module graph (e.g. [`:app` module graph](../app/README.md#module-dependency-graph)). When modules dependencies change, module graphs are automatically updated by the [Build.yaml](../.github/workflows/Build.yaml) workflow. You can also manually update the graphs by running the `graphUpdate` task. -## Modularization in Now in Android +## Further considerations Our modularization approach was defined taking into account the “Now in Android” project roadmap, upcoming work and new features. Additionally, our aim this time around was to find the right balance between overmodularizing a relatively small app and using this opportunity to showcase a modularization pattern fit for a much larger codebase, closer to real world apps in production environments. From a1516b2f7e0d4c0e3db54086765c489191c9ad5f Mon Sep 17 00:00:00 2001 From: Don Turner Date: Wed, 3 Dec 2025 22:47:12 +0000 Subject: [PATCH 8/8] Fix feature module names in documentation --- docs/ModularizationLearningJourney.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/ModularizationLearningJourney.md b/docs/ModularizationLearningJourney.md index 3485a0669..179ec1bec 100644 --- a/docs/ModularizationLearningJourney.md +++ b/docs/ModularizationLearningJourney.md @@ -108,11 +108,11 @@ For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog
feature1:api,
- feature2:api
+
feature:1:api,
+ feature:2:api
...
Navigation keys and functions that other features can use to navigate to this feature.
+
Navigation keys and functions that other features can use to navigate to this feature.

For example: The :topic:api module exposes a Navigator.navigateToTopic function that the :interests:impl module uses to navigate from the InterestsScreen to the TopicScreen when a topic is clicked. @@ -121,15 +121,15 @@ For example, `sync`, `benchmark` and `test` modules, as well as `app-nia-catalog
feature1:impl,
- feature2:impl
+
feature:1:impl,
+ feature:2:impl
...
Functionality associated with a specific feature or user journey. Typically contains UI components and ViewModels which read data from other modules.
Examples include:
    -
  • feature:topic displays information about a topic on the TopicScreen.
  • -
  • feature:foryou which displays the user's news feed, and onboarding during first run, on the For You screen.
  • +
  • feature:topic:impl displays information about a topic on the TopicScreen.
  • +
  • feature:foryou:impl which displays the user's news feed, and onboarding during first run, on the For You screen.
TopicScreen