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

Death by Planning

วางแผน​จน​ไม่​ได้​ส่ง​มอบ — จำ​ไว้​ว่า “การ​ส่ง​มอบ​คือ feature”

Death by Planning คือ​แอนตี้ pattern ระดับ​การ​บริหาร​โครงการ (management antipattern) ที่​เกิด​ขึ้น​เมื่อ​ทีม​หรือ​ผู้​บริหาร​โครงการ “เอา​แผน​จริงจัง​เกิน​ไป” — พยายาม​คาด​การณ์​และ​จัด​ตาราง​รายละเอียด​ทุก​อย่าง​ล่วงหน้า ทั้ง​ขอบเขต​งาน (scope) ระยะ​เวลา ทรัพยากร และ​ลำดับ​ขั้นตอน ก่อน​ที่​จะ​ลงมือ​เขียน code แม้แต่​บรรทัด​เดียว ผล​คือ​ทีม​พัฒนา​ใช้​เวลา​ส่วน​ใหญ่​ไป​กับ​การ​วางแผน ประชุม เขียน​เอกสาร และ​ปรับปรุง​ตาราง​งาน จน​ไม่​เหลือ​เวลา​พอ​สำหรับ​การ “สร้าง​จริง”

ต้นตอ​ของ​ปัญหา​นี้​มา​จาก​การ​ยืม​กรอบ​คิด​ของ​อุตสาหกรรม​ที่​งาน​คาด​การณ์​ได้​สูง เช่น การ​ก่อสร้าง​หรือ​การ​ผลิต มา​ใช้​กับ​ซอฟต์แวร์ ซึ่ง​โดย​ธรรมชาติ​เต็ม​ไป​ด้วย​สิ่ง​ที่​ไม่รู้ (unknowns) และ​ความ​ไม่​แน่นอน​ที่​ค้น​พบ​ระหว่าง​ทาง การ​วางแผน​แบบ​ละเอียด​ยิบ​ล่วงหน้า​จึง​มัก​ไม่​สอดคล้อง​กับ​ความ​เป็น​จริง​ของ​งาน​พัฒนา​ซอฟต์แวร์

Death by Planning มี​ความ​สัมพันธ์​ใกล้​ชิด​กับ Analysis Paralysis และ Big Design Up Front (BDUF) — ทั้ง​สาม​ล้วน​เป็น​อาการ​ของ​การ “คิดมาก​กว่า​ทำ” แต่ Death by Planning เน้น​เฉพาะ​มิติ​ของ​การ​บริหาร​จัดการ​โครงการ (การ​จัด​ตาราง​งาน การ​ประชุม การ​รี​แพลน​ซ้ำ ๆ) มากกว่า​มิติ​ของ​การ​ออกแบบ​ทาง​เทคนิค​หรือ​การ​วิเคราะห์​ความ​ต้องการ

