Modularisasi Android 2026: Arsitektur Multi-Modul dan Pertanyaan Interview
Kuasai arsitektur multi-modul Android dengan convention plugins, Gradle version catalogs, dan feature modules. Termasuk pertanyaan interview umum tentang strategi modularisasi.

Modularisasi Android mengubah codebase monolitik menjadi sistem yang dapat dipelihara dan diskalakan, memungkinkan tim bekerja secara paralel tanpa konflik kode. Aplikasi Android yang termodularisasi dengan baik memiliki waktu build lebih cepat, pengujian terisolasi, dan proses onboarding developer baru yang lebih singkat.
Modularisasi membagi aplikasi Android menjadi modul Gradle independen dengan batasan yang jelas. Coupling rendah antar modul dan kohesi tinggi dalam setiap modul adalah prinsip utamanya. Aplikasi referensi Now in Android dari Google mendemonstrasikan pola ini dengan 40+ modul.
Mengapa Arsitektur Multi-Modul Penting untuk Aplikasi Android
Aplikasi Android dengan satu modul akan mengkompilasi ulang seluruh kode ketika satu baris berubah. Modifikasi pada layer networking memicu rekompilasi UI. Dua developer yang mengedit fitur berbeda menciptakan konflik merge pada file bersama. Waktu build incremental bisa mencapai 4+ menit.
Arsitektur multi-modul mengatasi masalah ini secara langsung:
- Build lebih cepat: Gradle hanya mengkompilasi ulang modul yang terpengaruh. Perubahan di
:feature:checkouttidak menyentuh:feature:profile. - Development paralel: Tim memiliki modul terpisah dengan API yang terdefinisi. Konflik merge berkurang signifikan.
- Testing terisolasi: Unit test berjalan pada satu modul tanpa memuat seluruh aplikasi.
- Code reuse: Modul design system
:core:uimenjadi library yang dapat digunakan di berbagai aplikasi.
Panduan modularisasi Android resmi merekomendasikan struktur modul berdasarkan fitur atau layer yang berubah bersama, mengikuti Single Responsibility Principle.
Tipe Modul dan Tanggung Jawabnya
Repository Now in Android menetapkan taksonomi modul yang terbukti dapat diskalakan ke aplikasi enterprise.
include(":app")
// Core modules - utilitas bersama
include(":core:common")
include(":core:data")
include(":core:database")
include(":core:datastore")
include(":core:designsystem")
include(":core:domain")
include(":core:model")
include(":core:network")
include(":core:ui")
// Feature modules - logika spesifik layar
include(":feature:home")
include(":feature:search")
include(":feature:bookmarks")
include(":feature:settings")App module: Berisi MainActivity, setup navigasi, dan scaffolding level aplikasi. Bergantung pada semua feature modules dan core modules yang diperlukan.
Core modules: Menyediakan fungsionalitas bersama antar fitur. :core:network menangani API calls. :core:database mengelola Room entities. :core:designsystem mendefinisikan komponen visual aplikasi.
Feature modules: Mengenkapsulasi satu layar atau alur pengguna. Setiap feature module hanya bergantung pada core modules yang dibutuhkan, tidak pernah pada feature modules lain.
Struktur ini memaksakan dependensi searah: features bergantung pada core, dan app bergantung pada features.
Gradle Version Catalogs untuk Manajemen Dependensi
Mengelola dependensi di 25+ modul tanpa konflik versi memerlukan konfigurasi terpusat. Gradle Version Catalogs menyelesaikan ini dengan satu file libs.versions.toml.
# gradle/libs.versions.toml
[versions]
agp = "8.7.0"
kotlin = "2.1.0"
compose-bom = "2026.09.00"
ksp = "2.1.0-1.0.29"
hilt = "2.54"
room = "2.7.0"
retrofit = "2.11.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version = "1.15.0" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
retrofit-core = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
[bundles]
compose = ["androidx-compose-ui", "androidx-compose-material3"]
room = ["room-runtime", "room-ktx"]
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }Modul kemudian mereferensikan dependensi dengan type-safe accessors:
dependencies {
implementation(libs.bundles.compose)
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
}Gradle menghasilkan accessors ini selama sync, memungkinkan IDE autocompletion dan validasi compile-time.
Siap menguasai wawancara Android Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Convention Plugins: Konfigurasi Build yang DRY
Proyek dengan 25 modul tanpa convention plugins akan mengulang compileSdk, minSdk, composeOptions, dan aplikasi plugin yang sama di setiap build.gradle.kts. Modul yang berbeda dapat secara tidak sengaja menggunakan konfigurasi yang berbeda.
Convention plugins memusatkan logika ini dalam included build build-logic.
import com.android.build.api.dsl.LibraryExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
class AndroidLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.library")
pluginManager.apply("org.jetbrains.kotlin.android")
extensions.configure<LibraryExtension> {
compileSdk = 35
defaultConfig {
minSdk = 26
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}
}
}
}Daftarkan plugin di build-logic/convention/build.gradle.kts:
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
}
gradlePlugin {
plugins {
register("androidLibrary") {
id = "myapp.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
register("androidFeature") {
id = "myapp.android.feature"
implementationClass = "AndroidFeatureConventionPlugin"
}
register("androidHilt") {
id = "myapp.android.hilt"
implementationClass = "AndroidHiltConventionPlugin"
}
}
}Feature modules sekarang hanya memerlukan konfigurasi minimal:
plugins {
alias(libs.plugins.myapp.android.feature)
alias(libs.plugins.myapp.android.hilt)
}
dependencies {
implementation(projects.core.data)
implementation(projects.core.designsystem)
}Build-logic Now in Android dari Google menggunakan pola yang sama persis.
Pola Komunikasi Antar Modul
Feature modules tidak boleh bergantung satu sama lain secara langsung. Batasan ini menjaga kompilasi paralel dan mencegah circular dependencies. Tiga pola menangani komunikasi cross-feature.
Navigasi via Shared Routes
object Routes {
const val HOME = "home"
const val PRODUCT_DETAIL = "product/{productId}"
const val CHECKOUT = "checkout"
fun productDetail(productId: String) = "product/$productId"
}Feature modules mengimpor routes dari :core:navigation tanpa mengetahui modul mana yang mengimplementasikan setiap destinasi.
Shared Domain Models
data class Product(
val id: String,
val name: String,
val price: BigDecimal,
val imageUrl: String
)Baik :feature:catalog maupun :feature:checkout bergantung pada :core:model untuk class Product.
Event Bus atau Shared ViewModel
Untuk komunikasi runtime, shared event bus di :core:common atau scoped ViewModel menangani event cross-feature:
object CartEventBus {
private val _events = MutableSharedFlow<CartEvent>()
val events: SharedFlow<CartEvent> = _events.asSharedFlow()
suspend fun emit(event: CartEvent) {
_events.emit(event)
}
}
sealed interface CartEvent {
data class ItemAdded(val productId: String) : CartEvent
data class ItemRemoved(val productId: String) : CartEvent
}Pertanyaan Interview Modularisasi Android
Modularisasi sering muncul dalam interview Android level senior. Interviewer menilai pemahaman tentang build systems, keputusan arsitektur, dan trade-off praktis.
Saat membahas modularisasi dalam interview, referensikan metrik konkret: peningkatan waktu build, velocity tim, atau jumlah modul spesifik dari proyek. Jawaban abstrak tentang "separation of concerns yang lebih baik" kurang meyakinkan dibanding "waktu build turun dari 4 menit ke 45 detik setelah modularisasi."
Q: Apa perbedaan antara dependensi api dan implementation di Gradle?
Dependensi implementation bersifat internal untuk modul. Consumer modul tidak dapat mengaksesnya. Dependensi api diekspos secara transitif: jika modul A menggunakan api(libs.retrofit), modul B yang bergantung pada A dapat menggunakan class Retrofit secara langsung.
Aturan praktis: gunakan implementation secara default. Hanya gunakan api ketika dependensi merupakan bagian dari public API modul. Penggunaan api berlebihan merusak enkapsulasi dan memperlambat build.
Q: Bagaimana cara menangani navigasi antar feature modules yang tidak saling bergantung?
Buat modul :core:navigation yang berisi definisi route dan interface navigasi. Feature modules bergantung pada modul bersama ini. App module menghubungkan destinasi dengan implementasinya. Ini mengikuti dependency inversion principle: features bergantung pada abstraksi, bukan implementasi konkret.
Q: Apa trade-off dari memiliki terlalu banyak modul?
Setiap modul menambah overhead konfigurasi Gradle: build files, resource processing, manifest merging. Waktu sync awal meningkat. Titik optimal bervariasi per proyek, tetapi 50+ modul umum di aplikasi besar. Manfaatnya (parallel builds, isolated tests, ownership yang jelas) biasanya lebih besar dari overhead untuk tim 5+ developer.
Q: Bagaimana convention plugins berbeda dari buildSrc?
Perubahan buildSrc memicu rebuild seluruh proyek. Convention plugins dalam included build hanya mengkompilasi ulang ketika kode plugin berubah, bukan ketika modul yang mengonsumsi berubah. Ini membuat convention plugins lebih cepat untuk development iteratif. Selain itu, convention plugins dapat dipublikasikan sebagai artifact terpisah untuk digunakan kembali di berbagai repository.
Q: Bagaimana cara menguji feature module secara terisolasi?
Feature modules bergantung pada core modules melalui interface. Buat implementasi fake di test fixtures:
class FakeProductRepository : ProductRepository {
private val products = mutableListOf<Product>()
override suspend fun getProducts(): List<Product> = products
fun addProduct(product: Product) {
products.add(product)
}
}Test feature module menginjeksi fakes melalui testing APIs Hilt atau manual constructor injection.
Untuk latihan pertanyaan lebih lanjut tentang arsitektur Android, lihat pertanyaan interview arsitektur MVVM dan modul dependency injection.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Kesimpulan untuk Proyek Android Multi-Modul
- Struktur modul berdasarkan fitur (
:feature:home,:feature:checkout) dan layer (:core:data,:core:ui). Features bergantung pada core, tidak pernah pada satu sama lain. - Gunakan Gradle Version Catalogs (
libs.versions.toml) untuk memusatkan versi dependensi. Bundles mengelompokkan dependensi terkait untuk build files yang lebih bersih. - Implementasikan convention plugins di
build-logicuntuk menghilangkan konfigurasi duplikat antar modul. Satu perubahan plugin memperbarui semua modul yang mengonsumsi. - Terapkan dependensi searah: app bergantung pada features, features bergantung pada core. Tools seperti Dependency Guard dapat mengotomatisasi enforcement.
- Ukur performa build sebelum dan sesudah modularisasi. Lacak waktu incremental build, bukan hanya clean builds, untuk memvalidasi peningkatan.
- Jaga batasan modul tetap stabil. Restrukturisasi yang sering meniadakan manfaat modularisasi.
Bisakah kamu menemukan bug di Android?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 17 September 2026
Bagikan
Artikel terkait

Android CameraX 2026: Panduan Lengkap Pengambilan Foto dan Video dengan Pertanyaan Wawancara
Pelajari CameraX di Android 2026: pengambilan foto, perekaman video, integrasi Jetpack Compose, dan pertanyaan wawancara teknis untuk developer Android.

Jetpack Navigation Compose 2026: Navigasi Type-Safe dan Pertanyaan Interview
Pelajari Jetpack Navigation Compose 2.10 dengan navigasi type-safe menggunakan Kotlin Serialization. Panduan lengkap dengan contoh kode dan pertanyaan interview Android.

Android WorkManager 2026: Panduan Lengkap Background Tasks, Constraints, dan Pertanyaan Interview
Pelajari Android WorkManager untuk menjalankan background tasks dengan constraints, chaining, dan CoroutineWorker. Termasuk pertanyaan interview untuk persiapan wawancara kerja Android developer.