Bài 1. Tổng quan về module core-model
🎯 Mục tiêu học tập
Sau bài này, bạn sẽ nắm được:
- Hiểu rõ
core-modellà gì và vì sao cần tách riêng trong dự án Android đa module. - Phân biệt được sự khác nhau giữa Domain model, DTO, Entity, và UI Model.
- Biết cách sử dụng
core-modelđể giữ cho domain sạch, ít phụ thuộc, dễ bảo trì. - Nắm vững best practices khi định nghĩa và tổ chức model trong module này.
📖 1. Khái niệm
core-model là module trung tâm chứa domain model của ứng dụng. Nó được coi là trái tim của kiến trúc nhiều tầng bởi vì:
- Domain model biểu diễn các thực thể nghiệp vụ (business entities) quan trọng nhất của hệ thống.
- Các class trong
core-modelthường là Kotlin data class thuần túy, không có annotation, không phụ thuộc Android framework, Room, Retrofit hay bất kỳ thư viện nào khác. - Domain model có thể được sử dụng lại trong mọi tầng của ứng dụng: Presentation, Domain UseCase, Repository, DataSource, …
Ví dụ:
// core-model
// Một domain model cho bài hát trong ứng dụng nghe nhạc
data class Song(
val id: String,
val title: String,
val artistId: String,
val duration: Long
)
🧭 2. Vai trò
core-model giữ vai trò trung tâm trong toàn bộ dự án:
- Ngôn ngữ chung cho các tầng
Tất cả các tầng (UI, Data, Network, Database) đều map dữ liệu về domain model trongcore-model. Điều này đảm bảo toàn bộ hệ thống nói chung một “ngôn ngữ dữ liệu”. - Trái tim kiến trúc
API có thể thay đổi format JSON, database có thể thay đổi schema, nhưng domain model trongcore-modelthường ít khi thay đổi. Nó đảm bảo sự ổn định lâu dài. - Tách biệt trách nhiệm (Separation of Concerns)
core-networkchỉ tập trung vào DTO phục vụ network.core-databasechỉ tập trung vào Entity phục vụ database.presentation-modelchỉ tập trung vào UI model phục vụ UI.core-modelchứa các model chuẩn, trung lập, không dính đến framework.
🔍 3. Phân biệt các loại model
| Layer | Ví dụ | Đặc điểm |
|---|---|---|
Domain (core-model) |
Song |
Thuần Kotlin, không annotation, biểu diễn dữ liệu nghiệp vụ chính |
Network (core-network) |
SongDto |
Mapping với JSON, dùng annotation (@SerializedName), thường nullable |
Database (core-database) |
SongEntity |
Gắn annotation Room (@Entity), gắn với schema của database |
UI (presentation-model) |
DisplaySongModel |
Thêm field cho UI (ví dụ: isPlaying, isFavorite, isExpanded…) |
Mỗi loại model phục vụ một mục đích riêng biệt. Chúng không nên lẫn lộn để tránh coupling không cần thiết.
🔄 4. Ví dụ luồng dữ liệu
Để hiểu rõ hơn vai trò của core-model, hãy xem một luồng dữ liệu điển hình trong app nghe nhạc:
- API trả về
SongDto(chứa dữ liệu dạng JSON). - Repository map
SongDto→Song(domain model trongcore-model). - Database lưu trữ
SongEntity, khi query dữ liệu thì mapSongEntity→Song. - Ở UI layer,
Songđược map sangDisplaySongModelđể hiển thị trong RecyclerView hoặc Compose.
Sơ đồ minh họa:
presentation (feature-home, feature-player, feature-playlist)
│
▼
presentation-model (DisplaySongModel, UiState)
│
▼
core-model (Song, Artist, Playlist, …)
▲
┌─────┴───────────────┐
│ │
▼ ▼
core-network (SongDto) core-database (SongEntity)
📐 5. Best practices
✅ Nên
- Chỉ chứa pure Kotlin data class, không phụ thuộc Android SDK.
- Đặt tên ngắn gọn, rõ nghĩa:
Song,Artist,Playlist. - Tổ chức package theo nghiệp vụ:
song,playlist,artist. - Tận dụng sức mạnh
data class(equals, hashCode, copy). - Dùng Immutable property (val) bất cứ khi nào có thể để tăng tính an toàn.
❌ Không nên
- Không gắn annotation của Room, Retrofit, Gson, Moshi…
- Không đưa logic UI (
isSelected,isExpanded) vào domain model. - Không phụ thuộc Android framework (
Context,Parcelable,LiveData). - Không tái sử dụng domain model trực tiếp trong UI → luôn map sang UI model.
🏁 6. Kết luận
core-modellà nơi định nghĩa các domain model chuẩn cho ứng dụng.- Module này giúp hệ thống:
- Dễ bảo trì: API hoặc DB thay đổi nhưng domain không bị ảnh hưởng.
- Dễ test: unit test chạy thuần JVM, không cần Android framework.
- Dễ mở rộng: có thể thêm UI framework mới hoặc backend mới mà không chạm tới domain.
