Assumption Driven Programming
สมมติว่าผู้ใช้ทุกคนคิดและทำเหมือนตัวนักพัฒนา
ปัญหาคืออะไร
หัวข้อที่มีชื่อว่า “ปัญหาคืออะไร”Assumption Driven Programming คือภาวะที่นักพัฒนาตัดสินใจเรื่องพฤติกรรมของผู้ใช้ กติกาของข้อมูล หรือ flow การทำงาน โดยอิงจาก “ถ้าเป็นฉัน ฉันจะทำแบบนี้” แทนที่จะอิงข้อมูลจริงจากผู้ใช้ ปัญหาไม่ได้อยู่ที่การมีสมมติฐาน — ทุกการตัดสินใจในงานซอฟต์แวร์ล้วนมีสมมติฐานแฝงอยู่บ้าง — แต่อยู่ที่การ ไม่รู้ตัวว่ากำลังสมมติ และไม่เคยตรวจสอบสมมติฐานนั้นกับความเป็นจริง
มันแทรกอยู่ในทุกระดับ ตั้งแต่กติกาตรวจสอบข้อมูล (validation) เช่น สมมติว่าชื่อคนทุกคนเขียนด้วย ASCII และแยกชื่อ-นามสกุลชัดเจน ไปจนถึงการออกแบบ flow ของหน้าจอที่สมมติว่าผู้ใช้จะเดินตามเส้นทางที่นักพัฒนาคิดไว้ในหัว หรือแม้แต่การตีความกฎธุรกิจใน domain โดยไม่เคยถามผู้เชี่ยวชาญ domain จริง ๆ
วิธีเลี่ยงกับดักนี้คือการมีปฏิสัมพันธ์กับผู้ใช้ให้มากที่สุด สำคัญที่จะ dogfood ซอฟต์แวร์ของตน แต่ไม่ใช่แทนการดูว่าลูกค้าจริงใช้มันอย่างไร ผู้ใช้ app ของคุณไม่จำเป็นต้องทำอย่างที่คุณทำหรือที่คุณคิดว่าเขาควรทำ
ทำไมถึงดูน่าใช้
หัวข้อที่มีชื่อว่า “ทำไมถึงดูน่าใช้”- เร็วกว่า — ไม่ต้องรอ stakeholder รอบ review หรือรอบสัมภาษณ์ผู้ใช้ ตัดสินใจได้ทันทีระหว่างเขียน code
- รู้สึกมั่นใจ — นักพัฒนาคือคนที่เข้าใจระบบลึกที่สุดในทีม จึงรู้สึกว่าสัญชาตญาณของตัวเองน่าเชื่อถือ นี่คือรากของอคติที่เรียกว่า false-consensus effect ซึ่งงานวิจัยของ Nielsen Norman Group ชี้ว่าคนเรามักเชื่อว่าคนอื่นคิดและทำเหมือนตัวเองมากกว่าความเป็นจริง
- Dogfooding ให้ความรู้สึกปลอดภัยลวง — เมื่อทีมใช้ซอฟต์แวร์ของตัวเองทุกวันแล้วไม่เจอปัญหา ก็ง่ายที่จะสรุปว่าผู้ใช้ทั่วไปก็จะไม่เจอปัญหาเหมือนกัน ทั้งที่ทีมพัฒนารู้ domain ทนกับ rough edge ได้ และใช้งานในบริบทที่ต่างจากผู้ใช้จริงอย่างมาก
- แรงกดดันเรื่องเวลา — ภายใต้ deadline การเขียน spec แบบ “เดาว่าคงจะโอเค” ดูเหมือนถูกกว่าการรอ validate กับผู้ใช้จริง โดยเฉพาะเมื่อ requirement ดูเหมือน “สามัญสำนึก” อยู่แล้ว
ทำไมถึงเป็นปัญหา
หัวข้อที่มีชื่อว่า “ทำไมถึงเป็นปัญหา”สมมติฐานที่ไม่ได้ตรวจสอบจะถูกฝังลงไปใน code จริง กลายเป็น constraint ที่แข็งเป็นหิน แต่ไม่มีใครตั้งคำถามอีก จนกว่าผู้ใช้จริงจะไปเจอขอบ (edge) ที่สมมติฐานนั้นพัง — ซึ่งตอนนั้นมันขึ้น production ไปแล้ว และการแก้ไขแพงกว่าตอนออกแบบมาก
ตัวอย่างคลาสสิกคือชุดบทความ “Falsehoods Programmers Believe About Names” ของ Patrick McKenzie ที่รวบรวมสมมติฐานผิด ๆ เกี่ยวกับชื่อคน เช่น ชื่อทุกคนเขียนด้วยตัวอักษร ASCII, ชื่อมีความยาวจำกัดในช่วงที่คาดไว้, ทุกคนมีชื่อ-นามสกุลแยกกันชัดเจน และในสังคมเดียวกันทุกคนเห็นพ้องกับมาตรฐานการเขียนชื่อแบบเดียวกัน — ทั้งหมดนี้ล้วนมาจากนักพัฒนาที่มองโลกผ่านประสบการณ์ชื่อของตัวเองแล้วขยายผลไปทั้งโลก โครงการ awesome-falsehood บน GitHub ยังรวบรวมรายการแบบเดียวกันในหัวข้ออื่น ๆ เช่น ที่อยู่ เบอร์โทร เวลา และสกุลเงิน แสดงให้เห็นว่าอคตินี้เกิดซ้ำ ๆ ในทุก domain
Nielsen Norman Group อธิบายว่านี่คือ false-consensus effect ซึ่งเป็นอคติทางความคิดที่ทำให้เราประเมินสูงเกินไปว่าคนอื่นเชื่อและทำเหมือนที่เราเชื่อและทำ นักออกแบบและนักพัฒนาที่ตกอยู่ในอคตินี้มักมองว่า interface ของตัวเอง “เข้าใจง่ายอยู่แล้ว” เพราะมันเข้าใจง่ายสำหรับตัวเอง แล้วตัดสินว่าผู้ใช้ที่สับสนคือคนที่ “ใช้ผิด” ทั้งที่จริงปัญหาอยู่ที่การออกแบบ
อันตรายอีกชั้นคือสมมติฐานสะสมกันแบบเงียบ ๆ — แต่ละจุดตัดสินใจที่ไม่ถูกตรวจสอบเพิ่มระยะห่างระหว่าง model ในหัวนักพัฒนากับพฤติกรรมจริงของผู้ใช้ทีละนิด จนวันหนึ่งช่องว่างนั้นใหญ่เกินกว่าจะแก้ด้วยการปรับเล็กน้อย ต้องรื้อออกแบบใหม่ทั้ง feature ซึ่งเป็นต้นทุนที่ป้องกันได้ตั้งแต่ต้นถ้าตรวจสอบสมมติฐานเนิ่น ๆ
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”code ต่อไปนี้ฝังสมมติฐานส่วนตัวของนักพัฒนาไว้โดยไม่รู้ตัว ทั้งเรื่องรูปแบบชื่อและสกุลเงิน:
// สมมติฐาน: ชื่อผู้ใช้ทุกคนเขียนด้วยตัวอักษร ASCII และมี "ชื่อ" กับ "นามสกุล" แยกกันชัดเจนpublic class CustomerNameValidator{ private static readonly Regex NamePattern = new(@"^[A-Za-z]+\s[A-Za-z]+$");
public bool IsValid(string fullName) => NamePattern.IsMatch(fullName);}
public class CheckoutService{ public OrderConfirmation Checkout(Order order) { // สมมติฐาน: ลูกค้าทุกคนจ่ายด้วยสกุลเงิน USD เท่านั้น เพราะทีมพัฒนานั่งอยู่ในสหรัฐฯ var totalUsd = order.Items.Sum(i => i.PriceUsd * i.Quantity); return new OrderConfirmation(totalUsd, "USD"); }}ผลคือผู้ใช้ที่ชื่อมีคำเดียว (เช่นชื่อไทยหลายคน) หรือเขียนด้วยอักษรที่ไม่ใช่ละติน จะถูกปฏิเสธที่หน้าสมัครสมาชิกทันที และลูกค้านอกสหรัฐฯ จะเห็นยอดเป็น USD ที่ไม่ตรงกับสิ่งที่ธนาคารของตัวเองเรียกเก็บ — ทั้งสองจุดไม่เคยถูกตั้งเป็นคำถามที่ต้องตรวจสอบเลย เพราะ “ดูเป็นสามัญสำนึก” สำหรับทีมที่เขียนมันขึ้นมา
refactor ให้สมมติฐานกลายเป็นสิ่งที่ตรวจสอบได้และอิงข้อมูลจริง แทนที่จะ hardcode ความเชื่อส่วนตัว:
public class CustomerNameValidator{ // ไม่บังคับรูปแบบชื่อ ปล่อยกว้างที่สุดเท่าที่ระบบ downstream รองรับได้ // ค่า MaxNameLength มาจากการสำรวจความยาวชื่อจริงของผู้ใช้ ไม่ใช่ค่าที่เดาเอาเอง private const int MaxNameLength = 200;
public bool IsValid(string fullName) => !string.IsNullOrWhiteSpace(fullName) && fullName.Length <= MaxNameLength;}
public class CheckoutService{ private readonly ICurrencyProvider _currencyProvider; // อ้างอิง locale ของลูกค้าจริง ไม่ใช่ hardcode
public CheckoutService(ICurrencyProvider currencyProvider) => _currencyProvider = currencyProvider;
public OrderConfirmation Checkout(Order order) { var currency = _currencyProvider.ResolveFor(order.Customer); var total = order.Items.Sum(i => i.Price.ConvertTo(currency) * i.Quantity); return new OrderConfirmation(total, currency); }}จุดสำคัญไม่ใช่แค่ “code หลังแก้ดูถูกกว่า” แต่คือที่มาของค่าคงที่และ dependency แต่ละตัวเปลี่ยนจาก “นักพัฒนาคิดว่าใช่” ไปเป็น “มาจากข้อมูลผู้ใช้จริงหรือ service ที่ตรวจสอบได้”
ทางแก้และการ refactor
หัวข้อที่มีชื่อว่า “ทางแก้และการ refactor”หัวใจของทางแก้คือเปลี่ยนสมมติฐานที่ซ่อนอยู่ในหัวให้กลายเป็น สมมติฐานที่ทดสอบได้อย่างชัดเจน แล้ววน loop ตรวจสอบกับข้อมูลจริงก่อนที่มันจะฝังลง code:
flowchart TD
A[เจอจุดตัดสินใจเกี่ยวกับผู้ใช้] --> B{มีข้อมูลผู้ใช้จริงรองรับไหม}
B -- ไม่มี ใช้สัญชาตญาณล้วน --> C[เขียน code ตามที่ตนเองคิดว่าถูก]
C --> D[ปล่อยใช้งานจริง]
D --> E[ผู้ใช้เจอปัญหาที่ไม่คาดคิด]
E --> F[ต้องแก้ทีหลังด้วยต้นทุนสูง]
B -- มี หรือระบุเป็นสมมติฐานที่ตรวจสอบได้ --> G[เก็บ feedback หรือทำ usability test เล็ก ๆ]
G --> H[ปรับการตัดสินใจตามข้อมูลจริง]
H --> I[ปล่อยใช้งานจริงอย่างมั่นใจ]
แนวทางปฏิบัติที่ช่วยได้จริง:
- แปลงสมมติฐานให้เป็นข้อความชัดเจนที่เขียนออกมาได้ เช่น “เราเชื่อว่าผู้ใช้ 80% จะกรอกที่อยู่จัดส่งเดียวกับที่อยู่เรียกเก็บเงิน” แล้วจัดลำดับตามความเสี่ยง ก่อนตรวจสอบด้วยวิธีที่ถูกที่สุดก่อน เช่น prototype เล็ก ๆ หรือ spike
- ใช้เครื่องมือ analytics/observability ดูเส้นทางที่ผู้ใช้เดินจริงในระบบ แทนที่จะเดาจาก flow ที่ออกแบบไว้ในหัว (ดู Know Where You Are Going)
- เปิดช่องทาง feedback ที่เข้าถึงง่าย และตรวจสอบมันสม่ำเสมอ ไม่ใช่แค่ตอนมีคนบ่นดัง ๆ
- แบ่ง persona ตามข้อมูลจริง สำหรับผลิตภัณฑ์ขนาดใหญ่ที่มีผู้ใช้หลายกลุ่ม แทนที่จะสร้าง persona เดียวที่หน้าตาเหมือนทีมพัฒนา
- Dogfood ควบคู่กับผู้ใช้ทดสอบภายนอก เสมอ เพราะทีมพัฒนาไม่ใช่กลุ่มตัวอย่างที่เป็นตัวแทนของผู้ใช้จริง
- เขียน acceptance criteria ร่วมกับผู้มีส่วนได้ส่วนเสียจริงผ่าน Behavior Driven Development แทนการเดากฎธุรกิจเอง และตรวจสอบภาษาที่ใช้กับผู้เชี่ยวชาญ domain ให้ตรงกับ Ubiquitous Language ของธุรกิจจริง ไม่ใช่ศัพท์ที่ทีมพัฒนาคิดขึ้นเอง
ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”แหล่งอ้างอิง
หัวข้อที่มีชื่อว่า “แหล่งอ้างอิง”- ที่มา · deviq.com/antipatterns/assumption-driven-programming
- You Are Not the User: The False-Consensus Effect — Nielsen Norman Group
- Falsehoods Programmers Believe About Names — Patrick McKenzie
- awesome-falsehood — รวมรายการ “falsehoods programmers believe about X” ในหัวข้ออื่น ๆ
- Why Assumptions are the Bane of Software Development — Andy Farmer