All posts

19 min readAI

คนอ่าน user story เดียวกัน แต่เข้าใจคนละอย่าง: ความคลุมเครือไม่ใช่ปัญหาของ QA

dev ทำตาม story ครบ QA เทสผ่านทุกเคส PO อนุมัติแล้ว แต่ลูกค้าเปิดดูตอน UAT แล้วบอกว่า "ไม่ใช่ที่ขอ" และไม่มีใครในห้องทำผิดเลยสักคน บันทึกจากเดฟ·PM·PO ว่าทำไม user story ประโยคเดียวถึงถูกอ่านเป็นสี่งานในหัวสี่คน ทำไมความคลุมเครือของ requirement ถึงไม่ใช่ปัญหาที่ test จะจับได้ ยุค agent ทำให้มันซ่อนตัวเก่งขึ้นยังไง และวิธีที่ผมใช้ให้ทุกคนเห็นความต่างก่อนจะมีใครเขียนโค้ดบรรทัดแรก

Sutthiphong NuanmaSoftware Developer

ห้อง UAT ที่อึดอัดที่สุดที่ผมเคยนั่งไม่ใช่ห้องที่เจอบั๊กเยอะครับ แต่คือห้องที่ทุกคนถูกหมด

developer บอกว่าทำตาม story ครบทุกคำ QA บอกว่าเทสผ่านทุกเคสที่เขียนไว้ PO ซึ่งก็คือผมเอง บอกว่าอนุมัติไปแล้วเพราะมันตรงกับที่คุยกัน แล้วลูกค้าก็เปิดหน้าจอดูสักพัก ก่อนจะพูดประโยคที่ทุกคนในวงการนี้เคยได้ยิน "อันนี้ไม่ใช่ที่ขอนะครับ"

ที่แย่คือลูกค้าก็ถูกเหมือนกัน

ผมเป็นทั้ง developer, PM และ PO ที่ Mulberrysoft ดูแลทีม junior ทำงานกับลูกค้าที่ requirement แทบไม่เคยครบ และใช้ Claude, Codex กับ agent อื่น ๆ แทบทุกวัน ซีรีส์นี้เริ่มจากการให้ agent ทำงานแทนโดยไม่ให้มันคิดแทน ต่อด้วยวันที่คำตอบของ agent กลายเป็นความเห็นของเรา หนี้ความเข้าใจที่ไม่ขึ้นบน dashboard เจตนาที่ agent จ่ายแทนไม่ได้ สีเขียวที่ไม่ได้แปลว่าถูก การล็อกสเปกก่อนโค้ดด้วย OpenSpec การให้ agent grill เราจน requirement ชัด PRD ที่ AI เขียนให้แต่ไม่มีใครอ่าน และล่าสุดยุค agent ที่ทุกคนต้องเขียน AC เหมือน PO

โพสต์ที่แล้วผมพูดถึงคนเขียน AC โพสต์นี้ขอหันไปดูอีกฝั่งครับ คือคนอ่าน เพราะต่อให้เราเขียนดีแค่ไหน ประโยคเดียวกันก็ยังไปเกิดเป็นภาพคนละภาพในหัวคนแต่ละคนได้เสมอ และส่วนใหญ่ไม่มีใครรู้ตัวว่าภาพในหัวตัวเองไม่เหมือนของคนอื่น จนกระทั่งของจริงออกมาให้เทียบ

จุดยืนของโพสต์นี้คือ ความคลุมเครือของ requirement ไม่ใช่ปัญหาของการทดสอบ แต่เป็นปัญหาของความเข้าใจร่วมกัน QA ไม่มีทางเทสเจอความคลุมเครือที่ตัวเองก็ตีความไปแล้วเหมือนกัน และถ้าเรารอให้มันโผล่ตอนเทส เราก็จ่ายราคาแพงที่สุดสำหรับปัญหาที่ถูกที่สุดในการแก้

จุดเริ่มต้นจากโพสต์บน X

ผมเห็นโพสต์หนึ่งบน X ที่พูดถึงเรื่องที่คนทำซอฟต์แวร์คุ้นเคยกันดี ใจความรวม ๆ คือ user story เดียวกันถูกอ่านโดย developer, QA และ product owner แล้วแต่ละคนเข้าใจไปคนละทาง และปัญหานี้มักถูกมองเป็นเรื่องของฝั่งทดสอบ ทั้งที่จริงมันเริ่มตั้งแต่ตอนที่ requirement ถูกเขียนและถูกอ่าน

