All posts

18 min readAI

ยุค agent = คุณต้องเขียน AC เหมือน PO: เมื่อทุกคนที่สั่งงาน agent คือเจ้าของโปรดักต์

เมื่อ coding agent เขียนโค้ดได้เร็วกว่าที่เราคิดทัน คอขวดของงานจึงย้ายจากการพิมพ์โค้ดไปอยู่ที่คำถามเดียว คือ "เสร็จ" หน้าตาเป็นยังไง บันทึกจากเดฟ·PM·PO ว่าทำไมทุกคนที่สั่งงาน agent ถึงกลายเป็น PO โดยไม่รู้ตัว ทำไม output ที่ห่วยของ agent ส่วนใหญ่สะท้อน acceptance criteria ที่ห่วยของเรา และ AC แบบไหนที่ทั้ง junior และ agent หยิบไปทำต่อได้โดยไม่ต้องเดา

Sutthiphong NuanmaSoftware Developer

ประโยคที่ผมได้ยินบ่อยที่สุดในทีมช่วงนี้ไม่ใช่ "agent ทำไม่ได้" ครับ แต่คือ "agent ทำได้ แต่ไม่ใช่แบบที่อยากได้"

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

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

โพสต์ที่แล้วผมจบไว้ว่า ถ้าเวลามีจำกัดจนอ่าน PRD ได้แค่ส่วนเดียว ให้เลือกอ่าน acceptance criteria เพราะมันคือสิ่งที่ agent จะแปลงเป็น test โพสต์นี้คือการขยายประโยคนั้นครับ เพราะผมเริ่มเชื่อว่า AC ไม่ใช่แค่ส่วนหนึ่งของเอกสาร แต่เป็นทักษะหลักของทุกคนที่ทำงานกับ agent ไม่ว่าตำแหน่งในบริษัทจะเขียนว่าอะไร

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

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

ผมเห็นโพสต์หนึ่งบน X ที่พูดถึงไอเดียซึ่งช่วงนี้มีคนพูดกันเยอะในหลายรูปแบบ ใจความรวม ๆ คือเมื่อมี AI coding agent ช่วยเขียนโค้ด บทบาทของคนเขียนโปรแกรมจะเลื่อนไปเป็น product owner โดยปริยาย และคอขวดของงานไม่ได้อยู่ที่ความเร็วในการเขียนโค้ดอีกต่อไป แต่อยู่ที่ว่าเรานิยามได้ชัดแค่ไหนว่า "เสร็จ" แปลว่าอะไร

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

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

งานที่เคยเป็นของ PO ตอนนี้อยู่ในมือทุกคน

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

ตอนนี้สายงานสั้นลงครับ developer รับ requirement มา แล้วส่งต่อให้ agent ทันที ตำแหน่งของ developer ในสายงานเลยเปลี่ยนไปโดยไม่มีใครประกาศ จากคนที่ "รับ" AC มาตีความ กลายเป็นคนที่ "เขียน" AC ให้ agent ทำต่อ

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

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

ความต่างคือเมื่อก่อนถ้า AC ไม่ชัด developer ที่เป็นคนจะเดินมาถาม ตอนนี้ถ้า AC ไม่ชัด agent จะส่ง PR มาให้ในสิบนาที พร้อม test ที่เขียวครบ

งานเดียวกัน สองแบบ

ขอยกตัวอย่างให้เห็นภาพครับ ลูกค้าร้านขายของออนไลน์เจ้าหนึ่งพิมพ์มาใน LINE ประมาณว่า "อยากให้ลูกค้ายกเลิกออเดอร์เองได้ จะได้ไม่ต้องทักแอดมิน"

แบบแรก คือสิ่งที่ผมเห็นในทีมบ่อยที่สุด และยอมรับว่าผมเองก็ทำบ่อย

เพิ่มปุ่มยกเลิกออเดอร์ในหน้ารายละเอียดออเดอร์ของลูกค้า กดแล้วเปลี่ยนสถานะเป็น cancelled

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

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

แบบที่สอง คือเวอร์ชันที่ผมเขียนใหม่หลังจากโทรถามลูกค้าสิบนาที

เป้าหมาย: ลูกค้ายกเลิกออเดอร์ที่ร้านยังไม่ได้เริ่มเตรียมของได้เอง โดยไม่ต้องทักแอดมิน

