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

บรรทัดที่หลายทีมคัดลอกต่อๆ กันมาใส่ไฟล์ตั้งค่าของ coding agent มักหน้าตาคล้ายกันหมด คือให้เขียนเทสต์หนึ่งตัวให้แดงก่อน แล้วค่อยเขียนโค้ดให้เขียว จากนั้นจึงขยับไปตัวถัดไป เหตุผลเบื้องหลังฟังขึ้นจนแทบไม่มีใครหยุดตรวจ เพราะ TDD ช่วยให้ทีมที่เป็นมนุษย์ได้ design ที่ดีขึ้นและได้เทสต์ที่จับ regression ได้จริงมานานแล้ว ถ้าวินัยนี้ได้ผลกับคน ก็น่าจะได้ผลกับ agent
Birgitta Böckeler จาก Thoughtworks ทดสอบข้อสันนิษฐานนั้นในซีรีส์ Exploring Gen AI บน martinfowler.com ซึ่งรวบรวมการทดลองของ technologist จาก Thoughtworks ว่าด้วยการใช้ gen AI ทำซอฟต์แวร์ วิธีวัดคือให้ agent ทำโจทย์เดียวกันหลายรอบ ครึ่งหนึ่งสั่งให้ทำ TDD อีกครึ่งหนึ่งไม่สั่ง แล้วส่งคำตอบทั้งหมดให้อีกโมเดลตัดสินคุณภาพโดยไม่บอกว่าคำตอบไหนมาจากวิธีใด ผลรวมไม่พบความต่างที่ชัดเจน และมีมากกว่าหนึ่งครั้งที่ฝั่งไม่ได้ทำ TDD ได้คะแนนด้าน design และคุณภาพเทสต์สูงกว่าเล็กน้อย
การทดลองนี้ระบุขอบเขตไว้ตรงๆ ว่าเป็น exploratory evaluation ที่ตั้งใจสำรวจคำถามเพียงเบื้องต้น ไม่ใช่ eval เต็มรูปแบบ สิ่งที่ได้จึงเป็นสมมติฐานให้คิดต่อ ยังไม่ใช่ข้อพิสูจน์ว่าคำสั่ง TDD ไร้ประโยชน์
TDD กับ AI มีสามแบบ และมีแบบเดียวที่ถูกวัด