ไม่ใช่ไอเดียใหม่ครับ ใครเคยเห็นการ์ตูนชิงช้าบนต้นไม้ที่ลูกค้าอธิบายแบบหนึ่ง PM เข้าใจอีกแบบ developer สร้างอีกแบบ ก็คงรู้จักมุกนี้ดี แต่สิ่งที่ทำให้ผมหยุดคิดคือคำว่า "ไม่ใช่แค่ปัญหาของ testing" เพราะเมื่อมองย้อนไป ทีมผมจัดการเรื่องนี้ผิดที่มาตลอด

ทุกครั้งที่ UAT เจอว่า "ไม่ใช่ที่ขอ" สิ่งที่เราทำคือเปิด ticket เป็นบั๊ก ใส่ label ให้ QA ไปเพิ่ม test case ให้ developer ไปแก้ แล้วก็ไปต่อ ไม่มีใครถามว่าความเข้าใจที่ไม่ตรงกันนั้นเกิดขึ้นตอนไหน ทั้งที่คำตอบแทบทุกครั้งคือ มันเกิดตั้งแต่วันแรกที่ทุกคนอ่าน story แล้วพยักหน้าพร้อมกันในห้องประชุม

story เดียว สี่งาน

ขอยกตัวอย่างที่ผมเรียบเรียงจากหลายงานนะครับ ไม่ใช่เคสใดเคสหนึ่ง แต่ทุกรายละเอียดเป็นสิ่งที่ผมเจอจริงในรูปแบบใดรูปแบบหนึ่ง

ลูกค้าร้านค้าออนไลน์ส่ง requirement มา ผมแปลงเป็น story หน้าตาแบบนี้

ในฐานะแอดมินร้าน ฉันต้องการ export รายงานยอดขายรายเดือน เพื่อส่งให้ฝ่ายบัญชี

ประโยคเดียว ดูชัดมาก ทุกคนอ่านแล้วไม่มีใครถามอะไร ลองดูว่าแต่ละคนเห็นอะไรครับ

ลูกค้า เห็นไฟล์ Excel หน้าตาเหมือนที่สำนักงานบัญชีส่ง template มาให้เมื่อปีที่แล้ว มียอดก่อน VAT ตัว VAT และยอดรวมแยกคอลัมน์ นับตามวันที่ออกใบกำกับภาษี และไม่รวมออเดอร์ที่ยกเลิก เพราะนั่นคือสิ่งที่ฝ่ายบัญชีใช้จริง ลูกค้าไม่ได้พูดสักข้อ เพราะในหัวเขา "รายงานยอดขายสำหรับบัญชี" มีความหมายเดียว

PO ซึ่งก็คือผม เห็นปุ่ม Export ในหน้ารายงานที่มีอยู่แล้ว กดแล้วได้ไฟล์ตามตัวกรองที่เลือกอยู่บนหน้าจอ ผมคิดถึงประสบการณ์ของแอดมินมากกว่าฝ่ายบัญชี เพราะ story ขึ้นต้นด้วย "ในฐานะแอดมิน"

developer เห็น query ตาราง orders group by เดือนจาก created_at แล้ว stream ออกมาเป็น CSV ซึ่งเป็นวิธีที่เร็วที่สุดและรองรับข้อมูลเยอะที่สุด เวลาในฐานข้อมูลเก็บเป็น UTC developer ก็ใช้ UTC ตามที่ระบบเป็น

QA เห็นปุ่มที่กดแล้วไฟล์ต้องดาวน์โหลดได้ คอลัมน์ในไฟล์ต้องตรงกับตารางบนหน้าจอ เดือนที่ไม่มียอดต้องได้ไฟล์ว่างพร้อม header และไฟล์ต้องเปิดได้ไม่เพี้ยน

ไม่มีใครผิดเลยครับ ทุกการตีความสมเหตุสมผลจากมุมของคนอ่าน และนี่คือสิ่งที่ทำให้ปัญหานี้อันตราย ถ้ามีใครตีความผิดแบบชัด ๆ คนอื่นจะทักตั้งแต่แรก แต่เมื่อทุกการตีความดูสมเหตุสมผล ก็ไม่มีใครเห็นความจำเป็นต้องถาม

แล้วผลลัพธ์ตอน UAT คืออะไร ไฟล์เป็น CSV ที่เปิดใน Excel แล้วภาษาไทยเป็นตัวอักษรแปลก ๆ ยอดรวมยังไม่แยก VAT ออเดอร์ที่ยกเลิกปนอยู่ และที่หายากที่สุด ออเดอร์ที่เข้ามาช่วงเที่ยงคืนถึงเกือบเจ็ดโมงเช้าของวันที่ 1 ตามเวลาไทย ถูกนับไปอยู่ในเดือนก่อน เพราะใน UTC มันยังเป็นวันสุดท้ายของเดือนที่แล้ว

