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

Shipping Is A Feature

จนกว่า​จะ​ส่ง​มอบ ผลิตภัณฑ์​ของ​คุณ​ยัง​ไม่​สร้าง​คุณค่า​ให้​ใคร​เลย

อย่า​ลืม​ข้อเท็จจริง​ที่​ว่า จนกว่า​คุณ​จะ​ส่ง​มอบ (ship) ผลิตภัณฑ์ มัน​ยัง​ไม่​สร้าง​คุณค่า​ให้​ใคร​เลย Joel Spolsky กล่าว​ไว้​ได้​ดี​ว่า:

“โซลูชัน​ที่​ดี 50% ซึ่ง​ผู้คน​ได้​ใช้​จริง แก้​ปัญหา​ได้​มากกว่า​และ​อยู่​รอด​นาน​กว่า​โซลูชัน​ที่​ดี 99% ซึ่ง​ไม่มี​ใคร​ได้​ใช้​เพราะ​มัน​ยัง​อยู่​ใน​แล็บ​ที่​คุณ​คอย​ขัด​เงา​มัน​ไม่​หยุด การ​ส่ง​มอบ​คือ feature feature ที่​สำคัญ​มาก​ด้วย ผลิตภัณฑ์​ของ​คุณ​ต้อง​มี​มัน”

— Joel Spolsky

“Shipping Is A Feature” คือ​หลัก​ปฏิบัติ​ที่​ปฏิบัติ​ต่อ การ​ส่ง​มอบ​ซอฟต์แวร์​ให้​ผู้​ใช้​จริง เสมือน​เป็น​คุณสมบัติ (feature) หนึ่ง​ของ​ผลิตภัณฑ์ ไม่ใช่​แค่​ขั้นตอน​สุดท้าย​ที่​ทำ​เมื่อ “ทุก​อย่าง​พร้อม​แล้ว” ความคิด​เบื้องหลัง​มา​จาก​บทความ “The Duct Tape Programmer” (2009) ของ Joel Spolsky ที่​อ้าง​ถึง​ปรัชญา “Worse is Better” ของ Richard P. Gabriel และ​คำ​พูด​ของ Jamie Zawinski วิศวกร Netscape ที่​ว่า “At the end of the day, ship the fucking thing” — code ที่​ยัง​ไม่​ถูก​ส่ง​มอบ ไม่​ว่า​จะ​เขียน​ได้​สวยงาม​หรือ​สมบูรณ์​แบบ​เพียง​ใด ก็​ยัง​ไม่​สร้าง​มูลค่า​ใด ๆ ให้​กับ​ผู้​ใช้​หรือ​ธุรกิจ​เลย

หลักการ​นี้​เป็น​แนวคิด​เดียว​กับ release early, release often ของ Eric S. Raymond ใน​หนังสือ The Cathedral and the Bazaar (1997) ซึ่ง​เสนอ​ว่าการ​ปล่อย​ซอฟต์แวร์​บ่อย ๆ ทำให้​เกิด​วงจร​ป้อน​กลับ (feedback loop) ที่​แน่น​ระหว่าง​ผู้​พัฒนา​กับ​ผู้​ใช้ และ​ใน​ยุค​ปัจจุบัน​ก็​สอดคล้อง​กับ​แนวคิด Continuous Delivery ของ Martin Fowler ที่​นิยาม​ไว้​ว่า​เป็น​วินัย​การ​พัฒนา​ซอฟต์แวร์​ที่​ทำให้​ระบบ “พร้อม​ปล่อย​ขึ้น production ได้​ทุกเมื่อ” — ประเด็น​ร่วม​กัน​คือ การ​ส่ง​มอบ​ไม่​ควร​เป็น​เหตุการณ์​ที่​น่า​กลัว​หรือ​เกิด​ขึ้น​นาน ๆ ครั้ง แต่​ควร​เป็น​ความ​สามารถ​ที่​ทีม​ฝึกฝน​อยู่​เสมอ

มี​หลาย​ปัจจัย​ที่​ขัด​ขวาง​การ​ส่ง​มอบ หนึ่ง​ใน antipattern ที่​พบ​บ่อย​ที่สุด​คือ feature creep (หรือ scope creep) — การ​เพิ่ม feature “ต้อง​มี” เข้าไปในสโคป​ของ​รี​ลีส​เรื่อย ๆ จน​วัน​ปล่อย​ถูก​เลื่อน​ออก​ไป​ไม่​สิ้นสุด งาน​วิจัย​ของ Project Management Institute พบ​ว่า​โครงการ​ซอฟต์แวร์​กว่า 52% เผชิญ scope creep และ​มัน​เป็น​สาเหตุ​หลัก​ของ​ความ​ล้มเหลว​ราว 43% ของ​โครงการ​ที่​ล้มเหลว สำหรับ​ผลิตภัณฑ์​แบบ Minimum Viable Product (MVP) ปัญหา​นี้​ยิ่ง​รุนแรง เพราะ​คำ​ว่า “Minimum” ใน MVP คือ​สิ่ง​ที่ scope creep ทำลาย​โดยตรง

