eugenemind.com
← กลับไปที่บล็อก

7 พฤศจิกายน 2569 · 11 นาทีในการอ่าน

ADR สำหรับเอเจนต์ AI เก็บเหตุผลเบื้องหลังการตัดสินใจด้านสถาปัตยกรรม

#ai #architecture #adr #development

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

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

แต่ทีมเคยพิจารณาวิธีนี้ไปแล้วเมื่อหลายเดือนก่อน และตัดสินใจไม่ทำ

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

ทีมจึงแยกการทำงานนี้ออกมาเป็นโมดูลเฉพาะ เพื่อไม่ให้ตะกร้าทั่วไปซับซ้อนขึ้นและไม่กระทบขั้นตอนการซื้อที่มีอยู่แล้ว

เอเจนต์ไม่รู้เหตุผลนี้ มันเห็นโค้ดซ้ำและเสนอให้รีแฟกเตอร์ โดยไม่ทราบว่าเหตุใดทีมจึงแยกสองโมดูลตั้งแต่แรก

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

ADR มีไว้ทำอะไร

Architecture Decision Record หรือ ADR คือบันทึกสั้น ๆ เกี่ยวกับการตัดสินใจด้านสถาปัตยกรรมซอฟต์แวร์ Michael Nygard อธิบายแนวทางนี้ไว้ตั้งแต่ปี 2011 ในบทความ Documenting Architecture Decisions

ADR เก็บเหตุผลของการตัดสินใจ ทางเลือกที่พิจารณา และผลที่ตามมา สำหรับตัวอย่างนี้ บันทึกอาจสั้นเพียงเท่านี้

# ADR-014: แยกโมดูลสำหรับจองสินค้า

Task: SHOP-284
Status: Accepted
Module: DropReservation

## Context
ตะกร้าทั่วไปไม่ได้กันสต็อกสินค้า
สินค้าลิมิเต็ดต้องจองผ่านเซิร์ฟเวอร์
และมีเวลาหมดอายุของการจอง

## Decision
แยกระบบจองสินค้าออกจาก Cart

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

## Consequences
ยังมีโค้ดบางส่วนซ้ำกัน
แต่สองโมดูลพัฒนาต่อได้อย่างอิสระ

## Revisit
พิจารณาใหม่หากมีระบบจองสินค้า
ส่วนกลางที่ใช้ร่วมกันได้

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

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

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

แนวทางของ Matt Pocock

ใน รีโพสิทอรีรวมสกิลของ Matt Pocock มีสกิลชื่อ domain-modeling ซึ่งครอบคลุมการสร้าง ADR ด้วย

สกิลนี้แนะนำให้เสนอการสร้าง ADR เฉพาะเมื่อเข้าเงื่อนไขครบทั้งสามข้อ

  1. การย้อนกลับไปเปลี่ยนการตัดสินใจนั้นทำได้ยากหรือมีต้นทุนสูง
  2. คนที่มาอ่านภายหลังโดยไม่มีบริบทจะสงสัยว่าทำไมจึงเลือกวิธีนี้
  3. มีทางเลือกอื่นที่ทีมพิจารณาจริงก่อนตัดสินใจ

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

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

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

ไม่ได้หมายความว่าการแก้บั๊กทุกครั้งต้องมี ADR ถ้าไม่มีการตัดสินใจทางเทคนิคที่สำคัญ การสร้างเอกสารเพิ่มก็มีแต่จะเพิ่มสิ่งที่ต้องอ่าน

ADR ควรถือว่าเสร็จสมบูรณ์เมื่อไร

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

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

สำหรับผม ADR จะเป็นอาร์ติแฟกต์ฉบับสุดท้ายเมื่อปิดงานแล้ว ซึ่งโดยทั่วไปคือหลังจากเมิร์จโค้ดเรียบร้อย

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

การให้ AI สร้าง ADR ใหม่จากโค้ดสุดท้ายเพียงอย่างเดียวเสี่ยงกว่า เพราะมันอาจแต่งเหตุผลที่ฟังดูสมเหตุสมผล ทั้งที่ทีมเลือกวิธีนั้นด้วยเหตุผลอื่น

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