ข้อสุดท้ายนี้ QA ไม่เจอครับ เพราะข้อมูลทดสอบไม่มีออเดอร์ช่วงนั้น และไม่มีใครคิดจะสร้าง เพราะไม่มีใครในทีมคิดว่าคำว่า "รายเดือน" มีอะไรต้องคิด ลูกค้าเจอเองตอนเทียบยอดกับสมุดบัญชี

ทำไม test จับความคลุมเครือไม่ได้

ตรงนี้คือแก่นของโพสต์ครับ และเป็นสิ่งที่ผมเข้าใจผิดมานาน

ผมเคยคิดว่าถ้ามี QA ที่ละเอียดพอ ความไม่ตรงกันพวกนี้จะถูกจับได้ก่อนถึงลูกค้า แต่ลองดูว่า QA ทำงานยังไงครับ QA อ่าน story แล้วเขียน test case จากความเข้าใจของตัวเอง แล้วเทียบระบบกับ test case นั้น สิ่งที่ test ตรวจได้คือ ระบบตรงกับการตีความของ QA ไหม ไม่ใช่ระบบตรงกับสิ่งที่ลูกค้าต้องการไหม

ถ้าการตีความของ QA บังเอิญตรงกับลูกค้า เราก็โชคดี ถ้าบังเอิญตรงกับ developer test จะผ่านหมด แล้วทุกคนก็มั่นใจขึ้นว่างานถูก ทั้งที่สิ่งที่พิสูจน์ได้จริงมีแค่ว่าสองคนในทีมเดาเหมือนกัน

ในโพสต์ Verify ผมเขียนว่าสีเขียวไม่ได้แปลว่าถูก เคสนี้คือรูปแบบที่ร้ายที่สุดของประโยคนั้นครับ เพราะ test ไม่ได้เขียนผิด ไม่ได้ข้าม ไม่ได้ mock อะไรแปลก ๆ มันแค่ยืนยันความเข้าใจที่ผิดตั้งแต่ต้นอย่างแม่นยำ

ผมเลยคิดว่าการจัดความคลุมเครือเป็น "บั๊ก" แล้วโยนให้ QA มีปัญหาสองชั้น

ชั้นแรกคือมันผิดเวลา ความคลุมเครือที่ถูกพบตอนอ่าน story แก้ด้วยการถามหนึ่งคำถาม ความคลุมเครือเดียวกันที่ถูกพบตอน UAT แก้ด้วยการรื้อโค้ด แก้ test เลื่อนส่งงาน และบางครั้งต้องคุยเรื่องเงินกับลูกค้าว่าอันนี้คือการแก้บั๊กหรือ change request

ชั้นที่สองคือมันผิดเจ้าของ เมื่อเรียกว่าบั๊ก มันก็ฟังเหมือนมีคนทำงานพลาด ซึ่งในทีมผมส่วนใหญ่ตกไปที่ developer กับ QA ที่เป็น junior ทั้งที่ต้นเหตุคือ story ที่ผมเขียนแล้วไม่ได้ตรวจว่าคนอื่นอ่านแล้วเห็นภาพเดียวกับผมไหม น้องที่โดนเปิดบั๊กบ่อย ๆ ไม่ได้เรียนรู้ว่าต้องถามมากขึ้น เขาเรียนรู้ว่าตัวเองทำงานไม่ดี ซึ่งเป็นบทเรียนที่ผิดทั้งหมด

ยุค agent ทำให้มันซ่อนตัวเก่งขึ้น

ปัญหานี้มีมาก่อน agent นานแล้วครับ แต่ผมคิดว่า agent เปลี่ยนรูปร่างของมันไปในทางที่ต้องระวังกว่าเดิม

เมื่อก่อนความต่างของการตีความมีโอกาสโผล่กลางทาง developer เขียนไปครึ่งหนึ่งแล้วเกิดสงสัยว่าจะใช้วันที่ไหน ก็อาจเดินไปถาม QA นั่งเขียน test case แล้วเห็นว่า story ไม่พูดถึงออเดอร์ยกเลิก ก็อาจทักใน channel ความช้าของการทำงานด้วยมือสร้างจังหวะให้คนได้สงสัย

ตอนนี้ developer วาง story ให้ agent แล้วได้โค้ดในไม่กี่นาที QA วาง story เดียวกันให้ agent อีกตัวแล้วได้ test case ห้าสิบข้อ ทั้งสองฝั่งไม่ได้หยุดสงสัยตรงไหนเลย เพราะ agent เติมช่องว่างให้ก่อนที่คนจะทันเห็นว่ามีช่อง อย่างที่ผมเขียนในโพสต์ Intent Debt ครับ ช่องว่างจะถูกเติมเสมอ คำถามคือใครเติม