การ​วางแผน​ละเอียด​ดู​สม​เหตุ​สม​ผล​เพราะ:

  • ให้​ความ​รู้สึก​ควบคุม​ได้ ผู้​บริหาร​และ​ผู้​มี​ส่วน​ได้​ส่วน​เสีย​อยาก​เห็น​ตาราง​งาน วัน​ส่ง​มอบ และ​งบประมาณ​ที่​ชัดเจน​ตั้งแต่​ต้น การ​มี​แผน​ละเอียด​ทำให้​รู้สึก​ว่า​ความ​เสี่ยง​ถูก​จัดการ​แล้ว
  • อ้างอิง​ต้นทุน​ของ​การ​เปลี่ยนแปลง แนวคิด​ดั้งเดิม​เชื่อ​ว่า​เส้น​โค้ง​ต้นทุน​ของ​การ​แก้ไข (cost-of-change curve) พุ่ง​ขึ้น​แบบ​ทวีคูณ — ความ​ผิดพลาด​ที่​แก้​ตอน​วิเคราะห์​ราคา​ถูก​กว่า​การ​แก้​ตอน production มาก ดังนั้น​การ​คิด​ให้​รอบคอบ​ก่อน​ลงมือ​จึง​ดูเหมือน​เป็นการ​ลงทุน​ที่​คุ้ม​ค่า
  • ลด​ความ​กลัว​การ​ทำ​ผิดพลาด​ที่​แก้​ยาก โดย​เฉพาะ​ใน​โครงการ​ขนาด​ใหญ่ หรือ​ระบบ​ที่​เปลี่ยนแปลง​ยาก (เช่น ฮาร์ดแวร์​ฝัง​ตัว หรือ​ระบบ​เก่า​ที่ deploy ยาก) การ​วางแผน​ล่วงหน้า​จึง​ดู​เป็นการ​ป้องกัน​ความ​เสี่ยง​ที่​สม​เหตุ​สม​ผล
  • สอดคล้อง​กับ​วัฒนธรรม​องค์กร​ที่​เน้น​ความ​รับผิดชอบ (accountability) แผนที่​ละเอียด​ทำให้​ตรวจสอบ​ความ​คืบ​หน้า​ได้​ง่าย และ​ดูเหมือน​สร้าง​ความ​โปร่งใส​ให้​ผู้​บริหาร​ระดับ​สูง

ปัญหา​คือ​ซอฟต์แวร์​ไม่​ได้​มี​ลักษณะ​เหมือน​งาน​ก่อสร้าง​ที่​ทำนาย​ได้​แม่นยำ:

  • ต้นทุน​ของ​การ​วางแผน​สะสม​โดย​ไม่​สร้าง​คุณค่า ทุก​ชั่วโมง​ที่​ใช้​วางแผน​คือ​ชั่วโมง​ที่​ไม่​ได้​ใช้​สร้าง​ซอฟต์แวร์​ที่​ใช้งาน​ได้​จริง และ​อย่า​ลืม​ว่าการ​ประชุม 6 คน​หนึ่ง​ชั่วโมง​มี​ต้นทุน​ต่อ​บริษัท​ไม่​น้อย​เลย — ยิ่ง​ประชุม​วางแผน​บ่อย​และ​นาน​เท่าไร ต้นทุน​แฝง​นี้​ก็​ยิ่ง​สูง​ขึ้น
  • แผน​ล้าสมัย​เร็ว​กว่า​ที่​คิด ความ​ต้องการ​ทาง​ธุรกิจ​เปลี่ยนแปลง​เร็ว​กว่า​ที่​โครงการ​ขนาด​ใหญ่​จะ​ทำ​เสร็จ ทำให้​แผนที่ “สมบูรณ์​แบบ” ณ วัน​แรก​กลาย​เป็น​สิ่ง​ล้าสมัย​ก่อน​ถึง​วัน​ส่ง​มอบ​จริง
  • ขาด feedback loop จาก​ของ​จริง การ​วางแผน​ล้วน ๆ ไม่มี​การ implement หรือ deploy มา​ยืนยัน​สมมติฐาน ทำให้​ทีม​ค้น​พบ​ปัญหา​ช้า​เกิน​ไป เมื่อ​ค้น​พบ​ก็​ต้อง​รี​แพลน​ใหม่ วน​เป็น​วงจร​ไม่รู้​จบ
  • บั่นทอน​ขวัญ​กำลังใจ​ทีม​พัฒนา เมื่อ​ทีม​เห็น​ว่า​งาน​ของ​ตัวเอง​คือ​การ​นั่ง​ประชุม​และ​ปรับ​ตาราง​งาน​ซ้ำ ๆ แทนที่​จะ​ได้​เห็น​ผล​งาน​จริง​ถูก​ใช้งาน แรง​จูงใจ​ใน​การ​ทำงาน​ก็​ลด​ลง
  • สมมติฐาน​ที่​ผิด​เกี่ยว​กับ​ความ​สามารถ​ใน​การ​คาด​การณ์ งาน​ซอฟต์แวร์​เต็ม​ไป​ด้วย​สิ่ง​ไม่รู้ (unknown unknowns) การ​พยายาม​กำหนด​ทุก​รายละเอียด​ล่วงหน้า​จึง​มัก​อิง​อยู่​บน​สมมติฐาน​ที่​ผิด​ตั้งแต่​ต้น และ​แผนที่​ดู​ละเอียด​ยิบ​กลับ​ยิ่ง​เปราะบาง​เมื่อ​ความ​จริง​ไม่​ตรง​กับ​ที่​วาง​ไว้