วิธี​ที่​ได้​ผล​ใน​การ​ป้องกัน feature creep และ​รักษา​วินัย​การ​ส่ง​มอบ​คือ​การ​ตั้ง จังหวะ​การ​ส่ง​มอบ (delivery cadence) ที่​แน่นอน:

  1. กำหนด cadence ร่วม​กัน — ตกลง​กับ​ลูกค้า​และ​ภายใน​ทีม​ว่า​จะ​ปล่อย​ปี​ละ​สอง​ครั้ง ทุก​สี่​เดือน หรือ​ทุก​วัน​พฤหัส​เว้น​สัปดาห์ แล้ว​ยึดมั่น​กับ​มัน​อย่าง​เคร่งครัด
  2. ตัดสโคป ไม่ใช่​เลื่อน​วัน​ที่ — เมื่อ feature ไม่ทัน​กำหนดการ ให้​ตัด​มัน​ออก​จากรี​ลีสนี้​แล้วไป​รอบ​หน้า แทนที่​จะ​เลื่อน​วัน​ปล่อย​ทั้งหมด (แนวทาง​เดียว​กับ Timeboxing)
  3. แตก​งาน​เป็น​ชิ้น​ที่​ปล่อย​ได้​จริง — ใช้ Vertical Slices เพื่อ​ให้​แต่ละ feature เป็น​หน่วย​ที่​สมบูรณ์​และ​ส่ง​มอบ​ได้ที​ละ​ชิ้น แทนที่​จะ​พัฒนา​เป็น layer ที่​ต้อง​รอ​ให้​ทุก​ส่วน​เสร็จ​พร้อม​กัน
  4. ทำให้ deploy เป็น​เรื่อง​ธรรมดา — ลงทุน​ใน automated pipeline (build, test, deploy) เพื่อ​ให้​ทีม​สามารถ​ปล่อย​ซอฟต์แวร์​ได้​ทุกเมื่อ​โดย​ไม่​ต้อง​กังวล ตาม​แนวทาง Continuous Delivery ของ Fowler
  5. ยอมรับ​ความ​ไม่​สมบูรณ์​แบบ — ใช้ Tolerance for Imperfection เป็น​แนวทาง เพื่อ​ไม่​ให้​ทีม​ติด​กับดัก​การ​ขัดเกลา​ไม่รู้​จบ
  6. ใช้ YAGNI ตัด​สิ่ง​ที่​ยัง​ไม่​จำเป็น — ยึด​หลัก YAGNI เพื่อ​ไม่​เพิ่ม feature ที่​ยัง​ไม่มี​ความ​ต้องการ​จริง ๆ เข้าไปในสโคป

แผนภาพ​ต่อ​ไป​นี้​แสดง​วงจร​การ​ตัดสิน​ใจง่าย ๆ เมื่อ feature เสี่ยง​จะ​ทำให้​พลาด cadence ที่​กำหนด​ไว้:

flowchart TD
    Start[กำหนดวันปล่อยตาม cadence] --> Check{feature เสร็จทันไหม}
    Check -->|ทัน| Ship[ส่งมอบตามกำหนด]
    Check -->|ไม่ทัน| Cut[ตัด feature ออกจากสโคป]
    Cut --> Next[ย้ายไปคิวรอบถัดไป]
    Ship --> Feedback[รับ feedback จากผู้ใช้จริง]
    Next --> Ship
    Feedback --> Start

สมมติ​ทีม​กำลัง​จะ​ปล่อย feature export รายงาน​เป็น file และ​มี​คน​เสนอ​ให้​เพิ่ม export เป็น PDF พร้อม watermark แบบ​กำหนด​เอง​ก่อน​วัน​ปล่อย ทีม​สามารถ​ใช้ feature flag เพื่อ “ปิด” feature เสริม​ที่​ยัง​ไม่​พร้อม แล้ว​ส่ง​มอบ​เฉพาะ​สิ่ง​ที่​ทำงาน​ได้​จริง​ตาม​กำหนดการ:

