ข้าม​ไป​ยัง​เนื้อหา

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 แบบ:

  1. Cost of build — แรงงาน​ที่​เสีย​ไป​กับ feature ที่สุดท้าย​ไม่มี​ใคร​ใช้
  2. Cost of delay — โอกาส​ที่​เสีย​ไป​เพราะ​เอา​เวลา​ไป​สร้าง​สิ่ง​ที่​ยัง​ไม่​จำเป็น แทนที่​จะ​ส่ง​มอบ​สิ่ง​ที่​ผู้​ใช้​ต้องการ​ตอน​นี้​เร็ว​ขึ้น
  3. 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 บอก​ให้​ตัด​ทิ้ง