ผมจะเก็บ ADR ฉบับสุดท้ายไว้กับงานนั้น อย่างน้อยก็เป็นคอมเมนต์แยกใน Jira, Linear หรือระบบติดตามงานที่ทีมใช้

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

เครื่องมือที่มีอยู่แล้ว

นอกจากสกิลของ Matt Pocock ยังมีเครื่องมือสำหรับสร้าง ADR อัตโนมัติอีกหลายตัว

auto-adr ใช้กับ Claude Code ได้ เมื่อเรียกคำสั่ง /adr เอเจนต์จะสร้างเอกสารจากประวัติของเซสชันปัจจุบัน จึงเก็บการตัดสินใจที่เกิดขึ้นระหว่างพัฒนาได้ โดยไม่ต้องพยายามเดาเหตุผลจากโค้ดเพียงอย่างเดียว

docflow มีกระบวนการที่เป็นระบบมากกว่า มีสกิลสำหรับสร้าง ADR จัดการงาน และตรวจเอกสารเมื่อจบงาน

อีกตัวอย่างหนึ่งมาจากบทความของ Andrew Connell ชื่อ Architecture Decision Records as Long-Term Memory for an AI Coding Agent

หลังใช้ Claude Code ทำงานในโปรเจกต์หลายเดือน เขามี ADR สะสม 141 รายการ เขาเพิ่มกฎให้เอเจนต์เสนอการบันทึกการตัดสินใจสำคัญหลังทำตามแผนเสร็จ และให้เจ้าของโปรเจกต์เป็นผู้ยืนยัน

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

เมื่อแก้โค้ดเก่า เอเจนต์ก็สามารถอ่านบันทึกเหล่านี้ก่อน แทนที่จะเสนอแนวทางที่ทีมเคยปฏิเสธไปแล้ว

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

ตั้งค่าแบบนี้ก็ได้

ตอนเริ่มต้นยังไม่จำเป็นต้องมีเครื่องมือแยก แค่กฎสั้น ๆ ใน AGENTS.md หรือ CLAUDE.md ที่เอเจนต์อ่านทุกเซสชันก็พอ ผมเคยเขียนเรื่องคำสั่งแบบนี้ไว้ในบทความ เรื่อง AGENTS.md สำหรับ Codex และ Claude Code

## ADR

ระหว่างทำงาน ให้จดฉบับร่างของการตัดสินใจ
ไว้ใน docs/adr/drafts/<task-id>.md
บันทึกตัวเลือกที่เลือก
ทางเลือกที่ไม่เลือก และเหตุผล

ก่อนปิดงาน ให้ตรวจเงื่อนไขสามข้อ
1. การตัดสินใจนี้เปลี่ยนภายหลังได้ยากหรือมีต้นทุนสูง
2. ถ้าไม่มีบริบท คนอ่านจะไม่เข้าใจว่าทำไมจึงทำแบบนี้
3. มีทางเลือกอื่นที่พิจารณาจริง

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

จะเก็บบันทึกฉบับสุดท้ายไว้ที่ไหนขึ้นอยู่กับว่าเอเจนต์เข้าถึงอะไรได้บ้าง ถ้าเอเจนต์ทำงานกับ Jira หรือ Linear ผ่านการเชื่อมต่อระบบได้ ก็เก็บ ADR เป็นคอมเมนต์ในงานนั้นได้เลย ถ้าไม่ได้ การเก็บในโฟลเดอร์ docs/adr/ ในรีโพสิทอรีจะสะดวกกว่า โดยตั้งชื่อไฟล์ด้วยเลขลำดับและชื่อสั้น ๆ เช่น 0014-drop-reservation.md แบบนี้เอเจนต์จะค้นเจอได้ด้วยการค้นหาโค้ดตามปกติ และในงานก็มีลิงก์ไปยังไฟล์นั้น

ตัวกฎเองควรสั้นไว้ ส่วนเทมเพลต ADR แยกไว้ในไฟล์หรือสกิลต่างหาก แล้วโหลดเฉพาะตอนที่ต้องเขียนบันทึกจริง ๆ ไม่เช่นนั้นคำสั่งสำหรับเอเจนต์จะยาวขึ้นเร็วกว่าการตัดสินใจเสียอีก

สรุป

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

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

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

บทความที่เกี่ยวข้อง