AI Series Interview 16: Spec Coding ที่ดีควรเป็นอย่างไร?
Spec Coding ที่ดี (การเขียนโค้ดตามข้อกำหนด) หัวใจสำคัญคือการเปลี่ยน "ความคิดที่คลุมเครือ" ให้กลายเป็น "สัญญาที่แม่นยำ ตรวจสอบได้ และดำเนินการได้" มันไม่ใช่แค่การเขียนเอกสาร แต่เป็นการสร้างภาษาสื่อสารที่ไร้ความกำกวมระหว่างมนุษย์กับ AI (หรือระหว่างมนุษย์ด้วยกัน) ด้านล่างนี้我将อธิบายลักษณะของ spec ที่ดีจากสี่มิติ ได้แก่ โครงสร้างเนื้อหาของข้อกำหนด หลักการเขียน กระบวนการทำงานร่วมกับ AI และการตรวจสอบคุณภาพ
1. โครงสร้างมาตรฐานของเอกสารข้อกำหนด (ยกตัวอย่างโมดูลฟังก์ชัน)
| หัวข้อ | เนื้อหาที่ต้องมี | ตัวอย่าง |
|---|---|---|
| 1. เป้าหมายและขอบเขต | อธิบายสั้นๆ ว่าจะทำอะไร ระบุสิ่งที่ไม่ทำ | "สร้าง API สำหรับลงทะเบียนผู้ใช้ โดยไม่รวมการยืนยันอีเมล" |
| 2. สัญญาอินพุต/เอาต์พุต | โครงสร้างข้อมูล ชนิด ฟิลด์ที่ต้องระบุ/ไม่บังคับ ค่าตัวอย่าง | POST /register body {email: string, password: string} ตอบกลับ 201 หรือ 400 พร้อมรหัสข้อผิดพลาด |
| 3. พฤติกรรมและตรรกะ | กฎทางธุรกิจ เงื่อนไขขอบเขต การเปลี่ยนสถานะ | "รหัสผ่านยาว 8-20 ตัวอักษร ต้องมีตัวเลขอย่างน้อยหนึ่งตัว ถ้าอีเมลมีอยู่แล้วให้คืนค่า 409" |
| 4. การจัดการข้อผิดพลาด | สถานการณ์ยกเว้นทั้งหมดที่อาจเกิดขึ้น พร้อมรหัส/ข้อความข้อผิดพลาดที่สอดคล้อง | "การเชื่อมต่อฐานข้อมูลล้มเหลว → คืนค่า 503 โดยไม่เปิดเผย stack trace" |
| 5. ข้อกำหนดที่ไม่เกี่ยวกับฟังก์ชัน | ประสิทธิภาพ (เวลาตอบสนอง < 200ms), ความปลอดภัย (parameterized query), การบันทึก, การสังเกตได้ | "SQL ทั้งหมดต้องใช้ prepared statement; บันทึก email แต่ไม่บันทึก password" |
| 6. กรณีทดสอบ (สำคัญ) | อย่างน้อย 3 อินพุตทั่วไป + 2 อินพุตขอบเขต/ผิดปกติ พร้อมเอาต์พุตที่คาดหวัง | ดูตารางด้านล่าง |
| 7. dependencies และข้อจำกัด | ไลบรารีที่ใช้ เวอร์ชัน ตัวแปรสภาพแวดล้อม | "Python 3.10+, FastAPI, ตัวแปรสภาพแวดล้อม DB_URL" |
ตัวอย่างกรณีทดสอบ (ฝังใน spec)
| สถานการณ์ | อินพุต | เอาต์พุตที่คาดหวัง |
|---|---|---|
| ลงทะเบียนปกติ | email: a@b.com, pwd: Pass1234 |
201 คืนค่า user_id |
| รหัสผ่านสั้นเกินไป | pwd: Ab1 |
400, รหัสข้อผิดพลาด WEAK_PASSWORD |
| อีเมลมีอยู่แล้ว | email เดียวกัน | 409, รหัสข้อผิดพลาด EMAIL_EXISTS |
Spec ที่ดีต้องเขียนกรณีทดสอบก่อน เพราะ AI สามารถสร้าง unit test จากกรณีเหล่านั้นโดยตรง และตรวจสอบอัตโนมัติเมื่อเสร็จ
2. หลักการหลักในการเขียน Spec (ตัวแปร SMART)
| หลักการ | คำอธิบาย | ตัวอย่างที่ไม่ดี |
|---|---|---|
| แม่นยำ (Precise) | ใช้ตัวเลข ประเภท เงื่อนไขบูลีนที่เฉพาะเจาะจง หลีกเลี่ยง "ให้มากที่สุด", "โดยทั่วไป" | ❌ "รหัสผ่านต้องปลอดภัยพอ" → ✅ "รหัสผ่านอย่างน้อย 8 ตัวอักษร มีตัวพิมพ์ใหญ่ ตัวพิมพ์เล็ก และตัวเลข" |
| ตรวจสอบได้ (Verifiable) | ทุกข้อกำหนดสามารถตรวจสอบผ่าน/ไม่ผ่านได้โดยการทดสอบอัตโนมัติหรือการตรวจสอบด้วยตนเอง | ❌ "โค้ดต้องสวยงาม" → ✅ "วงรอบของฟังก์ชัน ≤ 10, ไม่มีโค้ดที่ซ้ำกัน" |
| ไร้ความกำกวม (Unambiguous) | คำศัพท์เดียวกันมีความหมายเดียวกันตลอดทั้งเอกสาร อาจต้องมี glossary | ❌ "ถ้าผู้ใช้ไม่มีอยู่ ให้คืนค่าข้อผิดพลาด" → ✅ "ผู้ใช้ไม่มีอยู่ → คืนค่า 404 และ {code: 'USER_NOT_FOUND'}" |
| สมบูรณ์ (Complete) | ครอบคลุมเส้นทางปกติ เส้นทางผิดปกติทั้งหมด และข้อกำหนดที่ไม่เกี่ยวกับฟังก์ชัน | ❌ เขียนเฉพาะสถานการณ์สำเร็จ → ✅ รวมถึง timeout ฐานข้อมูล, สิทธิ์ไม่เพียงพอ ฯลฯ |
| เป็นอะตอม (Atomic) | หนึ่ง spec อธิบายฟังก์ชันเดียวที่สามารถส่งมอบได้อิสระ (สะดวกให้ AI ทำครั้งเดียว) | ❌ ใช้ spec เดียวเขียน "ระบบชำระเงินทั้งหมด" → ✅ แยกเป็น "สร้างคำสั่งชำระเงิน", "ยืนยัน callback", "คืนเงิน" |
3. กระบวนการ Spec Coding เมื่อทำงานร่วมกับ AI
- มนุษย์เขียน spec (ตามโครงสร้างข้างต้น โดยเฉพาะกรณีทดสอบและลายเซ็นฟังก์ชัน)
- ป้อน spec ให้ AI ครั้งเดียว (ไม่ควรเพิ่มความต้องการแบบสนทนา เพื่อหลีกเลี่ยงการปนเปื้อน vibe)
- AI สร้างโค้ด + unit test (AI ต้องสร้าง test ที่รันได้จากกรณีทดสอบใน spec)
- รัน test: ถ้าผ่านทั้งหมด ไปขั้นตอนถัดไป ถ้าไม่ผ่าน ให้แก้ไข spec หรือแก้ไขโค้ดโดยตรง (สามารถวนรอบเล็กได้ แต่ต้องบันทึกการเปลี่ยนแปลง)
- ตรวจสอบโดยมนุษย์: ตรวจสอบว่ามีฟังก์ชันนอกเหนือ spec หรือไม่ (scope creep) ตรวจสอบความปลอดภัย/ประสิทธิภาพ
- ทำให้เป็นหลักฐาน: นำเอกสาร spec และโค้ดสุดท้าย commit ไปยัง repository เพื่อเป็นเอกสารถาวร
แนวทางปฏิบัติที่สำคัญ: ทำให้ spec เป็นโค้ด — ใช้
spec.md+test_spec.pyโดยที่ไฟล์ทดสอบมาจากตัวอย่างใน spec โดยตรง เพื่อให้เวลาแก้ไขโค้ดในภายหลัง แค่รัน test ก็สามารถตรวจสอบได้ว่า spec ถูกละเมิดหรือไม่
4. ผลลัพธ์ที่ได้จาก Spec ที่ดี (ใช้เป็นเกณฑ์การยอมรับ)
- ความแน่นอน: spec เดียวกันให้ AI (หรือบุคคล) ต่างกันได้ผลลัพธ์ใกล้เคียงกัน
- ความสามารถในการทดสอบ: เมื่อเขียนโค้ดเสร็จ สามารถตรวจสอบความถูกต้องโดยอัตโนมัติได้ 90%
- ความสามารถในการบำรุงรักษา: ครึ่งปีต่อมา ทุกคนที่อ่าน spec จะเข้าใจเจตนาการออกแบบดั้งเดิม
- ต้นทุนการสื่อสารต่ำ: ทีมงานอภิปรายเฉพาะ spec ไม่ใช่บรรทัดโค้ด
- ความปลอดภัย/คุณภาพในตัว: ข้อกำหนดด้านความปลอดภัย (เช่น parameterized query) และเงื่อนไขขอบเขตถูกระบุใน spec ให้ AI ต้องปฏิบัติตาม
5. ตัวอย่าง Spec ที่ดี (ฉบับสั้นมาก)
# Spec: API การลงทะเบียนผู้ใช้
## ขอบเขต
- รับ email, password
- ไม่ส่งอีเมลยืนยัน ไม่ตรวจสอบความถูกต้องของอีเมล
## สัญญา
POST /register
Content-Type: application/json
Request: { "email": string, "password": string }
Response 201: { "user_id": string }
Response 400: { "code": "INVALID_PASSWORD" | "INVALID_EMAIL" }
Response 409: { "code": "EMAIL_ALREADY_EXISTS" }
## พฤติกรรม
- email ต้องตรงตามรูปแบบพื้นฐานของ RFC 5322 (a@b.c)
- password: ยาว 8-20 ตัวอักษร ต้องมีตัวเลขอย่างน้อยหนึ่งตัวและตัวพิมพ์ใหญ่หนึ่งตัว
- ใช้ bcrypt เข้ารหัสจัดเก็บ โดย salt cost = 10
- ถ้าพบว่า email มีอยู่แล้วก่อนจัดเก็บลงฐานข้อมูล → 409
## กรณีทดสอบ (อินพุต -> สถานะที่คาดหวัง + ฟิลด์คำตอบ)
| อินพุต email | password | ที่คาดหวัง |
|------------|----------|------|
| test@x.com | Pass1234 | 201, user_id มีอยู่ |
| test@x.com | pass | 400, INVALID_PASSWORD |
| bad | Pass1234 | 400, INVALID_EMAIL |
| (อีเมลที่มีอยู่แล้ว) | Pass1234 | 409, EMAIL_ALREADY_EXISTS |
## ไม่เกี่ยวกับฟังก์ชัน
- SQL ต้องใช้ parameterized query (ป้องกัน SQL injection)
- บันทึกที่อยู่ IP ของการลงทะเบียน ไม่บันทึกรหัสผ่าน
- เวลาตอบสนอง 95% ของคำขอ < 100ms (ไม่รวม bcrypt)
## dependencies
- Python 3.10+, FastAPI, bcrypt, asyncpg
Spec Coding ที่ดี = การเขียน "การตัดสินใจออกแบบ" ของมนุษย์ให้เป็น "กรณีทดสอบ + ลายเซ็นชนิด + ข้อจำกัดพฤติกรรม" สำหรับเครื่อง เพื่อให้ AI ทำหน้าที่เติมเต็มการนำไปใช้งาน ส่วนมนุษย์ควบคุมคุณภาพและทิศทางตลอดเวลา
评论
暂无已展示的评论。
发表评论(匿名)