Modularization Android 2026: Kiến Trúc Multi-Module và Câu Hỏi Phỏng Vấn
Làm chủ kiến trúc multi-module Android với convention plugins, Gradle version catalogs và feature modules. Bao gồm các câu hỏi phỏng vấn phổ biến về chiến lược modularization.

Modularization Android chuyển đổi codebase nguyên khối thành hệ thống dễ bảo trì và mở rộng, cho phép các team làm việc song song mà không xung đột code. Ứng dụng Android được modularize tốt có thời gian build nhanh hơn, testing độc lập và quy trình onboarding developer mới ngắn hơn.
Modularization chia ứng dụng Android thành các module Gradle độc lập với ranh giới rõ ràng. Coupling thấp giữa các module và cohesion cao trong mỗi module là nguyên tắc chủ đạo. Ứng dụng tham chiếu Now in Android của Google minh họa pattern này với hơn 40 module.
Tại Sao Kiến Trúc Multi-Module Quan Trọng Với Ứng Dụng Android
Ứng dụng Android đơn module sẽ biên dịch lại toàn bộ code khi một dòng thay đổi. Sửa đổi layer networking kích hoạt biên dịch lại UI. Hai developer chỉnh sửa các tính năng khác nhau tạo ra xung đột merge trong các file dùng chung. Thời gian build incremental có thể lên tới hơn 4 phút.
Kiến trúc multi-module giải quyết trực tiếp các vấn đề này:
- Build nhanh hơn: Gradle chỉ biên dịch lại các module bị ảnh hưởng. Thay đổi trong
:feature:checkoutkhông chạm tới:feature:profile. - Phát triển song song: Các team sở hữu module riêng với API được định nghĩa. Xung đột merge giảm đáng kể.
- Testing độc lập: Unit test chạy trên một module duy nhất mà không cần tải toàn bộ ứng dụng.
- Tái sử dụng code: Module design system
:core:uitrở thành library có thể dùng trong nhiều ứng dụng.
Hướng dẫn modularization Android chính thức khuyến nghị cấu trúc module theo tính năng hoặc layer thay đổi cùng nhau, tuân theo Single Responsibility Principle.
Các Loại Module và Trách Nhiệm
Repository Now in Android thiết lập phân loại module đã được chứng minh có thể mở rộng tới ứng dụng enterprise.
include(":app")
// Core modules - tiện ích dùng chung
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 - logic theo màn hình
include(":feature:home")
include(":feature:search")
include(":feature:bookmarks")
include(":feature:settings")App module: Chứa MainActivity, thiết lập navigation và scaffolding cấp ứng dụng. Phụ thuộc vào tất cả feature modules và core modules cần thiết.
Core modules: Cung cấp chức năng dùng chung giữa các tính năng. :core:network xử lý API calls. :core:database quản lý Room entities. :core:designsystem định nghĩa các thành phần giao diện ứng dụng.
Feature modules: Đóng gói một màn hình hoặc luồng người dùng. Mỗi feature module chỉ phụ thuộc vào các core modules cần thiết, không bao giờ phụ thuộc vào feature modules khác.
Cấu trúc này bắt buộc dependency một chiều: features phụ thuộc vào core, và app phụ thuộc vào features.
Gradle Version Catalogs Cho Quản Lý Dependency
Quản lý dependency trên hơn 25 module mà không có xung đột phiên bản đòi hỏi cấu hình tập trung. Gradle Version Catalogs giải quyết điều này với một file libs.versions.toml duy nhất.
# 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" }Các module sau đó tham chiếu dependency với type-safe accessors:
dependencies {
implementation(libs.bundles.compose)
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
}Gradle tạo các accessors này trong quá trình sync, cho phép IDE autocompletion và validation compile-time.
Sẵn sàng chinh phục phỏng vấn Android?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Convention Plugins: Cấu Hình Build Theo Nguyên Tắc DRY
Dự án với 25 module mà không có convention plugins sẽ lặp lại cùng compileSdk, minSdk, composeOptions và áp dụng plugin trong mỗi build.gradle.kts. Các module khác nhau có thể vô tình sử dụng cấu hình khác nhau.
Convention plugins tập trung logic này trong 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
}
}
}
}
}Đăng ký plugin trong 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 giờ chỉ yêu cầu cấu hình tối thiểu:
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 của Google sử dụng chính xác pattern này.
Các Pattern Giao Tiếp Giữa Module
Feature modules không được phụ thuộc trực tiếp vào nhau. Ràng buộc này giữ biên dịch song song và ngăn circular dependencies. Ba pattern xử lý giao tiếp cross-feature.
Navigation Qua 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 import routes từ :core:navigation mà không biết module nào implement từng destination.
Shared Domain Models
data class Product(
val id: String,
val name: String,
val price: BigDecimal,
val imageUrl: String
)Cả :feature:catalog và :feature:checkout đều phụ thuộc vào :core:model cho class Product.
Event Bus hoặc Shared ViewModel
Để giao tiếp runtime, shared event bus trong :core:common hoặc scoped ViewModel xử lý các 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
}Câu Hỏi Phỏng Vấn Về Modularization Android
Modularization xuất hiện thường xuyên trong các buổi phỏng vấn Android cấp senior. Người phỏng vấn đánh giá hiểu biết về build systems, quyết định kiến trúc và trade-off thực tế.
Khi thảo luận về modularization trong phỏng vấn, hãy tham chiếu các metric cụ thể: cải thiện thời gian build, velocity của team, hoặc số module cụ thể từ dự án. Câu trả lời trừu tượng về "separation of concerns tốt hơn" ít thuyết phục hơn so với "thời gian build giảm từ 4 phút xuống 45 giây sau khi modularization."
Q: Sự khác biệt giữa dependency api và implementation trong Gradle là gì?
Dependency implementation là nội bộ của module. Consumer của module không thể truy cập chúng. Dependency api được expose một cách transitive: nếu module A sử dụng api(libs.retrofit), module B phụ thuộc vào A có thể sử dụng các class Retrofit trực tiếp.
Quy tắc thực tế: sử dụng implementation mặc định. Chỉ sử dụng api khi dependency là một phần của public API của module. Lạm dụng api phá vỡ encapsulation và làm chậm build.
Q: Làm thế nào để xử lý navigation giữa các feature modules không phụ thuộc vào nhau?
Tạo module :core:navigation chứa định nghĩa route và interface navigation. Feature modules phụ thuộc vào module dùng chung này. App module kết nối destination với implementation. Điều này tuân theo dependency inversion principle: features phụ thuộc vào abstraction, không phải implementation cụ thể.
Q: Trade-off của việc có quá nhiều module là gì?
Mỗi module thêm overhead cấu hình Gradle: build files, resource processing, manifest merging. Thời gian sync ban đầu tăng. Điểm tối ưu thay đổi theo dự án, nhưng 50+ module là phổ biến trong ứng dụng lớn. Lợi ích (parallel builds, isolated tests, ownership rõ ràng) thường lớn hơn overhead cho team 5+ developer.
Q: Convention plugins khác với buildSrc như thế nào?
Thay đổi buildSrc kích hoạt rebuild toàn bộ dự án. Convention plugins trong included build chỉ biên dịch lại khi code plugin thay đổi, không phải khi các module sử dụng thay đổi. Điều này làm convention plugins nhanh hơn cho development lặp đi lặp lại. Ngoài ra, convention plugins có thể được publish như artifact riêng để tái sử dụng trong nhiều repository.
Q: Làm thế nào để test feature module một cách độc lập?
Feature modules phụ thuộc vào core modules thông qua interface. Tạo implementation fake trong 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 inject fakes thông qua testing APIs của Hilt hoặc manual constructor injection.
Để luyện tập thêm các câu hỏi về kiến trúc Android, xem câu hỏi phỏng vấn kiến trúc MVVM và module dependency injection.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Kết Luận Cho Dự Án Android Multi-Module
- Cấu trúc module theo tính năng (
:feature:home,:feature:checkout) và layer (:core:data,:core:ui). Features phụ thuộc vào core, không bao giờ phụ thuộc vào nhau. - Sử dụng Gradle Version Catalogs (
libs.versions.toml) để tập trung phiên bản dependency. Bundles nhóm các dependency liên quan cho build files gọn gàng hơn. - Implement convention plugins trong
build-logicđể loại bỏ cấu hình trùng lặp giữa các module. Một thay đổi plugin cập nhật tất cả các module sử dụng. - Bắt buộc dependency một chiều: app phụ thuộc vào features, features phụ thuộc vào core. Công cụ như Dependency Guard có thể tự động hóa việc enforcement.
- Đo lường hiệu suất build trước và sau modularization. Theo dõi thời gian incremental build, không chỉ clean builds, để xác nhận cải thiện.
- Giữ ranh giới module ổn định. Tái cấu trúc thường xuyên làm mất đi lợi ích của modularization.
Bạn có tìm ra lỗi trong Android không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 17 tháng 9, 2026
Chia sẻ
Bài viết liên quan

Android CameraX 2026: Hướng Dẫn Chụp Ảnh và Quay Video với Câu Hỏi Phỏng Vấn
Tìm hiểu CameraX trên Android 2026: chụp ảnh, quay video, tích hợp Jetpack Compose và các câu hỏi phỏng vấn kỹ thuật dành cho lập trình viên Android.

Jetpack Navigation Compose 2026: Điều Hướng Type-Safe và Câu Hỏi Phỏng Vấn
Tìm hiểu Jetpack Navigation Compose 2.10 với điều hướng type-safe sử dụng Kotlin Serialization. Hướng dẫn đầy đủ với ví dụ code và câu hỏi phỏng vấn Android.

Android WorkManager 2026: Hướng Dẫn Toàn Diện Background Tasks, Constraints và Câu Hỏi Phỏng Vấn
Tìm hiểu Android WorkManager để chạy background tasks với constraints, chaining và CoroutineWorker. Bao gồm các câu hỏi phỏng vấn Android developer thường gặp.