AC 1 — ยกเลิกได้เฉพาะออเดอร์ที่ยังไม่เตรียมของ Given ออเดอร์อยู่ในสถานะ pending_payment หรือ paid When ลูกค้าเปิดหน้ารายละเอียดออเดอร์ Then เห็นปุ่ม "ยกเลิกออเดอร์"

AC 2 — ซ่อนปุ่มเมื่อร้านเริ่มเตรียมของแล้ว Given ออเดอร์อยู่ในสถานะ preparing, shipped หรือ delivered When ลูกค้าเปิดหน้ารายละเอียดออเดอร์ Then ไม่เห็นปุ่มยกเลิก และเห็นข้อความ "หากต้องการยกเลิก กรุณาติดต่อร้านค้า" พร้อมลิงก์ LINE OA

AC 3 — ต้องยืนยันก่อนยกเลิก Given ลูกค้ากดปุ่มยกเลิก When ระบบแสดงหน้าต่างยืนยัน Then ต้องเลือกเหตุผลจากรายการก่อนกดยืนยันได้ และกด "ไม่ยกเลิก" แล้วออเดอร์ต้องไม่เปลี่ยน

AC 4 — คืนสต็อกทันที Given ออเดอร์ถูกยกเลิกสำเร็จ Then จำนวนสินค้าทุกรายการในออเดอร์ถูกบวกกลับเข้าสต็อกในธุรกรรมเดียวกับการเปลี่ยนสถานะ

AC 5 — ออเดอร์ที่จ่ายแล้วไม่คืนเงินอัตโนมัติ Given ออเดอร์อยู่ในสถานะ paid และถูกยกเลิก Then สถานะเป็น cancelled_refund_pending และระบบแจ้งเตือนแอดมินในกลุ่ม LINE ของร้าน ห้าม implement การคืนเงินผ่าน payment gateway ในงานนี้

ยังไม่ทราบ: ลูกค้ายกเลิกได้ภายในกี่ชั่วโมงหลังจ่ายเงิน รอเจ้าของร้านยืนยัน ผู้ติดตามคือ Earth ระหว่างนี้ไม่ต้องจำกัดเวลา

นอกขอบเขต: การยกเลิกบางรายการในออเดอร์ การคืนเงินอัตโนมัติ

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

ที่น่าสนใจกว่านั้นคือ AC 5 กับบรรทัด "ยังไม่ทราบ" ไม่ได้มาจากความเก่งของผมครับ มันมาจากการที่ผมพยายามเขียน Given/When/Then ให้ครบ แล้วพบว่าตอบไม่ได้ การเขียน AC บังคับให้ผมเจอคำถามที่ผมไม่รู้ว่าตัวเองยังไม่ได้ถาม

เรื่องที่เกิดซ้ำกับ junior และ agent

ขอเล่าเป็นภาพรวมจากหลายงานนะครับ ไม่ใช่เคสใดเคสหนึ่ง แต่รูปแบบมันซ้ำจนผมเริ่มเห็นเป็น pattern

ผม assign งานให้น้อง junior คนหนึ่งด้วยคำอธิบายสั้น ๆ ใน ticket เช่น "ทำหน้าค้นหาลูกค้าในระบบหลังบ้าน ค้นจากชื่อหรือเบอร์โทรได้" น้องรับงาน เปิด agent วาง ticket ลงไปทั้งก้อน ได้หน้าค้นหาที่ใช้งานได้ภายในครึ่งชั่วโมง ส่ง PR มาให้ผมรีวิว

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

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

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

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

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

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

Output ห่วย มักแปลว่า AC ห่วย

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

ผมคิดว่ามีสามเหตุผลที่ทำให้ความเชื่อมโยงนี้แน่นกว่าสมัยก่อน

เหตุผลแรกคือ agent ไม่มีบริบทที่คนมี developer ที่อยู่ในทีมมาหนึ่งปีรู้ว่าลูกค้ารายนี้เกลียดหน้าต่าง popup รู้ว่าระบบนี้ห้ามลบข้อมูลจริง รู้ว่าเมื่อปีที่แล้วเคยมีปัญหาเรื่องเบอร์โทรซ้ำ ความรู้พวกนี้เคยทำหน้าที่เป็น AC ที่ไม่ได้เขียนไว้ agent ไม่มีสิ่งนี้เลยครับ AGENTS.md หรือ CLAUDE.md ช่วยได้ส่วนหนึ่ง แต่สิ่งที่เฉพาะกับงานชิ้นนี้ต้องอยู่ใน AC เท่านั้น

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

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

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

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

