Mobile Development 24 min read

Mastering Android Module Design: Cohesion, Coupling, and Component Principles

This article explains how to organize Android Gradle modules using component design principles—covering cohesion, coupling, module splitting, encapsulation, and integration—while relating them to SOLID and providing concrete examples, formulas, and best‑practice guidelines.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Mastering Android Module Design: Cohesion, Coupling, and Component Principles

Component Design Principles Overview

In Android a component corresponds to a Gradle module that groups business‑related files. Proper modularisation aims for high cohesion (related code stays together) and low coupling (modules depend only on stable abstractions).

1. Cohesion Principles

Common Closure Principle (CCP)

Classes that change for the same reason should be placed in the same module. A module therefore has a single reason to change, mirroring the SRP at the module level.

Common Reuse Principle (CRP)

Classes that are reused together belong to the same module, while unrelated classes must not be forced into the same module. This reduces unnecessary recompilation and aligns with the ISP for modules.

Reuse/Release Equivalency Principle (REP)

The granularity of reuse should match the granularity of release. When a module is published as a binary library, its version should be managed as a single unit. Using a Bill of Materials (BOM) simplifies version alignment, e.g.:

implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-moshi:2.9.0"

Gradle’s BOM support allows adding dependencies without specifying versions explicitly.

2. Coupling Principles

Acyclic Dependencies Principle (ADP)

Modules must not form dependency cycles. Gradle detects cycles at compile time. Typical resolutions are:

Extract a new common module to break the cycle.

Apply the Dependency Inversion Principle (depend on abstractions instead of concrete modules).

Stable Dependencies Principle (SDP)

Dependencies should point from unstable to stable modules. Stability is measured by Instability : I = fanOut / (fanIn + fanOut) Fan‑in : number of modules that depend on this module (higher → more responsibility).

Fan‑out : number of modules this module depends on (higher → less independent).

Lower I indicates a more stable module.

Stable Abstractions Principle (SAP)

Stable modules should be more abstract. Abstractness A is calculated as:

A = Na / Nc
Nc

: total classes in the module. Na: number of abstract classes or interfaces.

Balancing I and A yields three zones:

Zone of Pain : high stability, low abstractness – hard to change and extend.

Zone of Useless : high instability, high abstractness – rarely used.

Main Sequence : ideal balance where A + I ≈ 1.

3. Module Splitting Strategies

Layer‑based Splitting

Divides the codebase into presentation, domain, and data layers. Easy to adopt but often violates cohesion and coupling because a single feature may span all layers, leading to large monolithic modules.

Feature‑based Splitting

Creates a separate module for each feature. Advantages:

Isolated changes and clear project purpose.

Independent team ownership.

Parallel Gradle compilation reduces build time.

Drawbacks include reduced reusability and potential violations of SDP/SAP, which can lead to large feature modules.

Domain‑based (Component) Splitting

Separates UI modules from domain‑data component modules. Shared code (e.g., networking utilities) lives in a shared directory.

interface PDPNavigator {
    // adapt for fragments, Navigation Component, Compose, etc.
    fun navigateToCart(activity: Activity)
    fun navigateToWishlist(activity: Activity)
}

The app module implements these interfaces, providing navigation glue:

class AppNavigator : PDPNavigator, WishlistNavigator, CartNavigator {
    override fun navigateToCart(activity: Activity) { /* ... */ }
    override fun navigateToWishlist(activity: Activity) { /* ... */ }
}

4. Encapsulation of Modules

Expose only the API needed by other modules as public; keep the rest internal. Prefer Gradle implementation over api to avoid leaking transitive dependencies.

For Dagger modules, mark them internal because they are used only for code generation within the same module.

// Dagger module for a Wishlist Component
@Module
@InstallIn(SingletonComponent::class)
internal object WishlistComponentModule {
    @Provides
    fun provideAddToWishlistUseCase(impl: AddToWishlistUseCaseImpl): AddToWishlistUseCase = impl
    // ... other providers
}

// Dagger module for a Wishlist UI module
@Module
@InstallIn(ActivityComponent::class)
internal object WishlistUIModule {
    @Provides
    fun provideSomeDependency(impl: SomeDependencyImpl): SomeDependency = impl
    // ... other providers
}

5. Integration Layer

The app module acts as the integration layer. It contains:

Glue code that connects feature modules.

Framework initialization (e.g., Dagger, logging).

Navigation logic between UI modules.

Provision of common dependencies such as database or network clients.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidClean Architecturemodular architectureCouplingCohesionComponent PrinciplesGradle Modules
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.