และมีอีกกรณีที่ผมเจอแล้วรู้สึกว่าอันตรายกว่า คือเมื่อโค้ดกับ test มาจาก agent ตัวเดียวกัน หรือจาก story ก้อนเดียวกันผ่านโมเดลเดียวกัน การตีความของสองฝั่งจะตรงกันแทบทุกครั้ง เพราะมันมาจากที่เดียวกัน test ผ่านหมด coverage สูง ทุกอย่างดูแข็งแรง แต่ ความเห็นตรงกันของ agent ไม่ใช่ความเข้าใจร่วมกันของทีม มันคือการเดาครั้งเดียวที่ถูกเขียนลงไปสองที่

ในทีมที่มีคน dev กับ QA เป็นคนละคน ความต่างของการตีความอย่างน้อยยังมีโอกาสชนกันเองแล้วโผล่ขึ้นมา แต่ถ้าทั้งสองฝั่งส่งต่อให้ agent ที่คิดเหมือนกัน เราตัดโอกาสนั้นทิ้งไปเลยโดยไม่รู้ตัว

ผมไม่ได้บอกว่าห้ามให้ agent เขียน test นะครับ ผมใช้ทุกวัน แต่ผมเลิกเชื่อว่า test ที่ agent เขียนจาก story จะช่วยจับความคลุมเครือของ story นั้นได้ มันช่วยจับบั๊กในโค้ด ไม่ได้ช่วยจับช่องว่างในความเข้าใจ

คำที่ทำให้คนอ่านแยกทาง

หลังจากเจอเรื่องแบบนี้ซ้ำหลายรอบ ผมเริ่มสังเกตว่าความเข้าใจที่ไม่ตรงกันไม่ได้เกิดแบบสุ่มครับ มันมักเกิดที่คำบางประเภท ซึ่งดูธรรมดาจนไม่มีใครหยุดอ่าน

คำเกี่ยวกับเวลา เช่น "รายเดือน" "วันนี้" "ล่าสุด" "หมดอายุ" คำพวกนี้ต้องการคำตอบว่านับจากเวลาไหน เขตเวลาอะไร และนับจากเหตุการณ์ไหน วันสั่ง วันจ่าย หรือวันออกใบกำกับภาษี

คำบอกปริมาณ เช่น "ทั้งหมด" "ทุกรายการ" "บางส่วน" ทั้งหมดรวมรายการที่ถูกลบไปแล้วไหม รวมของสาขาอื่นไหม รวมออเดอร์ทดสอบที่แอดมินสร้างไว้ไหม

คำบอกบทบาท เช่น "แอดมิน" "ผู้ใช้" "ลูกค้า" ในระบบที่มีหลายระดับสิทธิ์ แอดมินของลูกค้าอาจหมายถึงเจ้าของร้าน ส่วนแอดมินของ developer อาจหมายถึง role ที่ชื่อ admin ในตาราง ซึ่งอาจไม่ใช่คนเดียวกัน

คำบอกสถานะ เช่น "สำเร็จ" "ยกเลิก" "ใช้งานอยู่" คำไทยหนึ่งคำอาจตรงกับหลายค่าในระบบ "ออเดอร์ที่สำเร็จ" คือ paid หรือ delivered หรือทั้งสอง

คำบอกคุณภาพ เช่น "ง่าย" "เร็ว" "สวย" "ใช้งานสะดวก" อันนี้ทุกคนรู้ว่าคลุมเครือ แต่ก็ยังเขียนกันอยู่ เพราะมันฟังดีในห้องประชุม

คำกริยาที่มีหลายระดับ เช่น "ลบ" "export" "แจ้งเตือน" ลบคือ soft delete หรือลบจริง export คือ CSV หรือ Excel หรือ PDF แจ้งเตือนคือ email, LINE หรือแค่จุดแดงบนไอคอน

ประโยค "เพื่อ..." ท้าย story ส่วนนี้คนมักข้าม แต่ผมคิดว่ามันสำคัญที่สุดครับ ในตัวอย่างข้างบน คำว่า "เพื่อส่งให้ฝ่ายบัญชี" คือเบาะแสทั้งหมดที่บอกว่าไฟล์ต้องหน้าตาแบบไหน แต่ทุกคนรวมทั้งผมอ่านผ่านไปเหมือนเป็นคำประดับ

