บทที่ 6 — ระบบที่ทำให้ AI ทำงานถูกทาง
AI ที่ไม่มีกรอบจะสร้างของเร็วมากแต่เละเร็วพอกัน — เขียน component ซ้ำสามอัน วางไฟล์คนละที่ทุกครั้ง ลืมกฎที่เคยตกลงกันไว้เมื่อวาน
บทนี้คือ ระบบ 5 ชั้น ที่โปรเจกต์นี้ใช้กันปัญหานั้น ทุกชั้นมีอยู่จริงใน repo เปิดดูได้เลย
5 ชั้นที่คุมคุณภาพงาน AI (คลิกดูทีละชั้น)
คลิกชั้นใดก็ได้เพื่อดูรายละเอียด
1. กฎที่โหลดอัตโนมัติ
กติกาทั้งหมดเขียนไว้ที่เดียว AI อ่านเองทุก session ทุกคน — ไม่ต้องพิมพ์ย้ำ และ dev คนใหม่ได้กฎชุดเดียวกัน
2. เอกสารที่ผูกกับประเภทงาน
AGENTS.md มีตารางว่างานแบบไหนต้องอ่าน doc ไหนก่อน เช่นแตะฐานข้อมูลต้องอ่าน docs/database.md ก่อน AI จึงไม่ออกแบบตารางใหม่ทับของเดิม
3. บันทึกการตัดสินใจ
ทำไมเลือกวิธีนี้ ทางอื่นทำไมไม่เอา — กัน AI (และคน) มาเปลี่ยนกลับด้วยเหตุผลที่เคยพิจารณาแล้ว
4. ตาข่ายอัตโนมัติ
typecheck / lint / build / docker build ทุก PR — จับของพังที่สายตาคนมองข้าม และจับตอน AI มั่นใจผิด ๆ
5. คนกดปุ่มสุดท้าย
AI เตรียม PR ได้ แต่คนเป็นคนตัดสินใจว่าจะ merge เข้า uat (= ปล่อยขึ้นเว็บจริง) เมื่อไหร่
ชั้นที่ 1: AGENTS.md — กฎที่ไม่ต้องพิมพ์ซ้ำ
ปัญหาคลาสสิกของการทำงานกับ AI: คุณบอกกฎไปในแชท พอเปิดหน้าต่างใหม่ มันลืมหมด และ dev คนอื่นก็ไม่เคยได้ยินกฎนั้นเลย
ทางแก้คือเขียนกฎลงไฟล์ที่ AI อ่านอัตโนมัติ ตัวอย่างกฎจริงในโปรเจกต์นี้:
| กฎ | เหตุผล |
|---|---|
แตก branch ใหม่จาก develop ทุกงาน ห้าม commit ตรง |
กันงานครึ่ง ๆ หลุดขึ้นเว็บ |
| ราคาทุกจำนวนเก็บเป็นจำนวนเต็มสตางค์ | เลขทศนิยมทำให้ยอดเงินเพี้ยนได้ |
| ห้ามเชื่อราคา/สต็อกที่ส่งมาจากเบราว์เซอร์ | ลูกค้าแก้ค่าในหน้าเว็บได้ ต้องคิดใหม่ที่ server เสมอ |
ห้ามใช้ any ใน TypeScript |
ปิดตาระบบตรวจ type ทั้งระบบ |
| ห้ามใช้ emoji เป็นไอคอนใน UI | แสดงผลไม่เหมือนกันในแต่ละเครื่อง ทำให้ดูไม่มืออาชีพ |
| แตะ API/ฐานข้อมูล → ต้องอัปเดตเอกสาร + เทสต์ใน PR เดียวกัน | ถ้าแยกไปทำทีหลัง มันจะไม่ถูกทำ |
ลองทำเอง: เปิดไฟล์
AGENTS.mdใน repo แล้วอ่านหัวข้อ MANDATORY: branch per task กับ Deployment — สองอันนี้คือกฎที่คุณจะได้ใช้จริงตั้งแต่วันแรก
ชั้นที่ 2: เอกสารที่ผูกกับงาน
ไม่ใช่แค่ "มีเอกสาร" แต่ต้องบอกด้วยว่า งานแบบไหนต้องอ่านอันไหนก่อนลงมือ
จะแตะอะไร → ต้องอ่านอะไรก่อน (คลิกดู)
ก่อนเริ่มทุกงาน
ตามประเภทงาน
คลิกกล่องด้านบนเพื่อดูคำอธิบาย
docs/implementation-plan.md
ดูว่าตอนนี้โปรเจกต์อยู่เฟสไหน งานที่จะทำอยู่ในขอบเขตหรือยัง และมีข้อสมมติอะไรบันทึกไว้แล้ว
docs/ApexHuas.md
สเปกต้นฉบับจากลูกค้า 41 หัวข้อ — เป็นแหล่งความจริงว่าระบบต้องทำอะไรได้บ้าง
แตะฐานข้อมูล → database.md
มีตารางอะไรบ้าง ความสัมพันธ์เป็นยังไง กฎการออกแบบ เช่นห้ามลบข้อมูลจริงให้ใช้ archive แทน
แตะ auth/ไฟล์/ชำระเงิน → security.md
ใครมีสิทธิ์ทำอะไร กฎอัปโหลดไฟล์ การเก็บ log และสิ่งที่ห้าม log เด็ดขาด
เพิ่มหน้า/ฟีเจอร์ → architecture.md
โครงสร้างโฟลเดอร์ แผนที่ route และหลักการวางโค้ด
แตะ UI → DESIGN.md
สี ตัวอักษร ระยะห่าง component ที่มีอยู่ — กัน AI สร้างสไตล์ใหม่ที่หลุดจากของเดิม
แตะ deploy → uat-deploy.md
server อยู่ไหน deploy ยังไง secret มีอะไรบ้าง
ผลลัพธ์: AI ไม่ต้องเดา และงานที่ได้จะเข้ากับของเดิมตั้งแต่รอบแรก
ชั้นที่ 3: ADR — จดว่าทำไมถึงเลือกแบบนี้
ADR (Architecture Decision Record) คือบันทึกสั้น ๆ หนึ่งไฟล์ต่อหนึ่งการตัดสินใจสำคัญ
ตัวอย่างจริงใน repo นี้:
ADR ที่มีอยู่จริง
-
ADR 0001 — เขียนระบบสองภาษาเอง ไม่ใช้ library
เหตุผล: Next.js 16 เพิ่งเปลี่ยนโครงสร้างครั้งใหญ่ library ยังตามไม่ทัน และเรามีแค่ 2 ภาษา ไม่คุ้มกับความเสี่ยง
-
ADR 0002 — deploy ด้วย SSH + credential ใช้แล้วทิ้ง
เหตุผล: ไม่อยากฝัง token ถาวรบน server เพราะเป็นของที่ต้องคอยหมุนเปลี่ยนและลืมง่าย
เมื่อไหร่ต้องเขียน ADR: การตัดสินใจที่ย้อนยาก / ที่คนอ่านในอนาคตจะงง / ที่กระทบทั้งระบบ — งานปกติไม่ต้องเขียน
ชั้นที่ 4–5: CI และคน
สองชั้นนี้มีบทของตัวเอง (บทที่ 7–8 เรื่อง CI และบทที่ 11 เรื่อง deploy) แต่ประเด็นสำคัญคือ มันซ้อนกัน — ของที่หลุดชั้นหนึ่งยังมีอีกชั้นรอรับ
ทำไมต้องมีหลายชั้น
มีระบบซ้อนกัน
- AI ลืมกฎ → AGENTS.md เตือนตั้งแต่ยังไม่เริ่ม
- โค้ดพลาด type → typecheck จับ
- เขียนผิดแพทเทิร์นอันตราย → lint จับ
- พังตอน build จริง → CI จับก่อนถึง server
- ฟีเจอร์ทำงานไม่ตรงใจ → คนรีวิวจับ
- เว็บล่มหลัง deploy → health check จับแล้วขึ้นแดง
ไม่มีระบบ
- ทุกอย่างขึ้นกับความจำของคนสั่งงาน
- ปัญหาไปโผล่ตอนลูกค้าเปิดเจอ
- ไม่รู้ว่าเว็บที่รันอยู่มาจากโค้ดชุดไหน
- แก้บั๊กเดิมซ้ำ ๆ เพราะไม่มีใครจดว่าเคยแก้ยังไง
- dev คนใหม่เข้ามาแล้วทำผิดแบบเดิมทั้งหมด
วิธีทำงานแบบ mock ก่อน ต่อของจริงทีหลัง
โปรเจกต์นี้เลือกสร้าง ทั้งเว็บด้วยข้อมูลปลอมก่อน แล้วค่อยต่อฐานข้อมูลจริง เหตุผลคือ:
- เห็นภาพเร็ว ลูกค้าคอมเมนต์ได้ตั้งแต่ยังแก้ถูก
- ตัดสินใจเรื่องหน้าตาและ flow ให้จบก่อน ค่อยลงแรงกับส่วนที่แก้ยาก
- ไม่เสียของ — เพราะกฎบังคับว่าข้อมูลปลอมต้องอยู่ในโฟลเดอร์
_mocks/แยกชัด พอต่อของจริงก็ลบโฟลเดอร์นั้นทิ้ง UI ทั้งหมดยังอยู่ครบ
เส้นทาง mock-first ของโปรเจกต์นี้
1. M1 ระบบดีไซน์ + หน้าแรก
กำหนดสี ฟอนต์ component พื้นฐาน และระบบสองภาษา ให้ทุกหน้าหลังจากนี้หน้าตาเป็นชุดเดียวกัน
2. M2 แคตตาล็อกสินค้า
หน้ารายการ + ตัวกรอง + หน้ารายละเอียดสินค้า ใช้สินค้าปลอม 24 รายการที่มีสเปกครบเหมือนของจริง
3. M3 หน้าข้อมูล + ล็อกอิน
about/ติดต่อ/FAQ/ขอใบเสนอราคา และหน้า auth ที่กรอกอะไรก็ผ่าน (ติดป้ายว่าโหมดเดโมชัดเจน)
4. M4 ตะกร้า + ชำระเงิน
ตะกร้าที่จำของข้ามหน้าได้จริง และ checkout 4 ขั้นจบด้วยเลขออเดอร์ปลอม
5. M5 บัญชีลูกค้า
ประวัติคำสั่งซื้อ ที่อยู่ รายการโปรด ใบเสนอราคา
6. M6 หลังบ้าน
17 หน้าสำหรับแอดมิน — จัดการสินค้า คลัง ออเดอร์ พนักงาน สิทธิ์ log
7. ต่อจากนี้: ต่อฐานข้อมูลจริง
ลบ _mocks/ ทีละส่วน แล้วต่อ PostgreSQL เข้าไปแทน โดย UI ไม่ต้องรื้อ
เช็คความเข้าใจ
-
เพราะตอนต่อข้อมูลจริง คุณแค่ลบโฟลเดอร์นั้นแล้วเสียบตัวดึงข้อมูลจริงเข้าไป ถ้าเขียนปนอยู่ในหน้าเว็บ จะต้องไล่แก้ทีละไฟล์และมีโอกาสหลงเหลือข้อมูลปลอมขึ้น production
-
อ่าน ADR เดิมก่อนว่าเหตุผลยังใช้ได้ไหม ถ้าสถานการณ์เปลี่ยนจริง (เช่น library ตามทันแล้ว) ให้เขียน ADR ใหม่ที่ 'แทนที่' ฉบับเก่า ไม่ใช่ลบของเก่าทิ้งเงียบ ๆ
-
เพราะทุกอย่างที่เบราว์เซอร์ส่งมาแก้ได้หมด ถ้า server เชื่อราคาที่ส่งมา คนซื้อจะแก้ราคาสินค้าเป็น 1 บาทได้ ระบบต้องดึงราคาจริงจากฐานข้อมูลมาคิดเองเสมอ
บทหน้า: ตาข่ายชั้นที่ 4 — CI ทำงานยังไงและอ่านผลยังไง