YAGNI
You Aren’t Gonna Need It — คุณยังไม่ต้องใช้มันหรอก
แนวคิดหลัก
หัวข้อที่มีชื่อว่า “แนวคิดหลัก”YAGNI หรือ “You Aren’t Gonna Need It” (“คุณจะยังไม่ต้องใช้มันหรอก”) ถือกำเนิดขึ้นเป็นหนึ่งในหลักการสำคัญของ Extreme Programming (XP) โดย Ron Jeffries หนึ่งในผู้ร่วมก่อตั้ง XP สรุปหลักการนี้ไว้อย่างกระชับว่า:
จง implement สิ่งต่าง ๆ เมื่อคุณ ต้องใช้มันจริง ๆ เท่านั้น อย่า implement เพียงเพราะคุณ คาดการณ์ ว่า อาจจะต้องใช้
หลักการนี้มาจากบท “Simple Design” ใน XP และเป็นแรงขับเคลื่อนของแนวปฏิบัติ “Do The Simplest Thing That Could Possibly Work” (DTSTTCPW) กล่าวคือ เมื่อต้องเลือกระหว่างการออกแบบที่ครอบคลุมกรณีในอนาคตกับการออกแบบที่ตอบโจทย์เฉพาะสิ่งที่ต้องการตอนนี้ ให้เลือกอย่างหลัง
Martin Fowler ชี้ให้เห็นสิ่งสำคัญที่มักถูกเข้าใจผิด นั่นคือ YAGNI ใช้ได้กับความสามารถ (capability) ที่สร้างขึ้นเพื่อรองรับ feature ที่ยังไม่ได้ถูกใช้งานจริงเท่านั้น — มันไม่ได้ครอบคลุมความพยายามที่ทำให้ code เปลี่ยนแปลงได้ง่ายขึ้น เช่น refactoring, การเขียน automated test, หรือการวาง continuous integration/delivery สิ่งเหล่านี้ไม่ใช่การเดา feature อนาคต แต่เป็นการลงทุนใน “ความยืดหยุ่นของ code” ซึ่งจำเป็นต่อการที่ YAGNI จะใช้ได้ผลตั้งแต่แรก — code ที่แก้ไขยากจะทำให้ “ค่อยเพิ่มทีหลัง” กลายเป็นเรื่องเจ็บปวด
Fowler แจกแจงต้นทุนของการสร้าง feature ล่วงหน้า (speculative feature) ไว้ 3 แบบ:
- Cost of build — แรงงานที่เสียไปกับ feature ที่สุดท้ายไม่มีใครใช้
- Cost of delay — โอกาสที่เสียไปเพราะเอาเวลาไปสร้างสิ่งที่ยังไม่จำเป็น แทนที่จะส่งมอบสิ่งที่ผู้ใช้ต้องการตอนนี้เร็วขึ้น
- Cost of carry — ความซับซ้อนส่วนเกินที่ต้องแบกไว้ตลอดอายุของ code ทำให้การเพิ่ม feature อื่น ๆ ในอนาคตช้าลง
ในบางแง่ YAGNI คล้ายกับการผลิตแบบ Just-In-Time (JIT) แทนที่จะสั่งชิ้นส่วนจำนวนมากตามที่คิดว่าอาจต้องใช้ ก็รอคำสั่งซื้อจริงจากลูกค้าและทำให้กระบวนการ lean พอที่จะดึงคำสั่งซื้อผ่าน supply chain ได้เร็วพอจะสนองลูกค้า เช่นเดียวกับที่ JIT ทำงานได้ดีเฉพาะในองค์กรที่มีวินัยพอจะยึดหลัก lean YAGNI ก็ทำงานได้ดีที่สุดในสภาพแวดล้อมที่รักษา code ให้ modify ได้ง่าย หาก code กลายเป็น spaghetti ไปแล้ว การเพิ่ม feature ทีหลังก็จะแพงกว่าที่ควร
ทำไมถึงสำคัญ
หัวข้อที่มีชื่อว่า “ทำไมถึงสำคัญ”มีเหตุผลหลายข้อที่ทำให้ YAGNI เป็นหลักการที่คุ้มค่าปฏิบัติตาม:
- ลด waste — feature ที่ไม่จำเป็นจริง ๆ เป็นแหล่งความสูญเปล่ามหาศาล ทั้งในการพัฒนา การดูแลรักษา และในภาระที่ผู้ใช้ต้องเรียนรู้และใช้งานมันด้วย
- ประหยัดเวลาได้จริง — Ron Jeffries ชี้ปัญหาเชิงตรรกะไว้ว่า คุณจะประหยัดเวลาได้จากการทำล่วงหน้าก็ต่อเมื่อการ implement ทีหลังใช้เวลานานกว่าตอนนี้เท่านั้น แต่ project ส่วนใหญ่มีงานเร่งด่วนล้นมืออยู่แล้ว การเผื่ออนาคตจึงมักแย่งเวลาจากสิ่งที่ต้องทำจริงตอนนี้
- code สะอาดกว่า — การเดา feature อนาคตมักเดาผิด (บางส่วนหรือทั้งหมด) และ “การเดาที่ผิด” เหล่านั้นจะฝังตัวอยู่ใน code เป็นภาระต่อไปเรื่อย ๆ แม้ไม่มีใครใช้งานมันจริง
- เมื่อถึงเวลาต้องใช้จริง คุณจะออกแบบได้ดีกว่า — ความเข้าใจ requirement ที่แท้จริงเมื่อถึงเวลาต้องสร้าง feature นั้น มักดีกว่าความเข้าใจตอนพยายามหยั่งรู้ล่วงหน้าตั้งแต่ต้น project มาก
- สอดคล้องกับ agile/lean — YAGNI สนับสนุนการส่งมอบคุณค่าทีละน้อยและปรับตัวตาม feedback แทนที่จะพยายาม design ทุกอย่างไว้ล่วงหน้าแบบ waterfall
Fowler ยังยอมรับว่า YAGNI-failure (กรณีที่ไม่สร้างล่วงหน้าแล้วภายหลังเจ็บตัวจริง) เกิดขึ้นได้และมีค่าใช้จ่ายสูงเมื่อเกิด แต่เขาชี้ว่ากรณีเหล่านี้เกิดขึ้นไม่บ่อยเมื่อเทียบกับผลประโยชน์ที่ YAGNI ให้โดยรวม เพียงแต่ความล้มเหลวมักจำง่ายกว่า (availability bias) จึงดูเหมือนเกิดบ่อยกว่าความเป็นจริง
ข้อควรระวังที่ชุมชน XP เองก็ยอมรับ (จาก c2 wiki) คือมีบางกรณีที่การเผื่อไว้ล่วงหน้าคุ้มค่าจริง เช่น การรองรับ internationalization หรือการออกแบบโครงสร้างข้อมูลให้ขยายได้ในภายหลัง แต่ข้อยกเว้นเหล่านี้ควรเป็นข้อยกเว้นที่ใช้วิจารณญาณ ไม่ใช่ข้ออ้างให้ทิ้งหลักการไปเลย
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”สมมติทีมกำลังสร้างระบบคำนวณราคาสินค้า (pricing) และ product owner บอกว่า “อนาคตอาจจะต้องรองรับหลายสกุลเงิน” — การละเมิด YAGNI คือรีบสร้าง abstraction ที่ซับซ้อนสำหรับ multi-currency ทั้งที่ตอนนี้ระบบขายแค่สกุลเงินเดียว:
// ละเมิด YAGNI — เผื่ออนาคตที่ยังไม่มีจริง เพิ่ม complexity// โดยไม่มี requirement หรือ test ใด ๆ รองรับมันตอนนี้public class PriceCalculator{ private readonly ICurrencyConverter _converter; private readonly IExchangeRateProvider _rateProvider; private readonly ICurrencyFormattingStrategyFactory _formatFactory;
public PriceCalculator( ICurrencyConverter converter, IExchangeRateProvider rateProvider, ICurrencyFormattingStrategyFactory formatFactory) { _converter = converter; _rateProvider = rateProvider; _formatFactory = formatFactory; }
// รองรับแปลงหลายสกุลเงิน คำนวณ rounding ตาม locale ฯลฯ // ทั้งที่ระบบจริงขายเฉพาะ THB สกุลเดียวและไม่มีแผนขยายในเร็ว ๆ นี้ public Money CalculateTotal(Order order, string targetCurrency) { var rate = _rateProvider.GetRate("THB", targetCurrency); var strategy = _formatFactory.Create(targetCurrency); var subtotal = order.Items.Sum(i => i.Price * i.Quantity); return _converter.Convert(subtotal, rate, strategy); }}// ทำตาม YAGNI — แก้ปัญหาที่มีอยู่จริงตอนนี้ให้ดีที่สุด// เขียน test ครอบคลุม ทำให้ refactor ได้ง่าย เมื่อ requirement// multi-currency เข้ามาจริง ค่อยขยายจากฐานที่สะอาดนี้public class PriceCalculator{ public decimal CalculateTotal(Order order) { return order.Items.Sum(item => item.Price * item.Quantity); }}ข้อสังเกตสำคัญ: code ฝั่ง YAGNI ไม่ได้ “ปิดประตู” ไม่ให้รองรับ multi-currency ในอนาคต — มันแค่ไม่จ่ายต้นทุนของความซับซ้อนนั้นตอนนี้ เพราะยังไม่มี requirement จริงมารองรับการตัดสินใจออกแบบใด ๆ เมื่อ requirement มาจริง (พร้อม test cases และ business rules ที่ชัดเจน) การเพิ่ม abstraction ที่เหมาะสมจะทำได้ง่ายกว่ามาก เพราะทีมเข้าใจปัญหาจริงแล้ว ไม่ใช่แค่เดา
สัญญาณว่ากำลังละเมิดหลักการนี้
หัวข้อที่มีชื่อว่า “สัญญาณว่ากำลังละเมิดหลักการนี้”- เพิ่ม parameter, configuration flag, หรือ extension point เพราะ “เผื่อไว้” โดยไม่มี use case ปัจจุบันรองรับ
- สร้าง interface หรือ abstraction layer สำหรับ implementation เดียวที่มีอยู่ เพียงเพราะ “อนาคตอาจมี implementation อื่น”
- เขียน field, table column หรือ API field ที่ยังไม่มี code ส่วนไหนอ่านหรือเขียนค่าไปใช้จริง
- ออกแบบ plugin architecture หรือ generic framework ทั้งที่ระบบมี use case เดียวและไม่มีสัญญาณว่าจะขยาย
- เถียงในที่ประชุม design ด้วยประโยค “เผื่อในอนาคต…” โดยไม่มี requirement, deadline หรือ stakeholder ที่ยืนยันความต้องการนั้นจริง
- มี method หรือ class ที่ไม่มีใคร call ใช้เลย (dead code ที่หลงเหลือจากการเผื่ออนาคต) — c2 wiki แนะนำให้ลบทิ้งทันทีที่พบ
- สับสนระหว่าง YAGNI กับการละเลยคุณภาพ code: ใช้ YAGNI เป็นข้ออ้างไม่เขียน test หรือไม่ refactor — ทั้งที่จริง ๆ แล้วสิ่งเหล่านี้คือสิ่งที่ทำให้ YAGNI ใช้ได้ผลตั้งแต่แรก ไม่ใช่สิ่งที่ YAGNI บอกให้ตัดทิ้ง
ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”- Keep It Simple, Stupid — KISS
- Don’t Repeat Yourself — DRY
- Test-Driven Development
- Refactoring
- Simple Design
- Tolerance for Imperfection
แหล่งอ้างอิง
หัวข้อที่มีชื่อว่า “แหล่งอ้างอิง”- ที่มา · deviq.com/principles/yagni
- Martin Fowler — bliki: Yagni
- Wikipedia — You aren’t gonna need it
- C2 Wiki — YouArentGonnaNeedIt
- 2016 / 2013 Software Craftsmanship Calendar