ตอนนี้ผมใช้รายการนี้เหมือน lint ของภาษาไทยครับ ก่อนส่ง story ออกไป ผมไล่ขีดเส้นใต้คำในหมวดเหล่านี้ทุกคำ แล้วถามตัวเองว่าถ้าคนสี่คนอ่านคำนี้ จะได้คำตอบเดียวกันไหม

อ่านแยกก่อน แล้วค่อยคุย

วิธีที่ได้ผลที่สุดที่ผมเจอไม่ได้ซับซ้อนเลยครับ มันคือการบังคับให้ความต่างโผล่ขึ้นมา ก่อนที่จะมีใครเขียนโค้ด

ปัญหาของการประชุม refinement แบบเดิมคือ PO อ่าน story ให้ฟัง แล้วถามว่ามีคำถามไหม ซึ่งแทบไม่มีใครถาม เพราะทุกคนกำลังเข้าใจ story ผ่านภาพในหัวตัวเอง และภาพนั้นดูสมบูรณ์ดี ไม่มีใครรู้ว่าตัวเองไม่รู้

ผมเลยเปลี่ยนเป็นแบบนี้ครับ ก่อนคุย ให้ทุกคนที่เกี่ยวข้อง ทั้ง developer, QA และผม เขียนแยกกันคนละห้านาที ว่า ถ้างานนี้เสร็จ เราจะยกตัวอย่างอะไรสามข้อ ต้องเป็นตัวอย่างที่มีข้อมูลจริง ไม่ใช่คำอธิบาย แล้วค่อยเอามาวางเทียบกัน

ถ้าทำกับ story ข้างบน สิ่งที่ได้อาจหน้าตาประมาณนี้

คนเขียนตัวอย่างที่ยก
devเลือกเดือน ต.ค. ได้ไฟล์ CSV ทุกออเดอร์ที่ created_at อยู่ใน ต.ค.
QAเดือนที่ไม่มีออเดอร์ ได้ไฟล์ที่มีแต่ header
POกรองสาขา A แล้วกด Export ได้เฉพาะออเดอร์สาขา A

แค่สามแถวนี้ก็มีคำถามโผล่มาทันทีครับ "ทุกออเดอร์" รวมที่ยกเลิกไหม created_at หรือวันจ่ายเงิน ไฟล์ต้องเคารพตัวกรองบนหน้าจอหรือเป็นรายงานทั้งร้าน และคำถามที่สำคัญที่สุด ฝ่ายบัญชีใช้ไฟล์นี้ทำอะไร ซึ่งไม่มีใครในห้องตอบได้ ต้องถามลูกค้า

ความต่างของวิธีนี้กับการถามว่า "มีคำถามไหม" คือมันไม่ได้พึ่งให้คนรู้ตัวว่าตัวเองสงสัย มันแค่ทำให้ภาพในหัวแต่ละคนออกมาอยู่บนโต๊ะ แล้วให้ความต่างพูดแทน

ส่วนลูกค้า ผมไม่ได้ให้เขียนตัวอย่างแบบนี้นะครับ เพราะลูกค้าส่วนใหญ่ไม่ได้มีเวลาหรืออยากทำ สิ่งที่ผมทำแทนคือขอของจริงที่เขาใช้อยู่ ในเคสนี้คือ "ขอไฟล์ที่ฝ่ายบัญชีอยากได้สักเดือนหนึ่งได้ไหมครับ" ไฟล์ตัวอย่างไฟล์เดียวตอบคำถามได้มากกว่าการประชุมหนึ่งชั่วโมง เพราะมันคือการตีความของลูกค้าที่ถูกเขียนออกมาแล้ว

ให้ agent อ่านแทนหลายคน

ผมพูดไปว่า agent ทำให้ความคลุมเครือซ่อนตัวเก่งขึ้น แต่ถ้าใช้ถูกทาง agent ก็ช่วยลากมันออกมาได้เหมือนกันครับ

แทนที่จะให้ agent อ่าน story แล้วลงมือทำ ผมให้มันอ่านแล้ว แสดงการตีความที่เป็นไปได้หลายแบบ ก่อน prompt ที่ผมใช้ประมาณนี้

อ่าน user story ด้านล่าง ยังไม่ต้องเขียนโค้ดหรือ test

1. ลองอ่านในมุมของ developer, QA, PO และลูกค้าที่ไม่ใช่คนเทคนิค
   แต่ละมุมเข้าใจว่า "เสร็จ" หน้าตาเป็นยังไง ยกตัวอย่างที่มีข้อมูลจริงมุมละ 2 ข้อ
