โค้ดขยะ (junk code) หมายถึงโค้ดและ dependencies ที่ไม่ก่อให้เกิดประโยชน์ต่อโปรเจกต์ แต่เพิ่มขนาด เวลาบิวด์ และภาระทางปัญญาให้กับทีม ต่างจากโค้ดที่ตายแล้ว (dead code) ที่ไม่เคยถูกเรียกใช้งาน จังก์อาจทำงานได้แต่ทำอย่างไม่มีประสิทธิภาพหรือซ้ำซ้อน: ไลบรารีที่ซ้ำกัน, import ที่ไม่ได้ใช้, บล็อกที่ถูกคอมเมนต์, polyfill ที่ล้าสมัย และ abstraction เชิงตกแต่ง ตามรายงาน CodeScene Code Health Report (2025) โดยเฉลี่ย 15 เปอร์เซ็นต์ของ dependencies ในโปรเจกต์มือถือไม่ได้ถูกใช้โดยตรงและดึงเฉพาะแพ็กเกจแบบ transitive เท่านั้น โค้ดขยะ คือ “น้ำหนักส่วนเกิน” ของโปรเจกต์: มันทำให้ฐานโค้ดหนาขึ้นแต่ไม่แข็งแกร่งขึ้น การตรวจสอบ dependencies เป็นประจำและการลบ abstraction ที่ซ้ำซ้อนช่วยเพิ่มความเร็วในการบิวด์และคุณภาพโค้ดได้โดยตรง
ประเด็นสำคัญ
จังก์ (junk code) เป็นคำรวมสำหรับโค้ด การกำหนดค่า และ dependencies ที่มีอยู่ในโปรเจกต์แต่ไม่มีคุณค่าเชิงหน้าที่ จังก์ไม่จำเป็นต้องเสียหายหรือไม่ได้ใช้ — ปัญหาคือการมีอยู่ของมันทำให้เมตริกโปรเจกต์แย่ลงโดยไม่มีเหตุผลอันสมควร
จังก์แบ่งออกเป็นสี่ประเภท ประเภทแรก — dependencies ที่ซ้ำซ้อน: ไลบรารีที่ถูกเพิ่มสำหรับฟีเจอร์เดียวซึ่งสามารถ implement ด้วยเครื่องมือมาตรฐานได้ ประเภทที่สอง — น้ำหนักที่ตายแล้ว: บล็อกที่ถูกคอมเมนต์, TODO ที่ไม่มี ticket, เมธอดที่ว่างเปล่า และคลาส stub ประเภทที่สาม — โซลูชันที่ซ้ำกัน: ไลบรารีสองตัวที่ทำสิ่งเดียวกัน (เช่น Gson และ Kotlin Serialization ในโปรเจกต์เดียว) ประเภทที่สี่ — การออกแบบเกินจำเป็น: ชั้นสถาปัตยกรรมที่ไม่ได้ใช้แต่ถูกดูแล “เผื่อไว้”
จากการวิจัยของ Stripe Engineering Productivity (2025) การลบจังก์ 10 เปอร์เซ็นต์ออกจากโปรเจกต์ทั่วไปช่วยลดเวลาบิวด์ทั้งหมดโดยเฉลี่ย 22 เปอร์เซ็นต์ สาเหตุ: ทุก dependencies ที่เพิ่มขึ้นทำให้กราฟบิวด์ใหญ่ขึ้น ทุก abstraction ที่ว่างเปล่าต้องใช้เวลาในการทำความเข้าใจ ทุกบล็อกที่ถูกคอมเมนต์เบี่ยงเบนความสนใจ
ความยากหลักในการต่อสู้กับจังก์คือการไม่มีผลลัพธ์ในทันที โปรเจกต์ที่มีโค้ดขยะยังคอมไพล์และทำงานได้ ปัญหาสะสมทีละน้อย: บิวด์ช้าลง จำนวน dependencies แบบ transitive เพิ่มขึ้น และหลังจากหนึ่งปีการเพิ่มฟีเจอร์ใหม่ใช้เวลานานเป็นสองเท่าของที่ควรจะเป็น
dependencies ขยะ คือไลบรารีและแพ็กเกจที่ถูกเพิ่มเข้าไปในโปรเจกต์แต่ไม่ได้ใช้โดยตรงในโค้ด หรือใช้เพียงฟีเจอร์เดียวซึ่ง implement ด้วย API มาตรฐานได้ง่ายกว่า
ตัวอย่างทั่วไป: ไลบรารีประมวลผล JSON เมื่อโปรเจกต์ใช้ Kotlin Serialization อยู่แล้ว (parser สองตัวคือขยะ); ไลบรารี Apache Commons Lang สำหรับการเรียก StringUtils.isEmpty เพียงครั้งเดียวซึ่งสามารถแทนที่ด้วย Kotlin extension isNullOrBlank; ไลบรารี DI ที่ใช้ในหนึ่งโมดูลจากสิบในขณะที่โมดูลอื่นได้รับ dependencies ผ่าน constructor ด้วยตนเอง
ทุ dependencies ที่เกินมาไม่ใช่แค่โค้ดส่วนเกินในไบนารี มันเพิ่ม พื้นที่ผิวการโจมตี สำหรับช่องโหว่: ตาม GitHub Advisory Database (2025) 40 เปอร์เซ็นต์ของ CVE ที่สำคัญในโปรเจกต์มือถือมาจาก dependencies แบบ transitive ที่นักพัฒนาไม่สามารถควบคุมได้ ยิ่ง dependencies น้อย พื้นที่ผิวการโจมตียิ่งเล็กลง
// View Gradle dependency tree
./gradlew app:dependencies --configuration releaseRuntimeClasspath
// Find unused dependencies (Gradle plugin)
plugins {
id "com.autonomousapps.dependency-analysis" version "2.0.0"
}
// Generate unused library report
./gradlew buildHealth
สำหรับ iOS ให้ใช้คำสั่ง swift package show-dependencies ซึ่งแสดงแผนผัง dependencies ทั้งหมด เครื่องมือ Xcode Build Timeline แสดงว่าแต่ละไลบรารีเพิ่มเวลาให้กับการบิวด์เท่าใด ถ้าไลบรารีใช้เวลา 30 เปอร์เซ็นต์ของการคอมไพล์แต่ใช้บนหน้าจอเดียว มันคือตัวเลือกสำหรับการลบหรือแทนที่
สำหรับ Node.js (React Native) ให้ใช้ depcheck — ยูทิลิตี้ที่ค้นหา dependencies ที่ไม่ได้ใช้ใน package.json และ npm-check ซึ่งแสดงเวอร์ชันที่ล้าสมัยเพิ่มเติม กำหนดกฎ: ทุก dependencies ใหม่ต้องผ่านการตรวจสอบโค้ดพร้อมเหตุผลว่า “ทำไมไม่สามารถใช้เครื่องมือมาตรฐาน”
import ที่ตายแล้ว เป็นประเภทจังก์ที่พบบ่อยที่สุด มันไม่ส่งผลต่อรันไทม์แต่เพิ่มเวลาในการคอมไพล์: คอมไพเลอร์ประมวลผลทุก import แม้แต่ตัวที่ไม่ได้ใช้ ในโปรเจกต์ขนาดใหญ่ การลบ import ที่ไม่ได้ใช้ช่วยลดเวลาบิวด์ได้ 5–10 เปอร์เซ็นต์
IDE สมัยใหม่จะเน้น import ที่ไม่ได้ใช้เป็นสีเทาโดยอัตโนมัติ ตั้งค่าการทำความสะอาดอัตโนมัติเมื่อบันทึกไฟล์: ใน IntelliJ IDEA — Optimize Imports on the fly, ใน Xcode — Editor > Remove Unused Imports เพิ่มการตรวจสอบใน CI: linter ควรบล็อก commits ที่มี import ที่ไม่ได้ใช้
โค้ดที่ถูกคอมเมนต์ เป็นจังก์อีกประเภทหนึ่ง นักพัฒนาคอมเมนต์บล็อกเพื่อ “ไม่สูญเสีย” ฟังก์ชันในระหว่างการปรับโครงสร้าง อย่างไรก็ตาม git เก็บประวัติการเปลี่ยนแปลงทั้งหมด: โค้ดที่ถูกลบใดๆ สามารถกู้คืนได้ด้วยคำสั่ง git revert หรือ git log -S
กฎ: ไม่มีโค้ดที่ถูกคอมเมนต์ใน repository ถ้าโค้ดไม่จำเป็นให้ลบอย่างถาวร ถ้าโค้ดจำเป็นแต่ถูกปิดใช้งานชั่วคราว ให้ใช้ feature toggle พร้อม ticket และวันหมดอายุ คอมเมนต์แบบ // TODO: remove after migration — อย่าทิ้งไว้โดยไม่มีกำหนดเวลา กำหนดวันที่และเตือนตัวเองด้วยปฏิทิน
การออกแบบเกินจำเป็น คือการสร้างชั้นสถาปัตยกรรมที่ไม่แก้ปัญหาปัจจุบันแต่ต้องการการบำรุงรักษา นี่เป็นจังก์ประเภทที่ยากที่สุดประเภทหนึ่งเพราะโดยรูปแบบแล้วโค้ด “ถูกต้อง”: มัน遵循 SOLID, ครอบคลุมโดยการทดสอบ และสอดคล้องกับสถาปัตยกรรม ปัญหาคือมันไม่จำเป็น
ตัวอย่างคลาสสิกคือ คลาส UseCase เชิงนามธรรม ที่มีเมธอด invoke เพียงตัวเดียวซึ่งเรียก repository หาก UseCase ไม่เพิ่มตรรกะ (caching, retry, transformation) และเพียงส่งต่อการเรียก มันคือเอนทิตีที่เกินมา มันเพิ่มการนำทางในโปรเจกต์: นักพัฒนาเปิด UseCase เห็น invoke → repository แล้วปิดมัน เสียเวลา ได้ประโยชน์เป็นศูนย์
อีกตัวอย่างคือ การกำหนดพารามิเตอร์มากเกินไป อินเทอร์เฟซแบบ generic ที่มี type parameters หกตัวซึ่งใช้ในที่เดียว แต่ละ type parameter คือภาระทางปัญญา: เมื่ออ่านโค้ด คุณต้องจำหกประเภทในใจในขณะที่ใช้จริงเพียงสองประเภท ถ้า abstraction ไม่ถูกนำกลับมาใช้ใหม่ มันก็ซ้ำซ้อน
เกณฑ์การตัด: ถ้า abstraction ไม่ถูกนำกลับมาใช้ใหม่ในสามบริบทที่แตกต่างกัน ให้ลบทิ้ง abstraction จะสมเหตุสมผลเมื่อมันแก้ปัญหาการทำซ้ำได้จริง ไม่ใช่เมื่อมันทำนายสถานการณ์สมมติในอนาคต YAGNI (You Ain’t Gonna Need It) เป็นหลักการที่ดีที่สุดในการป้องกันการออกแบบเกินจำเป็น
การตรวจสอบจังก์ต้องใช้การผสมผสานระหว่างการวิเคราะห์แบบ static, การวิเคราะห์ dependencies และการตรวจสอบด้วยตนเอง เป็นไปไม่ได้ที่จะทำให้การตรวจจับ abstraction ที่ซ้ำซ้อนเป็นอัตโนมัติทั้งหมด แต่จังก์ทางเทคนิค (import ที่ตายแล้ว, ไลบรารีที่ไม่ได้ใช้, โค้ดที่ถูกคอมเมนต์) สามารถพบได้ด้วยเครื่องมือ
| หมวดหมู่ | เครื่องมือ | ตรวจสอบอะไร |
|---|---|---|
| dependencies ที่ไม่ได้ใช้ | dependency-analysis (Gradle) | ไลบรารีที่ไม่ได้ใช้ในโค้ด |
| dependencies ที่ไม่ได้ใช้ | depcheck (Node.js) | แพ็กเกจจาก package.json ที่ไม่มี import |
| dependencies ที่ไม่ได้ใช้ | swift package --show-dependencies | แผนผัง dependencies ของ SwiftPM |
| import ที่ตายแล้ว | IDE (Optimize Imports) | คำสั่ง import ที่ไม่ได้ใช้ |
| โค้ดที่ถูกคอมเมนต์ | grep -r “//” / rg “^\s*//” | บล็อกคอมเมนต์ที่มีโค้ด |
| เมธอด/คลาสที่ว่างเปล่า | SonarQube / CodeClimate | เมธอดที่ไม่มีเนื้อหาหรือเนื้อหาว่าง |
| ไลบรารีที่ซ้ำกัน | Gradle lint (duplicate classes) | ความขัดแย้งของคลาสจากไลบรารีต่างกัน |
สำหรับการตรวจสอบอย่างสมบูรณ์ ให้เรียกใช้ buildHealth (Android) หรือ depcheck (Node.js) ครั้งต่อ sprint สร้าง dashboard ใน CI ที่แสดงแนวโน้มจำนวน dependencies ตาม sprint ถ้าจำนวนเพิ่มขึ้นแต่ฟังก์ชันไม่ได้เพิ่มขึ้นตามสัดส่วน ทีมกำลังสะสมจังก์
ให้ความสนใจกับ คลาสที่ซ้ำกัน — ข้อผิดพลาดที่เกิดขึ้นเมื่อไลบรารีสองตัวมีคลาสเดียวกัน นี่ไม่ใช่แค่จังก์แต่ยังเป็นแหล่งโดยตรงของความขัดแย้งในการบิวด์ ใน Gradle ความขัดแย้งเหล่านี้แก้ไขผ่าน force หรือ exclude แต่การแก้ไขแต่ละครั้งเป็นสัญญาณว่าไลบรารีตัวใดตัวหนึ่งไม่จำเป็น
การทำความสะอาดจังก์ไม่ใช่การกระทำครั้งเดียวแต่เป็นกระบวนการประจำ ถ้าไม่มีขั้นตอน จังก์จะกลับมาภายในสองถึงสาม sprint แนวปฏิบัติที่ดีที่สุดคือจัดสรร 10–15 เปอร์เซ็นต์ของความจุของแต่ละ sprint ให้กับการทำความสะอาดทางเทคนิค รวมถึงการตรวจสอบจังก์
กระบวนการประกอบด้วยสี่ขั้นตอน ขั้นแรก — การวินิจฉัย: เรียกใช้เครื่องมือ รับรายงาน จัดลำดับความสำคัญ ลำดับความสำคัญสูง: dependencies ที่มี CVE ที่รู้จักและไลบรารีที่ซ้ำกัน ลำดับความสำคัญปานกลาง: import ที่ตายแล้วและโค้ดที่ถูกคอมเมนต์ ลำดับความสำคัญต่ำ: abstraction ที่ซ้ำซ้อน (ต้องการการวิเคราะห์ด้วยตนเอง)
ขั้นที่สอง — การทำความสะอาด: ลบ dependencies ที่ตายแล้ว, แทนที่ไลบรารีที่ซ้ำกันด้วยตัวเดียว, ลบโค้ดที่ถูกคอมเมนต์ การเปลี่ยนแปลงแต่ละครั้งควรเป็น commit แยกต่างหากพร้อมข้อความที่ชัดเจน: “remove unused dependency: gson (replaced by kotlinx.serialization)”, “delete commented code in LoginViewModel.”
ขั้นที่สาม — การตรวจสอบ: บิวด์โปรเจกต์ เรียกใช้การทดสอบ ตรวจสอบ UI ถ้าการทดสอบผ่านหลังจากลบ dependencies แสดงว่า dependencies นั้นไม่จำเป็นจริง ถ้าการทดสอบล้มเหลว แสดงว่ายังมี reference ที่ซ่อนอยู่ซึ่งตัววิเคราะห์แบบ static ตรวจไม่พบ
ขั้นที่สี่ — การป้องกัน: อัปเดต check list การตรวจสอบโค้ด, เพิ่มกฎ “ไม่มี dependencies ใหม่โดยไม่มีเหตุผล” ใน Definition of Done, ตั้งค่าการตรวจสอบอัตโนมัติใน CI การป้องกันเป็นวิธีเดียวที่จะป้องกันไม่ให้จังก์สะสมอีกครั้ง
คำถามที่พบบ่อย
หนี้ทางเทคนิคคือการประนีประนอมอย่างมีสติ (เร็วแต่คุณภาพต่ำ) ที่วางแผนจะแก้ไข จังก์ ไม่ใช่การตัดสินใจอย่างมีสติ แต่เป็นขยะที่สะสม: dependencies ที่เกินมา, โค้ดที่ถูกคอมเมนต์, abstraction ที่ว่างเปล่าที่ไม่มีใครวางแผนหรือต้องการบำรุงรักษา
จังหวะที่เหมาะสมที่สุดคือจัดสรร 10 เปอร์เซ็นต์ของแต่ละ sprint ให้กับการทำความสะอาดทางเทคนิค สิ่งนี้ทำให้จังก์อยู่ภายใต้การควบคุมโดยไม่สะสมมวลวิกฤต ถ้าโปรเจกต์มีจังก์มาก ให้เริ่มด้วย sprint ทำความสะอาดครั้งใหญ่แล้วค่อยเปลี่ยนเป็นจังหวะปกติ
วัดและแสดงตัวเลข: วัดเวลาบิวด์ก่อนและหลังลบ dependencies ที่เกินมา 3–5 ตัว การลดลง 15–30 วินาที ต่อการบิวด์คูณด้วยจำนวนบิวด์ต่อวันให้เวลาที่ทีมประหยัดได้เป็นชั่วโมง ตัวเลขโน้มน้าวใจได้ดีกว่าการเรียกร้องความเป็นระเบียบแบบนามธรรม
ใช่ โดยเฉพาะถ้า dependencies นั้นมี CVE ถึงแม้โปรเจกต์จะเสถียร ช่องโหว่ใน dependencies แบบ transitive ก็เป็น ความเสี่ยงด้านความปลอดภัย นอกจากนี้ เมื่ออัปเดต SDK หรือภาษา dependencies เก่าอาจเข้ากันไม่ได้ และการลบมันก่อนอัปเกรดจะช่วยประหยัดเวลาในการย้ายระบบเป็นชั่วโมง
ทุก TODO ที่ไม่มี ticket คือจังก์ กำหนดกฎ: TODO เขียนในรูปแบบ // TODO(PROJECT-1234): fix ที่เชื่อมโยงกับงานใน tracker เท่านั้น ตรวจสอบ TODO เป็นประจำและปิดอันที่หมดความเกี่ยวข้อง ลบ TODO ที่หมดอายุ — ถ้าปัญหาไม่ปรากฏในหกเดือน มันก็ไม่สำคัญ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม