Engineering guide

Material 3 App Engineering & Workflow

Learn how to structure, modularize, configure, test, optimize, and build production applications using Material Design 3.

Modular architecture

Clear boundaries across the application stack

App module (:app)

Application lifecycle startup, dependency injection root, global navigation graph, and activity shell.

Design system (:core:designsystem)

Centralized MaterialTheme, dynamic color schemes, typography scale, shape tokens, and expressive springs.

Data & domain (:core:data)

Data repositories, local persistence (DataStore, Room), network clients, and domain models.

Feature modules (:feature:*)

Independent feature screens, ViewModels, and UI state models isolated from other features.

Build setup

Version catalogs and convention plugins

Centralize build logic in a build-logic composite build to maintain consistent compile SDK, Java targets, and Compose compiler versions across all submodules.

Version catalog

Define all dependencies in gradle/libs.versions.toml to ensure uniform version alignment.

Application plugin

Applies Android application conventions, packaging rules, and release build type settings.

Library plugin

Applies shared library SDK configurations, Java 11 compatibility, and namespace standards.

Compose convention

Enables Compose compiler plugins and binds UI / Material 3 dependencies.

State and runtime

Unidirectional data flow and lifecycle safety

  1. 1

    Model immutable UI state

    Represent screen states as strongly typed Kotlin data classes.

  2. 2

    Expose StateFlow

    ViewModels process user intents and emit new state snapshots via StateFlow.

  3. 3

    Lifecycle-aware collection

    Composables observe state using collectAsStateWithLifecycle() to avoid background resource leaks.

  4. 4

    State-hoisted components

    Leaf UI composables remain stateless, receiving plain values and emitting event callbacks.

Optimization & Release

R8 optimization, resource shrinking, and signing

Enable Android Gradle Plugin optimization and R8 shrinking for release builds:

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

Keep keystore and signing credentials in local, git-ignored signing.properties.

Verification

Automated testing and lint gates

# Run build logic tests
.\gradlew.bat -p build-logic :convention:test

# Run unit tests across all modules
.\gradlew.bat testDebugUnitTest

# Run Android Lint
.\gradlew.bat lintDebug

# Assemble debug and release builds
.\gradlew.bat :app:assembleDebug
.\gradlew.bat :app:assembleRelease