ก่อนจะเถียงกันเรื่องผล ต้องแยกก่อนว่าการใช้ TDD กับ AI หมายถึงอะไร เพราะบทความแบ่งไว้สามแบบที่มีกระบวนการต่างกันมาก
- คนเขียนเทสต์เอง คนกำหนด test scenario ด้วยตัวเอง จะเป็นภาษาธรรมชาติ · แบบ BDD · หรือเขียนเป็นโค้ดตรงๆ ก็ได้ แล้วให้ AI เขียน implementation จนผ่าน โดยอาจมีขั้นแปลง scenario ของคนเป็นโค้ดคั่นอยู่
- AI เขียนเทสต์ คนอ่านก่อนไปต่อ AI เขียนเทสต์ที่แดงขึ้นมา คนอ่านตรวจว่าเทสต์นั้นตรวจพฤติกรรมที่ต้องการจริงไหม แล้ว AI ค่อยเขียน implementation
- agent เดินครบวงจรในลูปตัวเอง สั่งให้ agent เขียนเทสต์ที่แดงก่อนทีละตัว แล้วเขียน implementation แล้วเช็กเองว่าเทสต์ที่เพิ่งแดงกลายเป็นเขียว
แบบที่สามเป็นแบบที่บทความระบุว่าพบมากที่สุดในตอนนี้ และเป็นแบบเดียวที่การทดลองนี้วัด การแบ่งสามแบบนี้มีประโยชน์ตั้งแต่ยังไม่รู้ผล เพราะบรรทัดในไฟล์ตั้งค่าที่สั่งให้เขียนเทสต์ให้แดงก่อนเสมอ เท่ากับเลือกแบบที่สามไปแล้วโดยไม่ต้องประกาศ ส่วนทีมที่ยังหยุดเพื่อตรวจเทสต์ก่อนปล่อยให้เขียนโค้ด ยังอยู่ในแบบที่สอง และผลทั้งหมดต่อจากนี้พูดถึงแบบที่สามเท่านั้น
การทดลองวัดอะไร และเชื่อได้แค่ไหน
โจทย์มีสามขนาด เล็ก กลาง ใหญ่ ทั้งหมดเป็นงาน greenfield ที่มีแต่ business logic เช่น โมดูลตรวจรหัสนัดหมายทางการแพทย์ · pipeline สี่ขั้นที่แปลงสตริงเป็นรายงานข้อความ · loyalty points engine ที่มีอัตราสะสมตามระดับสมาชิกและการแลกแต้ม การทดลองจงใจใช้ logic ที่เฉพาะตัวและแปลกพอ เพื่อไม่ให้โมเดลดึงสิ่งที่มีอยู่มากแล้วใน training data มาตอบเหมือนกันหมด
ทุกรอบใช้ Sonnet 4.6 เขียนคำตอบ และใช้คำสั่งเดียวกันว่าต้องได้ code coverage อย่างน้อย 80% การทดลองแบ่งเป็น 5 batch แต่ละ batch มีสองคำตอบที่ไม่ได้สั่ง TDD และสองคำตอบที่สั่ง TDD กระจายเป็นงานเล็ก 1 batch · งานกลาง 3 batch · งานใหญ่ 1 batch มี batch หนึ่งที่เพิ่มอีกสองรอบ โดยสั่งเพียงให้เขียนเทสต์ก่อน ไม่ได้บังคับวินัย red-green ทีละขั้น เรียกว่าสาย test-first
ก่อนนำผลมาเทียบกัน ยังมี agent อีกตัวไล่อ่าน session transcript ของทุกรอบที่จัดเป็น TDD เพื่อยืนยันว่าแต่ละรอบทำตาม workflow จริงมากน้อยแค่ไหน จะได้ไม่เผลอนับรอบที่ไม่ได้ทำจริง จากนั้น Opus 4.8 ตัดสินคุณภาพของคำตอบและเทสต์โดยไม่รู้ว่าแต่ละคำตอบมาจากวิธีไหน และไม่ได้รับเกณฑ์คุณภาพที่กำหนดไว้อย่างละเอียด เพราะยิ่งระบุละเอียด โมเดลก็ยิ่งอาจ over-index กับเกณฑ์นั้น Opus จึงคิด rubric ขึ้นมาเองในตอนนั้น แล้วส่งต่อให้ subagent ทุกตัวที่ประเมินคำตอบแต่ละชิ้น ผลดิบทั้งหมดเปิดให้ไล่ดูได้ที่ repo tdd-comparisons
ผลที่ออกมา กับราคาที่จ่ายไป

