The Law of Diminishing Returns
ยิ่งทุ่มทรัพยากรเพิ่มเข้าไปเรื่อย ๆ ผลตอบแทนส่วนเพิ่มยิ่งลดลง
ใจความสำคัญ
หัวข้อที่มีชื่อว่า “ใจความสำคัญ”กฎว่าด้วยผลตอบแทนที่ลดน้อยถอยลง (Law of Diminishing Returns) มีรากมาจากเศรษฐศาสตร์คลาสสิก แนวคิดนี้ถูกกล่าวถึงครั้งแรก ๆ โดยนักเศรษฐศาสตร์ชาวฝรั่งเศส Jacques Turgot ในศตวรรษที่ 18 และถูกนำมาใช้อย่างเป็นระบบโดย David Ricardo, Thomas Malthus และเพื่อนร่วมสมัยในต้นศตวรรษที่ 19 เมื่อวิเคราะห์ค่าเช่าที่ดินทำการเกษตร
ใจความคือ: เมื่อเพิ่มปัจจัยการผลิตหนึ่งตัวเข้าไปเรื่อย ๆ โดยให้ปัจจัยอื่นคงที่ (เช่น เพิ่มแรงงานลงในที่ดินผืนเดิม) ผลผลิตส่วนเพิ่ม (marginal output) จากหน่วยที่เพิ่มเข้ามาแต่ละหน่วยจะค่อย ๆ ลดลง แม้ผลผลิตรวมอาจยังเพิ่มขึ้นอยู่ก็ตาม พูดอีกแบบคือ “ผลตอบแทนยังเป็นบวก แต่ลดน้อยลงเรื่อย ๆ” — ต่างจากผลตอบแทนติดลบ (negative returns) ซึ่งการเพิ่มปัจจัยกลับทำให้ผลผลิตรวมลดลง
ในเชิงทฤษฎีการผลิต (production theory) เส้นโค้งของผลผลิตส่วนเพิ่มมักถูกแบ่งเป็นสามช่วง: ช่วงแรกผลตอบแทนส่วนเพิ่ม เพิ่มขึ้น (increasing returns — ปัจจัยแรก ๆ ที่ใส่เข้าไปช่วยขจัดคอขวดที่ชัดเจนที่สุดก่อน), ช่วงกลางผลตอบแทนส่วนเพิ่ม ลดลง แต่ยังเป็นบวก (diminishing returns — นี่คือช่วงที่กฎนี้ตั้งชื่อตาม), และช่วงท้ายที่ผลตอบแทนส่วนเพิ่ม ติดลบ (negative returns — การใส่ปัจจัยเพิ่มกลับทำให้ผลผลิตรวมลดลง) ทีมวิศวกรรมที่ดีต้องรู้ว่างานที่ทำอยู่กำลังอยู่ในช่วงไหนของเส้นโค้งนี้
ในการพัฒนาซอฟต์แวร์ กฎนี้ปรากฏชัดในหลายมิติ: การเพิ่มคนเข้าโครงการที่ล่าช้า (เชื่อมโยงโดยตรงกับ Brooks’s Law), การไล่ optimize performance ให้เร็วขึ้นอีกไม่กี่เปอร์เซ็นต์, การไล่ refactor code ให้ “สมบูรณ์แบบ” ขึ้นเรื่อย ๆ, หรือการเพิ่ม test case เพื่อไล่ coverage ให้ถึง 100% — ทุกกรณีมีจุดหนึ่งที่ความพยายามเพิ่มเติมให้ผลตอบแทนน้อยลงจนไม่คุ้มกับต้นทุนที่เสียไป กฎนี้จึงไม่ใช่ข้อห้ามไม่ให้ลงทุนเพิ่ม แต่เป็นคำเตือนให้ ติดตามอัตราผลตอบแทน อยู่เสมอ ไม่ใช่ดูแค่ทิศทาง (เพิ่มขึ้นหรือลดลง) เพียงอย่างเดียว
ความหมายและนัยยะ
หัวข้อที่มีชื่อว่า “ความหมายและนัยยะ”สิ่งสำคัญคือต้องแยกสองแนวคิดที่มักถูกปนกัน:
- Diminishing returns (ผลตอบแทนลดลง) — ผลผลิตส่วนเพิ่มยังเป็นบวก แต่เพิ่มขึ้นในอัตราที่ช้าลงเรื่อย ๆ ต่อหน่วยปัจจัยที่ใส่เข้าไป
- Negative returns (ผลตอบแทนติดลบ) — จุดที่การเพิ่มปัจจัยกลับทำให้ผลผลิตรวม ลดลง ไม่ใช่แค่เพิ่มช้าลง
Brooks’s Law คือตัวอย่างที่ก้าวข้ามจาก diminishing ไปสู่ negative returns ได้ชัดเจนที่สุดในวงการซอฟต์แวร์: การเพิ่มโปรแกรมเมอร์เข้าไปในโครงการที่ล่าช้าอยู่แล้วในช่วงแรกอาจยังช่วยได้บ้าง (แต่ช่วยน้อยลงเรื่อย ๆ ต่อคนที่เพิ่ม) เพราะภาระการสื่อสารระหว่างสมาชิกทีมโตขึ้นแบบ quadratic (ทีม n คนมีคู่การสื่อสารที่เป็นไปได้ประมาณ n คูณ n ลบ 1 หารด้วย 2) จนถึงจุดที่คนใหม่ต้องใช้เวลาของคนเก่าในการสอนงานมากกว่าที่คนใหม่จะผลิตงานได้เอง ผลตอบแทนจึงติดลบ และโครงการยิ่งช้าลงกว่าเดิม
อีกมุมหนึ่งที่เกี่ยวโยงกันคือ Amdahl’s Law ซึ่งอธิบายว่าการเพิ่มจำนวน processor เพื่อเร่งความเร็วโปรแกรมแบบขนานก็เจอผลตอบแทนลดลงเช่นกัน เพราะส่วนของ code ที่ยังต้องรันแบบ sequential (serial fraction) จะกลายเป็นคอขวดที่จำกัดเพดานความเร็วสูงสุด ไม่ว่าจะทุ่ม core เพิ่มอีกกี่ตัวก็ตาม — เป็น version ทางคณิตศาสตร์ที่เข้มงวดกว่าของกฎเดียวกัน
ในเชิงการบริหารทีมและคุณภาพงาน นัยยะที่สำคัญคือ เส้นโค้งของผลตอบแทนไม่ใช่เส้นตรง ทีมที่ไม่ตระหนักถึงเรื่องนี้มักตกหลุมพราง sunk cost fallacy คือทุ่มเวลาต่อไปเพราะ “ลงทุนไปเยอะแล้ว” ทั้งที่ผลตอบแทนส่วนเพิ่มแทบไม่เหลือ หรือกลับกันคือหยุดเร็วเกินไปในจุดที่ยังมีผลตอบแทนคุ้มค่าเหลืออยู่ ทักษะที่แท้จริงจึงไม่ใช่การเดารู้ว่ากฎนี้มีอยู่ (มันมีอยู่เสมอ) แต่คือการ วัดผลตอบแทนส่วนเพิ่มอย่างต่อเนื่อง เพื่อรู้ว่ากำลังอยู่ตรงไหนบนเส้นโค้ง
กฎนี้ยังมีความสัมพันธ์ใกล้ชิดกับหลักการ Pareto (กฎ 80/20) ซึ่งมักถูกอ้างอิงคู่กันในบริบทซอฟต์แวร์: Pareto บอกว่าผลลัพธ์ 80% มักมาจากความพยายามเพียง 20% แรก ส่วนกฎว่าด้วยผลตอบแทนที่ลดลงอธิบาย กลไก ว่าทำไมถึงเป็นเช่นนั้น — เพราะ 20% แรกของความพยายามมักแก้ปัญหาที่ทรงคุณค่าที่สุดก่อน ส่วนความพยายามที่เหลืออีก 80% จึงเหลือแต่ปัญหาที่ให้ผลตอบแทนต่ำลงเรื่อย ๆ ทั้งสองแนวคิดจึงเสริมกันมากกว่าจะแข่งกัน
ตัวอย่างในโลกจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างในโลกจริง”- การเพิ่มคนเข้าโครงการที่ล่าช้า — ตัวอย่างคลาสสิกจาก Fred Brooks ใน The Mythical Man-Month (1975): โครงการ OS/360 ของ IBM ที่ล่าช้าและได้รับการเพิ่มกำลังคนเข้าไปแก้ปัญหา กลับล่าช้าหนักขึ้น เพราะต้นทุนการสื่อสารและการสอนงานคนใหม่กลืนกินผลผลิตที่ควรจะได้เพิ่ม
- Performance tuning — การ optimize จาก baseline ที่แย่มากไปสู่ “เร็วพอใช้” มักได้ผลตอบแทนสูงมากต่อชั่วโมงที่ลงทุน (เช่น แก้ N+1 query, เพิ่ม index) แต่การไล่บีบจาก 95% เร็วขึ้นไปเป็น 99% มักต้องใช้ความพยายามแบบ exponential เพื่อแลกกับเปอร์เซ็นต์ที่เหลือน้อยนิด (สอดคล้องกับหลักการที่ deviq.com อธิบายไว้)
- Test coverage — การเพิ่ม test จาก 0% ไปสู่ 60-70% coverage มักจับ bug สำคัญได้เยอะมาก แต่การไล่ให้ครบ 100% coverage มักหมายถึงการเขียนเทสให้ getter/setter หรือ code boilerplate ที่แทบไม่มีความเสี่ยง ต้นทุนสูงแต่ความเสี่ยงที่ลดได้ต่ำมาก
- Code review — reviewer คนแรกและคนที่สองมักจับปัญหาสำคัญต่างมุมกัน แต่ reviewer คนที่ห้าหรือหกในกลุ่มเดียวกันมักเห็นสิ่งเดียวกันซ้ำ ๆ ผลตอบแทนส่วนเพิ่มจากการเพิ่มผู้รีวิวจึงลดลงเร็ว ขณะที่ต้นทุนด้านเวลาของทุกคนในทีมเพิ่มขึ้นเป็นเส้นตรง
- Amdahl’s Law ในการคำนวณแบบขนาน — ถ้าโปรแกรมมีส่วนที่ต้องรัน sequential อยู่ 10% การเพิ่ม processor จาก 4 เป็น 64 ตัวแทบไม่ทำให้เร็วขึ้นตามสัดส่วนอีกต่อไป เพราะเพดานความเร็วสูงสุดถูกจำกัดด้วยส่วน sequential นั้นเสมอ
- จำนวนผู้เข้าร่วมประชุม — การประชุม design review ที่มีผู้เข้าร่วม 4-6 คนที่เกี่ยวข้องโดยตรงมักให้มุมมองที่หลากหลายและตัดสินใจได้เร็ว แต่เมื่อเพิ่มผู้เข้าร่วมเป็น 15-20 คน แต่ละคนพูดได้น้อยลง การตัดสินใจช้าลง และต้นทุนเวลารวมของทั้งองค์กรพุ่งสูงจนเกินคุณค่าที่ได้ ซึ่งเป็นภาพสะท้อนเดียวกันกับปัญหาความซับซ้อนในการสื่อสารของ Brooks’s Law
- การเพิ่ม QA tester เข้าไปไล่ bug ช่วงใกล้ปล่อยรุ่น — tester คนแรกมักเจอ bug สำคัญเยอะในเวลาสั้น ๆ แต่ยิ่งเพิ่ม tester เข้าไปในพื้นที่ทดสอบเดียวกัน โอกาสเจอ bug ใหม่ต่อคนยิ่งลดลง (ซ้ำกับที่คนอื่นเจอไปแล้ว) ขณะที่ภาระการประสานงานและการจัดการรายงาน bug เพิ่มขึ้นเป็นเส้นตรง
บทเรียนที่นำไปใช้
หัวข้อที่มีชื่อว่า “บทเรียนที่นำไปใช้”- วัดผลตอบแทนส่วนเพิ่ม ไม่ใช่ผลตอบแทนสะสม — ก่อนลงทุนรอบต่อไป (ไม่ว่าจะเป็นคน เวลา หรือ compute) ให้ถามว่า “หน่วยถัดไปที่ใส่เข้าไปจะให้ผลตอบแทนเท่าไร” ไม่ใช่ “รวมทั้งหมดที่ลงทุนไปแล้วได้ผลตอบแทนเท่าไร” — คำถามแรกช่วยตัดสินใจอนาคต คำถามหลังเป็นเพียง sunk cost
- กำหนดเกณฑ์ “พอแล้ว” ล่วงหน้า — เช่น “coverage ที่ 80% ของ business logic หลัก” หรือ “response time ต่ำกว่า 200ms” แทนที่จะไล่ optimize แบบไม่มีเพดาน การมีเกณฑ์ชัดเจนช่วยให้ทีมรู้ว่าเมื่อไรควรหยุดและย้ายความสนใจไปงานอื่นที่ให้ผลตอบแทนสูงกว่า แนวคิดนี้ผูกกับ Tolerance for Imperfection โดยตรง — ยอมรับว่าไม่มีระบบใดสมบูรณ์แบบ และการไล่ตามความสมบูรณ์แบบเกินจุดหนึ่งคือการสิ้นเปลือง
- อย่าขยายทีมเป็นวิธีแก้ปัญหาแรก — เมื่อโครงการล่าช้า สัญชาตญาณแรกมักเป็น “เพิ่มคน” แต่ตาม Brooks’s Law การเพิ่มคนกลางโครงการมักให้ผลตอบแทนติดลบในระยะสั้นเสมอ เพราะต้องเสียเวลาสอนงาน ควรพิจารณาลดขอบเขตงาน (scope) หรือเลื่อนกำหนดส่งก่อน
- ใช้หลักการเดียวกันกับ YAGNI — YAGNI เตือนไม่ให้สร้าง feature หรือ abstraction ล่วงหน้าเพราะผลตอบแทนของความยืดหยุ่นที่ยังไม่ถูกใช้งานจริงมักต่ำมากเมื่อเทียบกับต้นทุนความซับซ้อนที่เพิ่มเข้ามาทันที — เป็นอีกรูปแบบหนึ่งของผลตอบแทนลดลงที่ประเมินล่วงหน้า
- ระวัง sunk cost fallacy — การรู้ตัวว่ากำลังอยู่บนโซนผลตอบแทนต่ำ (หรือติดลบ) ของเส้นโค้ง แล้วยังลงทุนต่อเพราะ “ทำมาเยอะแล้ว” คือกับดักทางจิตวิทยาที่พบบ่อยที่สุดในทีมวิศวกรรม การตัดสินใจที่ดีต้องมองไปข้างหน้า ไม่ใช่มองย้อนหลัง
- Timebox แทนการไล่ตามความสมบูรณ์แบบ — การกำหนดกรอบเวลาตายตัวให้งานประเภท optimize/polish (เช่น “สองวันสำหรับ performance tuning รอบนี้”) บังคับให้ทีมต้องจัดลำดับความสำคัญของสิ่งที่จะทำก่อน แทนที่จะไล่ทำไปเรื่อย ๆ จนกว่าจะ “รู้สึกว่าเสร็จ” ซึ่งมักเลยจุดที่ผลตอบแทนคุ้มค่าไปแล้ว
- แบ่งงานเป็นชิ้นเล็กแล้ว re-prioritize บ่อย ๆ — แทนที่จะทุ่มทีมทั้งหมดไปกับ feature เดียวจนสุดทาง ให้ส่งมอบเป็น vertical slice เล็ก ๆ แล้ววัดผลตอบแทนจริงก่อนตัดสินใจว่าจะลงทุนต่อในทิศทางเดิมหรือย้ายไปทำสิ่งอื่นที่ให้คุณค่าสูงกว่า — แนวคิดนี้เชื่อมโยงกับหลัก Agility โดยตรง
flowchart TD
A[เริ่มลงทุนความพยายามหรือทรัพยากรเพิ่ม] --> B[วัดผลตอบแทนส่วนเพิ่มของหน่วยล่าสุด]
B --> C{ผลตอบแทนส่วนเพิ่มเทียบกับต้นทุนส่วนเพิ่ม}
C -->|ยังคุ้มค่ากว่าต้นทุนชัดเจน| D[ลงทุนต่ออีกหน่วย]
C -->|เริ่มใกล้เคียงกับต้นทุน| E[ทบทวนเกณฑ์พอแล้ว]
C -->|ต่ำกว่าต้นทุน หรือติดลบ| F[หยุด และย้ายไปงานที่ผลตอบแทนสูงกว่า]
D --> B
E --> B