ต่อจาก Grill Me, OpenSpec และ PRD ที่ไม่มีใครอ่าน

ถ้ามองทั้งซีรีส์ ผมเห็นโพสต์นี้เป็นจุดที่สามโพสต์ล่าสุดมาบรรจบกันครับ

Grill Me คือวิธีทำให้ AC เกิดขึ้น ให้ agent ซักเราทีละข้อจนทุกการตัดสินใจมีเจ้าของ ผลลัพธ์ที่ดีที่สุดของรอบ grill คือรายการ AC ที่เรายืนยันได้ทุกข้อ

OpenSpec คือที่เก็บ AC ไว้ให้อยู่รอดเกิน session เดียว scenario ในไฟล์ specs/ ที่เขียนแบบ WHEN/THEN ก็คือ AC ในรูปแบบที่ agent ตัวถัดไปอ่านได้และ review ได้

ส่วนโพสต์ PRD ที่ไม่มีใครอ่าน คือคำเตือนว่า AC ที่ AI ร่างให้แล้วเราไม่ได้อ่าน ไม่ใช่ AC ของเรา มันคือคำเดาที่อยู่ในรูปของ Given/When/Then ซึ่งอันตรายกว่าเดิมเพราะมันดูเป็นทางการ

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

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

AC ที่ดีสำหรับ agent หน้าตาเป็นยังไง

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

1. เริ่มจากเป้าหมายหนึ่งประโยค ว่างานนี้แก้ปัญหาอะไรให้ใคร agent ใช้ประโยคนี้ตัดสินใจในจุดที่ AC ไม่ได้ครอบคลุม ถ้าไม่มี มันจะตัดสินจากความคุ้นเคยกับระบบทั่วไปแทน

2. หนึ่ง AC หนึ่งพฤติกรรม ถ้าข้อเดียวมีคำว่า "และ" สามครั้ง แยกเป็นหลายข้อ เพราะ agent จะเขียน test ตามข้อ และ test ที่ตรวจหลายพฤติกรรมพร้อมกันจะบอกเราได้น้อยมากตอนมันล้ม

3. ใช้ Given/When/Then หรืออย่างน้อยให้มีครบสามส่วน สถานะเริ่มต้น การกระทำ และผลที่สังเกตได้ ส่วนที่คนมักลืมคือ Given ครับ "กดปุ่มยกเลิกแล้วออเดอร์ถูกยกเลิก" ไม่บอกว่าออเดอร์สถานะไหนกดได้ และนั่นคือที่ที่บั๊กครึ่งหนึ่งซ่อนอยู่

4. ผลลัพธ์ต้องตรวจได้ "หน้าค้นหาต้องเร็ว" ไม่ใช่ AC "ผลค้นหาแสดงภายใน 1 วินาทีสำหรับฐานข้อมูลลูกค้า 50,000 รายการ" คือ AC ถ้าเรายังไม่รู้ตัวเลข ให้เขียนว่ายังไม่รู้ อย่าเขียนคำที่ฟังดีแต่วัดไม่ได้

5. เขียนกรณีที่ห้ามเกิดด้วย AC ส่วนใหญ่บอกแค่สิ่งที่ต้องเกิด แต่ agent ต้องรู้สิ่งที่ห้ามเกิดด้วย เช่น "พนักงานสาขาต้องไม่เห็นลูกค้าของสาขาอื่น" หรือ "กด 'ไม่ยกเลิก' แล้วออเดอร์ต้องไม่เปลี่ยน" ข้อแบบนี้แหละที่ agent ไม่เคยเติมให้เอง

6. ใช้ชื่อจริงของสิ่งในระบบ ถ้าสถานะในฐานข้อมูลชื่อ paid ก็เขียน paid ไม่ใช่ "ชำระเงินแล้ว" agent จะไม่ต้องเดาว่าคำไทยในหัวเราตรงกับค่าไหนในโค้ด และคนรีวิวก็เทียบได้ทันที

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

