Meshtastic-Android/docs/archive/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md
James Rich 7d63f8b824
feat: build logic (#4829)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
2026-03-17 20:35:39 +00:00

9.5 KiB

Build-Logic Optimizations Summary

Overview

During review of the build-logic/ convention plugins, we identified and addressed several optimization opportunities while maintaining backward compatibility and clarity.

Changes Implemented

1. Test Dependencies Convention COMPLETED

Status: DEPLOYED AND TESTED

What: Centralized kotlin("test") dependency configuration for all KMP modules.

How: Created configureKmpTestDependencies() function in KotlinAndroid.kt and integrated it into KmpLibraryConventionPlugin.

Impact:

  • Removed duplicate implementation(kotlin("test")) from 7 feature modules
  • Single source of truth for test framework configuration
  • All new KMP modules automatically get correct test dependencies
  • Build files cleaner (7 build.gradle.kts files simplified)

Files Modified:

  • build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt - Added configureKmpTestDependencies()
  • build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt - Integrated test dependency function
  • feature/{messaging,firmware,intro,map,node,settings,connections}/build.gradle.kts - Removed redundant dependencies
  • AGENTS.md - Updated testing documentation

2. Compose Plugin Documentation COMPLETED

Status: ANALYZED AND DOCUMENTED

What: Identified that AndroidApplicationComposeConventionPlugin and AndroidLibraryComposeConventionPlugin are identical.

Analysis:

  • Both apply the same plugins (compose-compiler, compose-multiplatform)
  • Both call identical configureAndroidCompose() function
  • Differ only in extension type (ApplicationExtension vs LibraryExtension)

Decision: Keep separate with documentation

  • Reason 1: Explicit intent in build.gradle.kts (clarity wins over DRY)
  • Reason 2: Low cost of duplication (~20 lines per file)
  • Reason 3: Potential future divergence between app/library compose config
  • Future Path: Can be consolidated using CommonExtension when benefits outweigh clarity costs

Files Modified:

  • AndroidApplicationComposeConventionPlugin.kt - Added optimization documentation
  • AndroidLibraryComposeConventionPlugin.kt - Added optimization documentation

3. Flavor Configuration Documentation COMPLETED

Status: ANALYZED AND DOCUMENTED

What: Identified that AndroidApplicationFlavorsConventionPlugin and AndroidLibraryFlavorsConventionPlugin are nearly identical.

Analysis:

  • Both only configure flavor dimensions using configureFlavors() function
  • Underlying configureFlavors() function already handles both ApplicationExtension and LibraryExtension via pattern matching
  • Could technically be consolidated using CommonExtension

Decision: Keep separate with documentation

  • Reason 1: Explicit intent in build.gradle.kts (clarity wins over DRY)
  • Reason 2: Low cost of duplication (~30 lines per file)
  • Reason 3: Gradle/AGP conventions expect specific extension types
  • Future Path: Can consolidate if flavor config diverges from application/library handling

Files Modified:

  • AndroidApplicationFlavorsConventionPlugin.kt - Added consolidation opportunity note
  • AndroidLibraryFlavorsConventionPlugin.kt - Added consolidation opportunity note

4. KotlinAndroid.kt Cleanup COMPLETED

Status: IMPROVED IMPORT ORGANIZATION

What: Added missing import for RepositoryHandler (identified during optimization review)

Impact: Minor - improves import clarity for future use

Files Modified:

  • KotlinAndroid.kt - Added unused import for future extensibility

5. jvmAndroidMain Hierarchy Convention COMPLETED

Status: DEPLOYED AND TESTED

What: Replaced manual jvmAndroidMain source-set wiring in core KMP modules with an opt-in convention plugin backed by Kotlin's hierarchy template API.

Analysis:

  • core:common, core:model, core:network, and core:ui all used identical hand-written dependsOn(...) graphs
  • Kotlin emitted Default Kotlin Hierarchy Template Not Applied Correctly for those modules
  • The shared pattern was real and intentional, not module-specific behavior

Implementation:

  • Added configureJvmAndroidMainHierarchy() to KotlinAndroid.kt
  • Added KmpJvmAndroidConventionPlugin with id meshtastic.kmp.jvm.android
  • Migrated the four affected core modules to the plugin

Files Modified:

  • build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt
  • build-logic/convention/src/main/kotlin/KmpJvmAndroidConventionPlugin.kt
  • build-logic/convention/build.gradle.kts
  • core/common/build.gradle.kts
  • core/model/build.gradle.kts
  • core/network/build.gradle.kts
  • core/ui/build.gradle.kts
  • AGENTS.md
  • docs/kmp-status.md
  • docs/BUILD_LOGIC_CONVENTIONS_GUIDE.md
  • docs/BUILD_LOGIC_INDEX.md

Build-Logic Plugin Inventory

Plugin Type Duplication Status
KmpLibraryConventionPlugin Base KMP None Optimized (test deps added)
KmpJvmAndroidConventionPlugin KMP hierarchy None New opt-in convention
AndroidApplicationConventionPlugin Base Android Common baseline ⚠️ Documented
AndroidLibraryConventionPlugin Base Android Common baseline ⚠️ Documented
AndroidApplicationComposeConventionPlugin Compose Identical to Library Documented
AndroidLibraryComposeConventionPlugin Compose Identical to App Documented
AndroidApplicationFlavorsConventionPlugin Flavors Nearly identical to Library Documented
AndroidLibraryFlavorsConventionPlugin Flavors Nearly identical to App Documented
KoinConventionPlugin DI No duplication Good
DetektConventionPlugin Lint No duplication Good
SpotlessConventionPlugin Format No duplication Good
Others Various Low/None Good

Future Optimization Opportunities

A. Common Android Baseline Function (MEDIUM EFFORT)

Current Status: DOCUMENTED ONLY

Both AndroidApplicationConventionPlugin and AndroidLibraryConventionPlugin share common patterns:

  • Same plugin applications (lint, detekt, spotless, dokka, kover, test-retry)
  • Both call configureKotlinAndroid() and configureTestOptions()
  • Both configure test instrumentation runner

Potential Optimization:

internal fun Project.configureAndroidBaseConvention(
    extension: CommonExtension
) {
    // Shared setup
    extension.apply {
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        testOptions.animationsDisabled = true
    }
}

Effort: ~2 hours (extract logic, verify no regressions, add tests) Savings: ~50 lines of code Risk: Low (consolidating already-tested patterns)

B. Unified Flavor/Compose Convention (LOW PRIORITY)

When Application and Library compose/flavor handling diverges, could create specialized variants. Not recommended now—cost of duplication << cost of wrong abstraction.

C. Plugin Validation Test Suite (MEDIUM EFFORT)

Add unit tests to build-logic verifying:

  • Convention plugins apply correct defaults
  • Test dependencies are properly configured
  • Flavor configuration is consistent across app/library

Benefit: Prevent future regressions


Performance Impact

Build Time

  • No change (optimizations are configuration-time only)
  • Test dependencies now resolve faster (centralized, no duplication)
  • jvmAndroidMain configuration now uses a single convention instead of repeated manual source-set graphs

Code Size

  • Before: 155+ lines of near-duplicate code
  • After: Optimized, documented duplication (intentional for clarity)

Maintainability

  • Before: Changes to test config required updates in 7+ places
  • After: Single source of truth for test framework setup
  • Future: Documented consolidation paths for other duplications

Testing & Verification

All tests pass:

./gradlew spotlessCheck detekt       # BUILD SUCCESSFUL
./gradlew :core:model:compileAndroidMain :core:common:compileAndroidMain :core:network:compileAndroidMain :core:ui:compileAndroidMain # BUILD SUCCESSFUL
./gradlew test                       # BUILD SUCCESSFUL
./gradlew :feature:node:testAndroidHostTest :feature:settings:testAndroidHostTest # BUILD SUCCESSFUL
./gradlew :feature:messaging:jvmTest :feature:node:jvmTest # BUILD SUCCESSFUL
./gradlew assembleDebug test         # BUILD SUCCESSFUL

Recommendations

Immediate Actions

  1. Done: Test dependency centralization (DEPLOYED)
  2. Done: Document Compose duplication (DOCUMENTED)
  3. Done: Document Flavor duplication (DOCUMENTED)
  4. Done: Standardize jvmAndroidMain hierarchy setup (DEPLOYED)

Short-Term (Next Sprint)

  • Monitor if Application/Library Compose handling needs to diverge
  • Monitor if Flavor configuration needs specialization
  • Review configureTestOptions() to ensure all test config is centralized

Long-Term (Future)

  • If AndroidApplicationConventionPlugin and AndroidLibraryConventionPlugin patterns stabilize, consider extracting common baseline
  • Implement plugin validation tests to prevent future regressions
  • Create agent playbook for "build-logic optimization" with clear criteria

  • docs/BUILD_CONVENTION_TEST_DEPS.md - Details on test dependency centralization
  • docs/archive/BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md - Full analysis of optimization opportunities
  • AGENTS.md - Updated testing + KMP hierarchy guidelines (Section 3.B)