2. ชี้คำหรือวลีที่ทำให้แต่ละมุมเข้าใจต่างกัน
3. สรุปเป็นคำถามที่ต้องให้คนตัดสิน เรียงตามผลกระทบถ้าเดาผิด
4. ห้ามเลือกคำตอบแทน ถ้ามีข้อไหนที่คิดว่าชัดแล้ว ให้บอกว่าชัดเพราะอะไร

Story:
<วาง story และบริบทที่มี>

สิ่งที่ได้กลับมาไม่ได้ถูกทุกข้อครับ บางมุมที่ agent จินตนาการขึ้นมาก็ไกลเกินจริง แต่มันเก่งมากเรื่องหยิบคำอย่าง "รายเดือน" หรือ "ทั้งหมด" ขึ้นมาถามว่านับแบบไหน ซึ่งเป็นคำที่คนในทีมอ่านผ่านเพราะคุ้นเกินไป

ข้อ 4 สำคัญที่สุดครับ อย่างที่ผมเขียนในโพสต์ Grill Me ว่าหน้าที่ของ agent ในขั้นนี้คือถาม ไม่ใช่ตอบ ถ้าปล่อยให้มันเลือกคำตอบให้ เราก็แค่ได้การตีความแบบที่ห้า ซึ่งดูน่าเชื่อกว่าสี่แบบแรกเพราะมันเขียนมาเรียบร้อย และอย่างที่โพสต์ PRD ที่ไม่มีใครอ่าน เตือนไว้ คำเดาที่ดูเรียบร้อยคือคำเดาที่คนหยุดถาม

อีกเรื่องที่ผมระวังคือ ผลลัพธ์จาก prompt นี้ไม่ได้มาแทนการอ่านแยกของคนในทีมนะครับ agent ไม่รู้ว่าลูกค้ารายนี้มีสำนักงานบัญชีที่ส่ง template มา ไม่รู้ว่าแอดมินร้านนี้คือเจ้าของร้านเอง มันช่วยขยายรายการคำถาม แต่คนที่รู้ว่าคำถามข้อไหนสำคัญกับลูกค้ารายนี้คือคน

จาก AC ไปสู่ตัวอย่าง

ในโพสต์ AC ผมบอกว่าทุกคนที่สั่งงาน agent คือ PO และต้องเขียน AC ให้ชัด โพสต์นี้ขอเติมอีกชั้นครับ คือ AC เองก็ถูกอ่านต่างกันได้

"Then ไฟล์แสดงยอดขายของเดือนที่เลือก" เป็น AC ที่มี Given/When/Then ครบ แต่คำว่า "ยอดขายของเดือนที่เลือก" ยังมีทุกปัญหาที่ผมไล่มาข้างบน การเขียนให้เป็นรูปแบบไม่ได้ทำให้คำในนั้นชัดขึ้นเอง

สิ่งที่ช่วยได้จริงคือการผูก AC กับตัวอย่างที่มีข้อมูลจริงครับ เช่น

AC 3 — นับออเดอร์ตามวันออกใบกำกับภาษี เวลาประเทศไทย Given ออเดอร์ A ออกใบกำกับภาษีวันที่ 31 ต.ค. เวลา 23:50 น. (เวลาไทย) และออเดอร์ B ออกใบกำกับภาษีวันที่ 1 พ.ย. เวลา 00:30 น. (เวลาไทย) When แอดมิน export รายงานเดือน ต.ค. Then ไฟล์มีออเดอร์ A และไม่มีออเดอร์ B

AC 4 — ไม่รวมออเดอร์ที่ยกเลิก Given ออเดอร์ C ออกใบกำกับภาษีใน ต.ค. แล้วถูกยกเลิกพร้อมออกใบลดหนี้ When แอดมิน export รายงานเดือน ต.ค. Then ไม่มีออเดอร์ C ในไฟล์ ยังไม่ทราบ: ใบลดหนี้ต้องแสดงในรายงานแยกหรือไม่ รอลูกค้ายืนยันกับสำนักงานบัญชี

ตัวอย่างที่มีวันที่และเวลาจริงแบบนี้ไม่มีที่ให้ตีความต่างครับ developer อ่านแล้วรู้ทันทีว่าต้องแปลงเขตเวลา QA อ่านแล้วได้ข้อมูลทดสอบที่ต้องสร้าง agent อ่านแล้วเขียน test ที่จับปัญหาเที่ยงคืนได้ และลูกค้าอ่านแล้วตอบได้ว่าใช่หรือไม่ใช่ โดยไม่ต้องเข้าใจคำว่า UTC

