Modularization provides:
- Faster compilation - Only changed modules need to be rebuilt
- Better separation of concerns - Modules enforce architectural boundaries
- Parallel development - Teams can work on different modules independently
- Code reusability - Modules can be shared across platforms (Kotlin Multiplatform)
Module Types
The project defines four distinct types of modules:Library Modules
Reusable utilities that provide infrastructure services like caching, networking, and testing helpers.Examples:
cache, httpclient, foundations, viewmodelCharacteristics:- No business logic
- Highly reusable
- Often Kotlin Multiplatform
- Minimal dependencies
Component Modules
Feature-specific modules containing domain and data layers for a business capability.Examples:
cart-component, product-component, user-component, wishlist-componentCharacteristics:- Pure Kotlin or Kotlin Multiplatform
- Framework-independent
- Fast compilation (no Android dependencies)
- Contain domain models, repositories, and use cases
UI Modules
Feature-specific modules containing the presentation layer for a screen or UI component.Examples:
cart-ui, plp-ui, wishlist-ui, onboarding-uiCharacteristics:- Android-specific (uses Compose)
- Depends on corresponding component module
- Contains ViewModels and Composables
- Can aggregate multiple components
Module Structure
Here’s the complete module structure as defined insettings.gradle.kts:
settings.gradle.kts
Library Modules
Library modules provide reusable infrastructure:cache
Key-value storage abstraction with Flow-based reactive updatesDependencies: Kotlin Multiplatform, Coroutines, SerializationUsed by: All component modules that need persistence
httpclient
HTTP client abstraction for network requestsDependencies: KtorUsed by: Component modules that fetch remote data
foundations
Core utilities and language extensionsExample:
Answer<T, E> type for error handlingDependencies: None (pure Kotlin)viewmodel
ViewModel utilities without tight framework couplingUsed by: All UI modules
designsystem
Reusable UI components and themeDependencies: Jetpack ComposeUsed by: All UI modules
cache-test
Test doubles for cache moduleUsed by: Component module tests
flow-test-observer
Utilities for testing Flow emissionsUsed by: All tests that work with Flows
coroutines-test-dispatcher
JUnit rules for coroutine testingUsed by: All tests using coroutines
Example: Cache Library Module
cache/build.gradle.kts
Library modules are Kotlin Multiplatform, supporting JVM, iOS (x64, arm64, simulator). This enables code sharing and faster compilation.
Component Modules
Component modules encapsulate business features with domain and data layers:Cart Component
Structure:cart-component/build.gradle.kts
Component Assembler Pattern
Each component exposes its use cases through an assembler:cart-component/src/commonMain/kotlin/com/denisbrandi/androidrealca/cart/di/CartComponentAssembler.kt
Assemblers:
- Encapsulate component wiring
- Expose only use case interfaces (not implementations)
- Use lazy initialization for efficiency
- Apply Dependency Inversion Principle
UI Modules
UI modules contain presentation logic and Compose screens:Cart UI Module
Dependencies:cart-ui/build.gradle.kts
App Module
The app module orchestrates the entire application: Dependencies:- All UI modules
- All component modules (for assemblers)
- Library modules for infrastructure
Composition Root
Wires up all dependencies and creates assemblers
Navigation
Manages navigation between screens
Module Dependency Graph
Here’s how modules depend on each other (library modules omitted for clarity):
Horizontal Dependencies
Horizontal Dependencies
Component modules can depend on other component modules:
cart-component→user-component,money-componentwishlist-component→user-component,money-componentproduct-component→money-component
Vertical Dependencies
Vertical Dependencies
UI modules depend on component modules:
cart-ui→cart-component,money-componentplp-ui→product-component,wishlist-component,cart-component
No Circular Dependencies
No Circular Dependencies
The dependency graph is acyclic. Component modules never depend on UI modules, and the app module sits at the top.
Benefits of Modularization
Faster Build Times
Component modules compile much faster than Android modules because they don’t depend on the Android framework.Example:
cart-component compiles ~3-5x faster than cart-uiGradle can also build independent modules in parallel.Enforced Boundaries
Module dependencies enforce architectural rules at compile time.Example: You can’t accidentally use an Android class in a component module - it won’t compile.
Code Reusability
Component modules are Kotlin Multiplatform, enabling iOS, desktop, or backend reuse.Example: The
cart-component can be used in an iOS app without modification.Independent Testing
Each module can be tested in isolation with focused test suites.Example: Test
cart-component with pure unit tests (no Android dependencies).Parallel Development
Teams can work on different modules without conflicts.Example: One team works on
cart-ui while another works on product-component.Module Naming Convention
Pattern:
[feature]-[type]- feature: cart, product, user, wishlist
- type: component (domain + data), ui (presentation), or omitted for libraries
cart-component- Cart feature’s domain and data layerscart-ui- Cart feature’s presentation layercache- Library module (no type suffix)
When to Create a New Module
Create a new module when:New Feature
Adding a significant business capabilityExample: Adding checkout functionality →
checkout-component + checkout-uiShared Logic
Multiple features need the same infrastructureExample: Analytics needed across features →
analytics library modulePlatform Sharing
Business logic should work across platformsExample: Shared business rules → component module with Kotlin Multiplatform
Build Performance
A module is becoming too large and slowing buildsExample: Split a large feature into sub-features
Summary
The modularization strategy:- Library modules provide reusable infrastructure
- Component modules encapsulate features with domain + data layers (Kotlin Multiplatform)
- UI modules handle presentation with Android/Compose
- App module orchestrates everything with navigation and DI
- Clean architectural boundaries
- Fast build times
- Platform independence for business logic
- Clear dependency flow
- Easy testing and maintenance
Next Steps
Component Examples
Explore complete component implementations
App Module
Learn how the composition root wires modules together
Testing Strategy
See how modules enable focused testing
Library Modules
Understand module build configurations
Dependency Injection
Learn how the composition root wires modules together
Testing Strategy
See how modules enable focused testing
Library Modules
Explore shared library modules