สมมติ​ทีม​กำลัง​จะ​สร้าง​ระบบ​จัดการ​คำ​สั่ง​ซื้อ (order management) ใหม่ ภาย​ใต้​อิทธิพล​ของ Death by Planning ทีม​อาจ​ใช้​เวลา​หลาย​สัปดาห์​เขียน​เอกสาร spec interface ทุก​ตัว​ไว้​ล่วงหน้า ก่อน​ที่​จะ​รู้​ด้วย​ซ้ำ​ว่า workflow จริง​ของ​ธุรกิจ​เป็น​อย่างไร

// แอนตี้ pattern: interface ถูกออกแบบละเอียดยิบล่วงหน้า
// ตาม spec ที่ผ่านการประชุมวางแผน 3 เดือน โดยยังไม่เคยรัน
// code จริงหรือคุยกับผู้ใช้งานเลยสักครั้ง
public interface IOrderProcessingPipeline
{
ValidationResult ValidateOrder(Order order, ValidationRuleSet rules);
PricingResult ApplyPricingRules(Order order, PricingContext context);
InventoryReservation ReserveInventory(Order order, WarehouseSelectionStrategy strategy);
PaymentAuthorization AuthorizePayment(Order order, PaymentGatewayConfig config);
ShippingLabel GenerateShippingLabel(Order order, CarrierNegotiationResult carrier);
// ...อีก 12 method ที่ระบุไว้ในเอกสาร spec 40 หน้า
}
// สามเดือนต่อมา เมื่อเริ่ม implement จริง ทีมพบว่า
// ธุรกิจไม่มี "WarehouseSelectionStrategy" แบบที่วางแผนไว้
// เพราะมีคลังสินค้าเดียว และ "CarrierNegotiationResult"
// ก็ไม่เคยถูกใช้เพราะบริษัทใช้ผู้ให้บริการขนส่งรายเดียว
// ต้องรื้อ spec ทั้งหมดใหม่ ก่อนจะเขียน code ได้แม้แต่บรรทัดแรก

ใน​ทาง​กลับ​กัน ทีม​ที่​หลีก​เลี่ยง Death by Planning จะ​วางแผน​แค่​พอ​ให้​เริ่ม​งาน​ได้ และ​ปล่อย​ให้​รายละเอียด​ค่อย ๆ ชัดเจน​ขึ้น​จาก​การ implement จริง:

// ทางแก้: เริ่มจาก interface ขั้นต่ำที่จำเป็นต่อ use case แรก
// แล้วปล่อยให้ขยายตามความต้องการจริงที่พิสูจน์แล้วว่ามีอยู่
public interface IOrderProcessor
{
OrderResult Process(Order order);
}
public class OrderProcessor : IOrderProcessor
{
public OrderResult Process(Order order)
{
// เริ่มจาก flow ง่ายที่สุดที่ยัง deliver คุณค่าได้จริง
// ตรวจสอบ, จองสต๊อก, และเรียกเก็บเงิน
// เพิ่ม pricing rules, ผู้ให้บริการขนส่งหลายราย ฯลฯ
// ในภายหลังเมื่อธุรกิจต้องการจริง ๆ (ดู YAGNI)
return new OrderResult(OrderStatus.Confirmed);
}
}

แนวทาง​นี้​สอดคล้อง​กับ​สิ่ง​ที่ Martin Fowler เรียก​ว่า evolutionary design — ให้​สถาปัตยกรรม​ค่อย ๆ ปรากฏ​ขึ้น​จาก​การ implement จริง แทนที่​จะ​กำหนด​ไว้​ตายตัว​ล่วงหน้า​เหมือน​แบบแปลน​ตึก​ที่​ต้อง​สมบูรณ์​ก่อน​ก่อสร้าง