และที่ผมชอบที่สุดคือบรรทัด "ยังไม่ทราบ" ใน AC 4 ครับ มันไม่ได้มาจากการที่ผมนึกออกเอง มันมาจากการพยายามเขียนตัวอย่างให้ครบ แล้วพบว่าผมไม่รู้ว่าออเดอร์ที่ยกเลิกในทางบัญชีต้องทำยังไง ตัวอย่างบังคับให้ความไม่รู้โผล่ขึ้นมา ส่วนคำอธิบายช่วยซ่อนมันไว้

เช็กลิสต์ก่อนส่ง story ออกไป

ผมสรุปเป็นรายการที่ใช้จริงในทีมครับ ไม่ต้องทำครบทุกข้อในทุกงาน แต่ยิ่งงานแตะเงิน สิทธิ์ หรือตัวเลขที่ลูกค้าเอาไปใช้ต่อ ยิ่งควรทำครบ

ก่อนเขียน story

  • รู้ว่าผลลัพธ์ของงานนี้จะถูกใครใช้ต่อ และใช้ทำอะไร ไม่ใช่แค่ใครเป็นคนกด
  • ขอของจริงจากลูกค้าถ้ามี เช่น ไฟล์ตัวอย่าง ภาพหน้าจอระบบเดิม เอกสารที่เขาใช้อยู่
  • ประโยค "เพื่อ..." ใน story บอกเหตุผลจริง ไม่ใช่คำประดับ

ตอนเขียน

  • ไล่ขีดเส้นใต้คำเกี่ยวกับเวลา ปริมาณ บทบาท สถานะ คุณภาพ และคำกริยาที่มีหลายระดับ แล้วนิยามทุกคำ
  • คำไทยที่ตรงกับค่าในระบบ เขียนชื่อจริงกำกับ เช่น "ออเดอร์ที่จ่ายแล้ว (paid)"
  • AC ที่เกี่ยวกับตัวเลข วันที่ หรือสิทธิ์ มีตัวอย่างที่มีข้อมูลจริงอย่างน้อยหนึ่งข้อ
  • มีตัวอย่างของกรณีขอบ โดยเฉพาะขอบเวลา ขอบสิทธิ์ และข้อมูลที่ถูกลบหรือยกเลิก
  • มีหัวข้อ "ยังไม่ทราบ" พร้อมคนรับผิดชอบ แทนการแกล้งทำว่าครบ

ก่อนเริ่มทำ

  • dev, QA และ PO เขียนตัวอย่าง "เสร็จ" แยกกันคนละสามข้อ แล้ววางเทียบ
  • ให้ agent อ่าน story ในหลายมุมแล้วสรุปคำถาม โดยห้ามมันเลือกคำตอบเอง
  • ความต่างที่เจอถูกตัดสินโดยคน และถูกเขียนกลับเข้าไปใน story หรือ AC ไม่ใช่ตกลงกันปากเปล่า
  • junior ที่รับงานอธิบาย story กลับมาด้วยคำของตัวเองได้ พร้อมตัวอย่างหนึ่งข้อ

ตอนเจอปัญหาใน UAT

  • ถามก่อนว่านี่คือบั๊กในโค้ด หรือความเข้าใจที่ไม่ตรงกันตั้งแต่ต้น
  • ถ้าเป็นอย่างหลัง แก้ที่ story และ template ด้วย ไม่ใช่แค่เพิ่ม test case
  • ไม่โยนความคลุมเครือเป็นความผิดของ developer หรือ QA

นิสัยที่ผมใช้กับทีม

ให้น้องอธิบายกลับก่อนเริ่มงาน เวลา assign งานให้ junior ผมไม่ถามว่า "เข้าใจไหม" แล้ว เพราะคำตอบคือ "เข้าใจครับ" ทุกครั้ง สิ่งที่ผมถามแทนคือ "ลองเล่าให้พี่ฟังหน่อยว่าตอนเสร็จ พี่จะเห็นอะไร" ถ้าน้องเล่าแล้วไม่ตรงกับภาพในหัวผม ความผิดไม่ได้อยู่ที่น้อง มันคือหลักฐานว่า story ของผมยังไม่ชัด และดีกว่ามากที่เจอตอนนี้แทนที่จะเจอใน PR

แยกป้ายระหว่างบั๊กกับความเข้าใจไม่ตรงกัน ในบอร์ดงานของทีม ผมเพิ่ม label สำหรับปัญหาที่เกิดจาก requirement ไม่ชัด แยกจากบั๊กในโค้ด จุดประสงค์ไม่ใช่การนับคะแนนใคร แต่เพื่อให้ผมเห็นว่าปัญหาส่วนไหนมาจากต้นน้ำ และหลายครั้งที่เห็นแล้วก็ต้องยอมรับว่าต้นน้ำคือผม