8. มีหัวข้อ "นอกขอบเขต" agent ชอบช่วยครับ ถ้าเห็นว่าคืนเงินอัตโนมัติน่าจะดี มันอาจลงมือทำให้ด้วยความหวังดี การเขียนว่าอะไรไม่อยู่ในงานนี้กัน PR ที่บวมเกินกว่าที่เรารีวิวไหว

9. ทดสอบด้วยคำถามเดียว ก่อนส่ง ผมอ่าน AC ทั้งหมดแล้วถามว่า ถ้า agent ทำครบทุกข้อนี้ ผมจะกล้าส่งให้ลูกค้า UAT ไหม ถ้ายังไม่กล้า แปลว่ายังมี AC ที่อยู่ในหัวผมแต่ไม่อยู่บนหน้าจอ

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

## เป้าหมาย
<งานนี้แก้ปัญหาอะไรให้ใคร หนึ่งประโยค>

## Acceptance Criteria
### AC 1 — <ชื่อพฤติกรรมสั้น ๆ>
- Given <สถานะเริ่มต้น ใช้ชื่อจริงในระบบ>
- When <การกระทำ>
- Then <ผลที่ตรวจได้>

### AC 2 — <กรณีที่ห้ามเกิด>
- Given ...
- When ...
- Then ... ต้องไม่ ...

## ยังไม่ทราบ
- <คำถาม> — รอ <ใคร> ยืนยัน, ผู้ติดตาม: <ชื่อ>, ระหว่างนี้: <ทำอะไร / ห้ามทำอะไร>

## นอกขอบเขต
- <สิ่งที่ไม่ต้องทำในงานนี้>

## คำสั่งสำหรับ agent
- ถ้าเจอกรณีที่ AC ไม่ครอบคลุม ให้หยุดแล้วถาม อย่าเลือกเอง
- เขียน test ให้ครบทุก AC และอ้างหมายเลข AC ในชื่อ test
- สรุปการตัดสินใจที่ไม่ได้มาจาก AC ไว้ใน PR description

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

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

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

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

สอนน้องว่างานของน้องเริ่มก่อนเปิด agent ผมบอกน้อง junior ตรง ๆ ว่าในยุคนี้ ส่วนที่ยากที่สุดของงานไม่ใช่การเขียนโค้ดแล้ว แต่คือสิบห้านาทีก่อนกดส่งคำสั่งแรก ถ้าน้องอ่าน ticket แล้วเขียน Given/When/Then ไม่ได้ครบ นั่นไม่ใช่ความผิดของน้อง แต่เป็นสัญญาณว่าต้องกลับมาถามพี่ และการกลับมาถามคือการทำงาน ไม่ใช่การเสียเวลา

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

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

เขียน AC ด้วยภาษาเดียวกับที่ลูกค้าจะใช้ตอน UAT ถ้า AC ข้อไหนผมอ่านให้ลูกค้าฟังแล้วเขาไม่เข้าใจ ข้อนั้นอาจถูกต้องทางเทคนิค แต่ยังไม่ใช่ข้อตกลง AC ที่ดีควรใช้ได้ทั้งเป็นคำสั่งให้ agent และเป็นสิ่งที่ลูกค้าเซ็นรับได้

ยอมรับว่าบางงานไม่ต้องมี AC แก้ typo ปรับ spacing prototype ทิ้งเพื่อให้ลูกค้าเห็นภาพ งานพวกนี้ผมปล่อยให้ agent เดาได้ เพราะเดาผิดแล้วแก้ถูก คำถามเช็กยังเหมือนเดิมครับ ถ้า agent เดาผิดในงานนี้ ใครจะเป็นคนเจอ และเจอเมื่อไร ถ้าคำตอบคือลูกค้าตอน UAT งานนั้นต้องมี AC

ท้ายที่สุด

ตอนผมเริ่มทำงาน PO ใหม่ ๆ ผมคิดว่า AC เป็นงานเอกสารที่น่าเบื่อที่สุดในสายงาน เป็นสิ่งที่ต้องเขียนเพราะ process บอกให้เขียน ไม่ได้มีใครอ่านจริงจังนอกจากตอน UAT

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

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

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

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

เขียน AC ให้ชัดก่อนครับ แล้วค่อยให้ agent ลงมือ