public class ReportExportOptions
{
// feature หลักที่ต้องมีในรีลีสนี้ — พร้อมแล้ว
public bool EnableCsvExport { get; set; } = true;
// feature เสริมที่ยังไม่เสร็จ — ปิดไว้ก่อน เพื่อไม่ให้เลื่อนวันปล่อย
// ย้ายไปทำต่อในรอบถัดไปตาม delivery cadence
public bool EnablePdfWatermarkExport { get; set; } = false;
}
public class ReportExportService
{
private readonly ReportExportOptions _options;
public ReportExportService(ReportExportOptions options)
{
_options = options;
}
public byte[] Export(ReportData data)
{
// ส่งมอบ CSV export ที่ทำงานได้ 100% วันนี้
// ดีกว่ารอ PDF+watermark ที่ยังทำไม่เสร็จ 99%
if (_options.EnableCsvExport)
{
return CsvExporter.Write(data);
}
throw new InvalidOperationException("No export format is enabled.");
}
}

ตัวอย่าง config ที่​ประกาศ cadence และ scope ของ​รี​ลีส​ให้​ทั้ง​ทีม​เห็น​ตรง​กัน:

release:
cadence: "biweekly" # ปล่อยทุก 2 สัปดาห์ ไม่เปลี่ยนแปลงโดยไม่จำเป็น
next-date: "2026-07-30"
scope:
- csv-export # พร้อมแล้ว
deferred:
- pdf-watermark # ยังไม่พร้อม -> เลื่อนไปรอบถัดไป ไม่เลื่อนวันปล่อย

ประโยชน์

  • ผู้​เกี่ยวข้อง​เข้าใจ​ได้​เร็ว​ว่าการ​ที่ feature หนึ่ง​ไม่ทัน​รี​ลีสนี้​ไม่ใช่​เรื่อง​ใหญ่ ถ้า​มัน​ขึ้น​รอบ​หน้าที่​ไม่​ไกล​ได้
  • การ​ปล่อย​ตาม​กำหนด​อย่าง​สม่ำเสมอ​สร้าง​ความ​ไว้​วางใจ​ใน​ความ​สามารถ​ของ​ทีม​ใน​การ​ส่ง​มอบ​ซอฟต์แวร์​ที่​ใช้งาน​ได้​อย่าง​ต่อ​เนื่อง
  • รี​ลีส​ที่​เล็ก​ลง​และ​ถี่​ขึ้น​ลด​ความ​เสี่ยง​ของ​แต่ละ​การ​เปลี่ยนแปลง เพราะ​พื้นที่ diff เล็ก​ลง สืบสวน​ปัญหา​ได้​ง่าย​ขึ้น​เมื่อ​เกิด bug
  • ทีม​ได้​รับ feedback จาก​ผู้​ใช้​จริง​เร็ว​ขึ้น แทนที่​จะ​เดา​ความ​ต้องการ​อยู่​ใน​แล็บ​เป็น​เดือน ๆ
  • ลด feature creep เพราะ​ทุก​คน​รู้​ว่า​สิ่ง​ที่​ไม่ทัน​รอบ​นี้​ยัง​มี​รอบ​หน้า​รอ​อยู่ ไม่​ต้อง​ยัด​ทุก​อย่าง​เข้า​รี​ลีส​เดียว

ข้อ​ควร​ระวัง

  • อย่า​ใช้​หลักการ​นี้​เป็น​ข้อ​อ้าง​ใน​การ​ส่ง​มอบ​ของ​ที่​มี bug ร้ายแรง​หรือ​ไม่​ปลอดภัย — “50% solution” ของ Spolsky หมาย​ถึง feature ที่​ยัง​ไม่​ครบ​สมบูรณ์ ไม่ใช่​ซอฟต์แวร์​ที่​พัง
  • cadence ที่​ตั้ง​ไว้​ต้อง​สมจริง​กับ​ความ​สามารถ​ของ​ทีม การ​บีบ cadence ให้​ถี่​เกิน​ไป​โดย​ไม่มี​ระบบ​ทดสอบ​และ deploy อัตโนมัติ​รองรับ อาจ​นำ​ไป​สู่​หนี้​ทาง​เทคนิค​สะสม
  • ต้อง​แยก​ให้​ชัด​ระหว่าง Continuous Delivery (พร้อม​ปล่อย​ได้​ทุกเมื่อ) กับ Continuous Deployment (ปล่อย​ขึ้น production อัตโนมัติ​ทุก​การ​เปลี่ยนแปลง) — องค์กร​จำนวน​มาก​เลือก​แบบ​แรก​เพราะ​จังหวะ​การ​ปล่อย​ยัง​เป็นการ​ตัดสิน​ใจ​ทาง​ธุรกิจ
  • การตัดสโคป​ต้อง​มี​เกณฑ์​ชัดเจน​ว่า​อะไร “ต้อง​มี” กับ “ควร​มี” ไม่​เช่น​นั้น​ทีม​อาจ​ตัด​สิ่ง​ที่​ผู้​ใช้​ต้องการ​จริง ๆ ออก​ไป​เพื่อ​รักษา​วัน​ที่​เพียง​อย่าง​เดียว