หลักการ​สำคัญ​คือ ให้​แผน​ระยะ​สั้น​ใกล้​เคียง​กับ​การ implement จริง​ที่สุด และ​ให้​แผน​ระยะ​ยาว​คลุมเครือ​และ​ยืดหยุ่น​ที่สุด วิธี​ปฏิบัติ​ที่​ช่วย​ได้:

  1. แบ่ง​งาน​เป็น​ชิ้น​เล็ก แล้ว​ส่ง​มอบ​เป็น​รอบ​สั้น ๆ — แนวทาง​ที่​อุตสาหกรรม​เรียก​กัน​ว่า iterative development หรือ Agile นี่​คือ​คำ​ตอบ​โดยตรง​ต่อ Death by Planning เมื่อ​รอบ​วางแผน-สร้าง-ส่ง​มอบ​สั้น​ลง ต้นทุน​ของ​การ​วางแผน​ผิด​ก็​เล็ก​ลง​ตาม​ไป​ด้วย
  2. จำ​ไว้​ว่า Shipping Is A Feature — การ​ส่ง​มอบ​ของ​จริง​ให้​ผู้​ใช้​เห็น​และ​ใช้งาน​ได้ มี​ค่า​มากกว่า​การ​มี​แผนที่​สมบูรณ์​แบบ​บน​กระดาษ
  3. Update the Plan อย่าง​สม่ำเสมอ​แทน​การ​วางแผน​ใหญ่​ครั้ง​เดียว — ปรับ​แผน​เป็น​ระยะ​สั้น ๆ ตาม​ข้อมูล​จริง​ที่​ได้​จาก​การ​ส่ง​มอบ​รอบ​ก่อนหน้า แทนที่​จะ​พยายาม​คาด​การณ์​ทุก​อย่าง​ตั้งแต่​วัน​แรก
  4. ใช้ YAGNI — อย่า​ออกแบบ​หรือ​วางแผน​รองรับ feature ที่​ยัง​ไม่​พิสูจน์​ว่า​จำเป็น​จริง ลด​ขอบเขต​ของ​สิ่ง​ที่​ต้อง​วางแผน​ลง​ไป​ใน​ตัว
  5. ลด​ต้นทุน​การ​ประชุม — จำกัด​จำนวน​คน​และ​เวลา​ของ​การ​ประชุม​วางแผน ตั้ง​คำถาม​เสมอ​ว่า “การ​ประชุม​นี้​คุ้ม​กับ​เวลา​ที่​ใช้​ไป​หรือ​ไม่ เทียบ​กับ​การ​เอา​เวลา​นั้น​ไป​สร้าง​ของ​จริง”
  6. ลงทุน​ใน practice ที่​ทำให้ evolutionary design ปลอดภัย — automated test, continuous integration และ​การ refactor ที่​ดี ช่วย​ทำให้​เส้น​โค้ง​ต้นทุน​ของ​การ​เปลี่ยนแปลง (cost-of-change curve) แบน​ราบ​ลง ทำให้​ทีม​กล้า​เริ่ม​สร้าง​โดย​ไม่​ต้อง​วางแผน​ทุก​รายละเอียด​ล่วงหน้า เพราะ​มั่นใจ​ว่า​แก้ไข​ทีหลัง​ได้​โดย​ไม่​แพง​เกิน​ไป
flowchart TD
    Start[เริ่มโครงการ] --> ShortPlan[วางแผนระยะสั้น ใกล้ implementation]
    ShortPlan --> Build[สร้างและส่งมอบชิ้นเล็ก]
    Build --> Feedback[รับ feedback จากของจริง]
    Feedback --> UpdatePlan[ปรับปรุงแผนตามข้อมูลจริง]
    UpdatePlan --> ShortPlan
    LongPlan[แผนระยะยาว คลุมเครือและยืดหยุ่น] -.-> ShortPlan