ในงานเล็กและในงานกลางที่ยังใช้ prompt ชุดเดิม ผลออกมาซ้ำกัน คือ Opus จัดคำตอบที่ไม่ได้ทำ TDD ไว้อันดับ 1 และ 2 ส่วนคำตอบที่ทำ TDD ตามมาที่อันดับ 3 และ 4 คะแนนของงานเล็กออกมาแบบนี้ โดยให้คะแนนเต็ม 10 ทั้งสามด้าน
| รอบ | Design / Code / Tests | เฉลี่ย |
|---|---|---|
| ไม่ทำ TDD ตัวที่ 1 | 8 / 9 / 9 | 8.67 |
| ไม่ทำ TDD ตัวที่ 2 | 8 / 8 / 8 | 8.00 |
| ทำ TDD ตัวที่ 1 | 7 / 8 / 7 | 7.33 |
| ทำ TDD ตัวที่ 2 | 6 / 7 / 7 | 6.67 |
ระยะห่างระดับนี้ยังไม่ถึงขั้นคนละชั้น ส่วนงานใหญ่ให้ภาพต่างออกไป สองรอบที่ไม่ทำ TDD ได้ทั้งอันดับดีที่สุดและแย่ที่สุด ขณะที่รอบ TDD อยู่กลางตาราง เมื่อรวมทุก batch ทั้งสองฝั่งเคยได้ทั้งที่หนึ่งและที่โหล่ โดยบทความสรุปว่าภาพรวมของฝั่ง TDD แย่กว่าเล็กน้อย
ตัวชี้วัดที่ไม่ได้มาจากการตัดสินของโมเดลก็ไม่เข้าข้างฝั่ง TDD เช่นกัน นั่นคือ mutation score ซึ่งวัดโดยจงใจแก้โค้ดให้พังทีละจุด แล้วนับว่าเทสต์จับความเสียหายได้กี่เปอร์เซ็นต์ ในงานกลางรอบแรก ฝั่งไม่ทำ TDD ได้ 84.2% กับ 89.6% ส่วนฝั่ง TDD ได้ 81.0% กับ 77.3% ในงานเล็ก ฝั่ง TDD ขึ้นนำเล็กน้อยที่ 93.6% กับ 93.2% เทียบกับ 89.6% กับ 92.3% แล้วงานใหญ่ก็กลับมาใกล้กันอีกครั้ง บทความจึงสรุปว่าไม่มีสัญญาณว่าการทำ TDD ให้ mutation score ที่ดีกว่าอย่างมีความหมาย
สิ่งที่ต่างกันชัดจริงๆ มีสองอย่าง อย่างแรกคือจำนวนเทสต์ รอบที่ทำ TDD ได้เทสต์น้อยกว่าอย่างเห็นได้ชัดในทุกงาน งานเล็กได้ 21 กับ 20 ตัว เทียบกับ 61 กับ 58 ตัวของฝั่งที่ไม่ได้สั่ง งานใหญ่ก็ให้ผลแบบเดียวกัน คือ 22 กับ 21 ตัว เทียบกับ 69 กับ 74 ตัว อย่างที่สองคือราคา บทความสรุปว่าการทำ TDD กินโทเคนอย่างน้อย 3 เท่า แต่เตือนว่าตัวเลขนี้เป็นเพียง proxy คร่าวๆ ของต้นทุน session เพราะเป็นยอดสะสมตลอดบทสนทนา และ context ที่แต่ละ turn อ่านซ้ำก็ถูกนับใหม่ทุกครั้ง ตัวเลขจึงสะท้อนจำนวน turn ที่ถ่วงด้วยขนาด context มากกว่าจะสะท้อนเงินจริง ควรอ่านเป็นเพียงทิศทางว่าต้นทุนสูงขึ้นหลายเท่าอย่างสม่ำเสมอ ส่วนจะสูงกว่ากี่เท่ายังไม่แน่นอน
มีอยู่ครั้งเดียวที่คำตอบสาย TDD ขึ้นเป็นอันดับ 1 และเกิดขึ้นหลังจากเสริม prompt ด้วยขั้นตอน refactor และ design review ที่ชัดเจนขึ้น คะแนนเฉลี่ยของรอบนั้นคือ 7.67 สูงกว่า 7.33 กับ 7.0 ของฝั่งไม่ทำ TDD แต่ใน batch เดียวกัน คำตอบ TDD อีกตัวที่ใช้ prompt เดียวกันเป๊ะกลับได้อันดับสุดท้ายด้วยคะแนน 6.67 ผลนี้จึงสอดคล้องกับความแปรปรวนที่พบตลอดการทดลอง มากกว่าจะเป็นชัยชนะของวิธีใดวิธีหนึ่ง
ทำไมฝั่งที่ไม่ทำ TDD ถึงขึ้นนำ
คำอธิบายมาจากช่วงที่ Opus ได้ดู session trace โดยรู้แล้วว่าแต่ละรอบใช้วิธีไหน สิ่งที่พบคือรอบที่ไม่ทำ TDD และรอบ test-first วาง design ทั้งก้อนก่อนลงมือเสมอ ตั้งแต่ architecture · data type · edge case · contract แล้วค่อยเขียนโค้ดหรือเทสต์ ส่วนรอบ TDD ไล่ทำทีละ requirement และทีละเทสต์ ผลคือฝั่งแรกได้ data model ที่ดีกว่า จับ edge case ที่พาดข้ามหลายส่วนได้มากกว่า และทำงานได้ครบกว่าเล็กน้อย
คำสั่ง TDD ที่ใช้ในการทดลองทำงานสวนทางกับการวาง design ล่วงหน้าแบบนั้นโดยตรง เพราะ design ในรอบ TDD ค่อยๆ เกิดจากการตัดสินใจเฉพาะจุดที่ดีที่สุดในแต่ละครั้ง แล้วแทบไม่มีการย้อนกลับมาทบทวน สุดท้ายโครงสร้างจึงถูกเทสต์ตัวแรกกำหนดไว้ ส่วนพฤติกรรมใดที่ agent นึกไม่ถึงว่าจะต้องเขียนเทสต์ให้ มันก็ไม่เขียนโค้ดส่วนนั้นออกมาเลย
สั่งไปแล้วไม่ได้แปลว่าได้ TDD
สิ่งที่คนใส่คำสั่งไว้ควรรู้ก่อนจะคิดเรื่องคุณภาพด้วยซ้ำ คือ agent ทำ TDD ได้ไม่ครบตามที่สั่ง พฤติกรรมที่เกิดซ้ำตลอดการทดลองมีสามอย่าง ได้แก่ เขียน implementation ก่อนแล้วค่อยย้อนมาสร้างเทสต์ · ข้ามขั้นยืนยันว่าเทสต์แดงจริง · และเขียนล่วงหน้าเกินกว่าที่เทสต์ตัวปัจจุบันต้องการ จนเทสต์ตัวถัดไปผ่านเองโดยไม่เคยแดงสักครั้ง prompt ที่ใช้ในการทดลองได้ผลดีพอกับ Sonnet แต่ทุก session ก็ยังพบความล้มเหลวเหล่านี้อยู่บ้าง
ปัญหาที่ลึกกว่านั้นคือความหมายของสีแดง เทสต์ที่แดงจะเป็นหลักฐานว่า failure เกิดจากเหตุผลที่ถูกต้องได้ก็ต่อเมื่อมีใครสักคนตรวจว่ามันแดงเพราะอะไร เมื่อ agent เป็นทั้งคนเขียนเทสต์และคนยืนยันเองว่าแดง สีแดงจึงบอกได้เพียงว่าเทสต์รันแล้วพบ failure แต่ไม่ได้บอกว่า failure นั้นเกิดจากเหตุผลที่ถูกต้อง
การเขียนเทสต์ก่อนก็ไม่ได้ช่วยป้องกันเทสต์ที่วนกลับมาตรวจตัวเอง บาง session ที่ทำ TDD ยังได้เทสต์ที่นำผลลัพธ์ของ implementation มาเทียบกับตัวมันเอง โดยรันโค้ดชุดเดิมซ้ำเพื่อสร้างคำตอบที่คาดหวัง คำสั่งให้ implement เท่าที่จำเป็นก็เช่นกัน เพราะไม่อาจหยุด agent ไม่ให้เขียนเกินได้อย่างน่าเชื่อถือ ในเมื่อมันมี requirement ทั้งก้อนอยู่ในมือตั้งแต่แรก และบทความก็ระบุว่าการป้อน spec ทีละชิ้นเป็นวิธีที่ไม่มีประสิทธิภาพ
แล้วควรใส่อะไรแทนในไฟล์ตั้งค่า
คำถามที่บทความทิ้งไว้คมกว่าตัวเลขทุกตัวคือ ถ้าไม่มี checkpoint ของคนคั่นระหว่างเทสต์กับ implementation การเขียนเทสต์ก่อนยังเหลือจุดประสงค์อะไรอยู่ คนที่เขียนเทสต์ก่อนต้องเผชิญความฝืดจากการระบุพฤติกรรมทั้งที่ยังไม่รู้ว่าจะสร้างมันขึ้นมาอย่างไร ส่วน agent ไม่ได้รู้สึกถึงความฝืดนั้น มันเขียนเทสต์ได้ในเวลาเดียวกับที่วางแผน implementation
ทางเลือกแรกจึงเป็นการเพิ่ม checkpoint ก่อนเขียน implementation โดยให้คนอ่านเทสต์แดง หรือกำหนดขั้น design review ใน prompt ให้ชัดเจน ทางเลือกที่สองคือเลิกเขียนคำสั่งบอกโมเดลทีละก้าวว่าต้องทำอย่างไร แล้วหันไปทุ่มกับการตรวจผลลัพธ์แทน ข้อเสนอที่บทความปิดท้ายไว้คือการระบุอย่างละเอียดว่าอยากให้โมเดลทำอย่างไรไม่ใช่แนวทางที่ยั่งยืน สิ่งที่ควรทำคือหาวิธีติดตามผลลัพธ์และป้อน feedback กลับให้มากที่สุด ทำกระบวนการเหล่านั้นให้เป็นอัตโนมัติเท่าที่ทำได้ แล้วเลือกให้ดีว่าจะให้คนเข้ามาตัดสินว่าอะไรดีหรือถูกต้องตรงจุดไหน
ทางเลือกที่ผู้ทดลองนำมาใช้แทนคำสั่ง TDD ยาวๆ มีดังนี้
- ดูแลคุณภาพของเทสต์สำหรับจับ regression ด้วย mutation testing แทนการเขียนคำสั่งยาวแล้วภาวนาว่า agent จะทำตาม
- ให้ agent เข้าถึง static code analysis เพื่อกระตุ้นให้เกิดการ refactor
- รีวิวโครงสร้างและ modularity เป็นระยะ
- สร้าง ritual ของทีมที่ทำให้ทุกคนเข้าใจ codebase และจับ drift ได้เร็ว
- ติดตามแนวโน้มจำนวนไฟล์ที่แตะต่อการเปลี่ยนหนึ่งครั้ง และจำนวนโทเคนต่อการเปลี่ยนหนึ่งครั้ง
ผู้ทดลองเองเลิกสั่งให้ coding agent เขียนเทสต์ก่อน และจะไม่กลับมาใช้คำสั่งนี้จนกว่าจะเห็น eval หรือเหตุผลที่หนักแน่นกว่านี้ โดยหันไปให้ความสำคัญกับประโยชน์ของ TDD นอกลูปของ agent แทน ประโยคปิดของบทความบอกว่าบทบาทของ TDD แบบที่เคยรู้จักกันมานั้นลดลงมากเมื่อเทียบกับยุคก่อน GenAI
ข้อสรุปนี้ยังมีขอบเขตจำกัด เพราะการทดลองทั้งหมดใช้แต่งาน greenfield ขนาดไม่ใหญ่ที่เป็น business logic ล้วน ไม่มีรอบไหนแตะ codebase เก่าหรือระบบใหญ่เลย ทีมที่ใช้ agent แก้ของเดิมอยู่ทุกวันจึงยังไม่มีข้อมูลจากการทดลองนี้ให้ยึด สิ่งที่ตรวจได้ทันทีคือเปิดไฟล์ตั้งค่าของตัวเองขึ้นมาดูว่าบรรทัด TDD ที่ใส่ไว้ให้อะไรกลับมาจริงๆ
ที่มา: บทความ TDD inside the agent loop - theater or actual value? จาก martinfowler.com
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
NotebookLM ฉบับเข้าใจง่าย โยนเอกสารให้ AI อ่าน แล้วได้สรุป พอดแคสต์ และคลังความรู้ส่วนตัว
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
Claude Cowork · The Business Playbook

ฉบับภาษาไทย 15 บท เรียนรู้ผ่านโปรเจกต์จำลองต่อเนื่องทั้งเล่ม ตั้งแต่ตั้งค่า Workspace จัดการไฟล์ เชื่อมแอป ตั้งระบบอัตโนมัติ จนถึงสร้าง Plugin


