เหตุใดจึงควรแยกเป็นโมดูล
ความเร็วในการสร้าง ความเป็นเจ้าของ และการนำกลับมาใช้ใหม่
เหตุใดจึงควรแยกเป็นโมดูล เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
ปัญหาของโมโนลิธ
เมื่อแอป Android เติบโตขึ้น โค้ดทั้งหมดมักจะอยู่ในโมดูล app เดียว นี่คือ โมโนลิธ ช่วงแรกจะสะดวก แต่เมื่อเวลาผ่านไปจะเริ่มยุ่งยาก: การเปลี่ยนแปลงทุกอย่างกระทบโมดูลเดียวกัน การสร้างใช้เวลานานขึ้น และสมาชิกในทีมก็รบกวนงานของกันและกันอยู่เสมอ
การทำให้เป็นโมดูล หมายถึงการแบ่งโมดูลขนาดใหญ่นั้นออกเป็นโมดูล Gradle ขนาดเล็กที่มุ่งเน้นหน้าที่หลายโมดูล ในบทเรียนนี้ คุณจะเรียนรู้ว่าทำไมทีมจึงทำเช่นนี้และมีประโยชน์ที่เป็นรูปธรรมอย่างไร
โมดูลคืออะไรในทางปฏิบัติ
ใน Gradle โมดูล คือหน่วยโค้ดที่สร้างแยกจากกันได้และมีไฟล์ build.gradle.kts ของตัวเอง แอปของคุณมีอย่างน้อยหนึ่งโมดูลอยู่แล้ว นั่นคือโมดูล :app คุณประกาศทุกโมดูลไว้ใน settings.gradle.kts
การเพิ่มโมดูลทำได้ง่ายเพียงแค่เพิ่มโมดูลนั้นเข้าไป แต่ละโมดูลจะสร้างผลลัพธ์การสร้างของตัวเอง และสามารถพึ่งพาโมดูลอื่นได้
// settings.gradle.kts
include(":app")
include(":core:designsystem")
include(":core:data")
include(":feature:home")
include(":feature:profile")ประโยชน์ข้อที่ 1: สร้างได้เร็วขึ้น
ประโยชน์ที่เห็นได้ชัดที่สุดคือ ความเร็วในการสร้าง Gradle สามารถสร้างโมดูลแบบ ขนาน และที่สำคัญคือ แคชและข้าม โมดูลที่อินพุตไม่เปลี่ยนแปลงได้
หากคุณแก้ไขเฉพาะ :feature:profile Gradle จะนำผลลัพธ์ที่สร้างไว้แล้วของโมดูลอื่นทั้งหมดกลับมาใช้ ในโมโนลิธ การเปลี่ยนแปลงใด ๆ อาจบังคับให้คอมไพล์แอปทั้งหมดใหม่
- การทำงานแบบขนานระหว่างโมดูล
- การสร้างแบบเพิ่มทีละส่วน: สร้างใหม่เฉพาะส่วนที่เปลี่ยนแปลง
- อัตราการใช้แคชระยะไกลและแคชการสร้างได้ดีขึ้น
// gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=trueประโยชน์ข้อที่ 2: ขอบเขตที่ชัดเจน
โมดูลช่วยกำหนด ขอบเขต โค้ดในโมดูลหนึ่งจะมองเห็นได้เฉพาะสิ่งที่อีกโมดูลจงใจเปิดเผยเท่านั้น วิธีนี้ป้องกันโค้ดพันกันยุ่งเหยิงที่ทุกคลาสเข้าถึงคลาสอื่นไปหมด
คุณควบคุมการมองเห็นได้ด้วยการกำหนดค่า Gradle แบบ api และ implementation โดย implementation จะทำให้การพึ่งพาเป็นส่วนตัวภายในโมดูล ผู้ใช้โมดูลจึงไม่สามารถนำไปใช้โดยไม่ตั้งใจได้
// feature/profile/build.gradle.kts
dependencies {
// Exposed to whoever depends on :feature:profile
api(project(":core:model"))
// Private: hidden from consumers of this module
implementation(project(":core:network"))
}ประโยชน์ข้อที่ 3: การนำกลับมาใช้ใหม่
เมื่อย้ายตรรกะมาไว้ในโมดูลที่มุ่งเน้นหน้าที่แล้ว คุณสามารถ นำกลับมาใช้ใหม่ ได้ทุกที่ โมดูล :core:designsystem ที่เก็บธีม สี และ composable ที่นำกลับมาใช้ใหม่ได้ สามารถแชร์ให้ทุกฟีเจอร์ใช้ร่วมกัน
แนวคิดเดียวกันนี้ขยายไปยังหลายแอปได้ บริษัทสามารถแชร์โมดูล :core:network ระหว่างผลิตภัณฑ์หลายรายการ แทนการคัดลอกโค้ด
// Any feature can pull in shared building blocks
// feature/home/build.gradle.kts
dependencies {
implementation(project(":core:designsystem"))
implementation(project(":core:data"))
}ประโยชน์ข้อที่ 4: ความรับผิดชอบของทีม
โมดูลสอดคล้องกับ ความรับผิดชอบของทีม ได้เป็นอย่างดี ทีมชำระเงินรับผิดชอบ :feature:payments ส่วนทีมโปรไฟล์รับผิดชอบ :feature:profile ทั้งสองทีมทำงานขนานกันได้โดยมีข้อขัดแย้งตอนรวมโค้ดน้อยลง เพราะโค้ดอยู่ในโฟลเดอร์และไฟล์การสร้างคนละชุด
เครื่องมืออย่างไฟล์ CODEOWNERS สามารถขอให้ทีมที่เหมาะสมตรวจสอบโดยอัตโนมัติ ตามเส้นทางของโมดูล
# .github/CODEOWNERS
/feature/payments/ @org/payments-team
/feature/profile/ @org/profile-team
/core/designsystem/ @org/platform-teamประโยชน์ข้อที่ 5: การห่อหุ้มด้วยการมองเห็น
ภายในโมดูล ตัวปรับแต่ง internal ของ Kotlin มีประโยชน์อย่างมาก คลาสหรือฟังก์ชันที่เป็น internal จะมองเห็นได้ เฉพาะภายในโมดูลของตัวเองเท่านั้น โมดูลอื่นไม่สามารถอ้างอิงสิ่งนั้นได้โดยตรง
วิธีนี้ช่วยให้คุณเปิดเผยส่วนติดต่อสาธารณะขนาดเล็กและซ่อนรายละเอียดการทำงานภายใน ซึ่งไม่สามารถบังคับใช้ได้เมื่ออยู่ในโมดูลขนาดใหญ่เพียงโมดูลเดียว
// In :core:data
// Public API other modules may use
fun interface UserRepository {
suspend fun loadUser(id: String): User
}
// Hidden from other modules
internal class DefaultUserRepository(
private val api: UserApi
) : UserRepository {
override suspend fun loadUser(id: String) = api.fetch(id).toUser()
}ต้นทุน: ค่าใช้จ่ายเพิ่มเติมบางส่วน
การทำให้เป็นโมดูลไม่ได้ไม่มีต้นทุน แต่ละโมดูลเพิ่มไฟล์ build.gradle.kts ที่ต้องดูแล และคุณต้องคิดว่าโค้ดแต่ละส่วนควรเป็นของโมดูลใด การแบ่งโมดูลมากเกินไปในแอปขนาดเล็กจะเพิ่มงานจุกจิกโดยไม่ได้ประโยชน์คุ้มค่า
หลักทั่วไปคือ ควรทำให้เป็นโมดูลเมื่อเวลาสร้างนานจนเป็นปัญหา เมื่อทีมทำงานทับซ้อนกัน หรือเมื่อมีชั้นโค้ดที่นำกลับมาใช้ใหม่ได้อย่างชัดเจน แอปงานอดิเรกที่ทำช่วงสุดสัปดาห์แทบไม่จำเป็นต้องมี 30 โมดูล
โครงสร้างโมดูลทั่วไป
โครงสร้างที่พบได้บ่อยและขยายต่อได้จะแบ่งโมดูลออกเป็นชั้น app, feature และ core โมดูล :app เชื่อมทุกอย่างเข้าด้วยกัน ฟีเจอร์เก็บหน้าจอที่ผู้ใช้มองเห็น ส่วนโมดูล core เก็บโครงสร้างพื้นฐานที่ใช้ร่วมกัน
// Conceptual project tree
// app/ <- single entry point, wires features
// feature/
// home/
// profile/
// settings/
// core/
// designsystem/ <- theme + reusable composables
// data/ <- repositories
// network/ <- Retrofit/Ktor
// model/ <- shared data classesปลั๊กอินตามแบบแผนช่วยให้จัดการได้ง่าย
เมื่อมีหลายโมดูล การคัดลอกการตั้งค่า Gradle เดิม ๆ ไปไว้ทุกแห่งเป็นกับดัก ทีมจึงแยกการตั้งค่าที่ใช้ร่วมกันออกมาเป็น ปลั๊กอินตามแบบแผน (ในโมดูล build-logic) จากนั้นแต่ละโมดูลจริงจะใช้ปลั๊กอินเพียงหนึ่งตัว แทนการเขียนซ้ำหลายสิบบรรทัด
คุณจะเห็นรูปแบบนี้ในแอปโอเพนซอร์สขนาดใหญ่อย่าง Now in Android สำหรับตอนนี้ ขอให้เข้าใจเป้าหมายไว้ว่า ต้องทำให้ไฟล์การสร้างมีขนาดเล็กและสอดคล้องกัน
// feature/home/build.gradle.kts
plugins {
// One convention plugin sets up Android + Compose + Kotlin
id("myapp.android.feature")
}
android { namespace = "com.myapp.feature.home" }แนวคิด: คิดเป็นชั้น
แบบจำลองทางความคิดที่มีประโยชน์ที่สุดคือ การพึ่งพาควรไหล ลงด้านล่าง ฟีเจอร์พึ่งพา core ส่วน core ไม่พึ่งพาฟีเจอร์ โมดูล :app อยู่บนสุดและพึ่งพาทุกสิ่งที่จำเป็นต่อการประกอบแอป
หากรักษาทิศทางนี้ให้สม่ำเสมอ กราฟโมดูลจะสะอาดและคุณจะหลีกเลี่ยงการวนซ้ำ ซึ่งคุณจะได้ศึกษาในบทเรียนถัดไป
// Allowed: app -> feature -> core
// Forbidden: core -> feature (upward) or feature -> feature (sideways)
// app/build.gradle.kts
dependencies {
implementation(project(":feature:home"))
implementation(project(":feature:profile"))
}ตรวจสอบความเข้าใจ
ข้อใดต่อไปนี้คือประโยชน์ที่เป็นรูปธรรมและพบได้ในชีวิตประจำวันมากที่สุด ซึ่งทีมจะได้รับจากการทำให้แอป Android ที่กำลังเติบโตเป็นโมดูล
สรุป: ทำไมต้องทำให้เป็นโมดูล
คุณได้เรียนรู้ว่าทำไมทีมจึงแบ่งโมโนลิธออกเป็นโมดูล:
- สร้างได้เร็วขึ้น ด้วยการทำงานแบบขนานและการแคชแบบเพิ่มทีละส่วน
- ขอบเขตที่ชัดเจน ด้วย
api/implementationและinternal - การนำกลับมาใช้ใหม่ ของชั้น core เช่น ระบบการออกแบบและเครือข่าย
- ความรับผิดชอบของทีม พร้อมข้อขัดแย้งตอนรวมโค้ดที่น้อยลง
คุณยังได้เห็นต้นทุน (ไฟล์การสร้างที่เพิ่มขึ้น) และกฎทองคำว่า การพึ่งพาไหลลงด้านล่าง app -> feature -> core ขั้นต่อไป คุณจะวาดขอบเขตจริงระหว่างโมดูล feature และ core
คำถามที่พบบ่อย
บทเรียน “เหตุใดจึงควรแยกเป็นโมดูล” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เหตุใดจึงควรแยกเป็นโมดูล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เหตุใดจึงควรแยกเป็นโมดูล”
ความเร็วในการสร้าง ความเป็นเจ้าของ และการนำกลับมาใช้ใหม่ คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “เหตุใดจึงควรแยกเป็นโมดูล” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม
ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดจึงควรแยกเป็นโมดูล
- โมดูลฟีเจอร์และโมดูลแกนกลาง
- การจัดการการพึ่งพาระหว่างโมดูล
- การนำทางข้ามโมดูล