ให้ QA อ่าน story ก่อน developer เริ่ม ไม่ใช่หลัง developer ส่งงาน QA ที่ดีมีทักษะที่หายากมาก คือการมองหาว่าอะไรจะพัง และทักษะนั้นมีค่าที่สุดตอนที่ยังไม่มีโค้ด เพราะคำถามของ QA ตอนนั้นยังเปลี่ยน story ได้ ส่วนคำถามของ QA ตอนท้ายทำได้แค่เปิดบั๊ก

อ่านให้ลูกค้าฟังด้วยภาษาของลูกค้า ก่อนเริ่มงานที่สำคัญ ผมจะเล่าตัวอย่างใน AC ให้ลูกค้าฟังแบบไม่มีศัพท์เทคนิค "ถ้าออเดอร์ออกบิลตอนเที่ยงคืนครึ่งของวันที่ 1 จะไปอยู่ในรายงานเดือนใหม่นะครับ ถูกไหม" ลูกค้าตอบคำถามแบบนี้ได้ทันที แต่ตอบคำถามว่า "ใช้ timezone อะไรดีครับ" ไม่ได้

ไม่ให้ agent ตัวเดียวเป็นทั้งคนทำและคนตรวจโดยไม่มีคนคั่นกลาง ถ้า test มาจาก agent ผมต้องการให้มันเขียนจาก AC ที่มีตัวอย่างซึ่งคนยืนยันแล้ว ไม่ใช่จาก story ดิบ และผมยังเปิดดูว่ามี test สำหรับตัวอย่างขอบที่สำคัญจริง ไม่ใช่แค่ดูว่าเขียวครบ

เก็บคำที่เคยทำให้ทีมแตกเป็นรายการของโปรเจกต์ ทุกครั้งที่เจอคำที่คนอ่านไม่ตรงกัน ผมจดลงในไฟล์อภิธานศัพท์ของโปรเจกต์ พร้อมความหมายที่ตกลงกันแล้ว เช่น "ยอดขาย = ยอดตามใบกำกับภาษี ไม่รวมออเดอร์ยกเลิก เวลาไทย" แล้วให้ทั้งคนและ agent อ้างอิงไฟล์นั้น คำเดิมจะไม่ทำให้ทีมแตกซ้ำสองรอบ

ท้ายที่สุด

ผมเคยคิดว่าการสื่อสาร requirement คือการเขียนให้ชัด ถ้าเขียนชัดพอ ทุกคนจะเข้าใจตรงกัน ทุกวันนี้ผมคิดว่านั่นเป็นแค่ครึ่งเดียวครับ อีกครึ่งคือการตรวจว่าคนอ่านเห็นภาพเดียวกับเราจริงไหม เพราะความชัดไม่ได้อยู่ในตัวหนังสือ มันอยู่ในระยะห่างระหว่างภาพในหัวคนเขียนกับภาพในหัวคนอ่าน และระยะนั้นวัดไม่ได้จนกว่าจะเอาภาพมาวางเทียบกัน

ห้อง UAT ที่ทุกคนถูกหมดสอนผมว่า เมื่อไม่มีใครผิด ปัญหาไม่ได้อยู่ที่คน แต่อยู่ที่จังหวะ ความเข้าใจที่ไม่ตรงกันมีอยู่ตั้งแต่วันแรก เราแค่เลือกจะเจอมันตอนที่แพงที่สุด

ยุค agent ไม่ได้ทำให้ปัญหานี้หายไปครับ มันทำให้ทุกคนในทีมมีผู้ช่วยที่พร้อมเติมช่องว่างให้อย่างมั่นใจ และทำให้เราเดินจาก story ไปถึงโค้ดที่เทสผ่านได้เร็วจนไม่มีจังหวะให้สงสัย ถ้าเราไม่สร้างจังหวะนั้นขึ้นมาเอง ก็จะไม่มีใครสร้างให้

ดังนั้นครั้งถัดไปที่ผมส่ง story ให้ทีม ผมจะไม่ถามว่า "มีคำถามไหม" แต่จะถามว่า "ลองยกตัวอย่างให้ดูหน่อยว่าตอนเสร็จหน้าตาเป็นยังไง" แล้วฟังว่าคำตอบต่างจากที่ผมคิดตรงไหน

เพราะความคลุมเครือที่เจอตอนอ่าน story ราคาเท่ากับหนึ่งคำถาม ส่วนความคลุมเครือเดียวกันที่เจอตอน UAT ราคาเท่ากับความเชื่อใจของลูกค้า