← 返回列表

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

  1. มนุษย์เขียน spec (ตามโครงสร้างข้างต้น โดยเฉพาะกรณีทดสอบและลายเซ็นฟังก์ชัน)
  2. ป้อน spec ให้ AI ครั้งเดียว (ไม่ควรเพิ่มความต้องการแบบสนทนา เพื่อหลีกเลี่ยงการปนเปื้อน vibe)
  3. AI สร้างโค้ด + unit test (AI ต้องสร้าง test ที่รันได้จากกรณีทดสอบใน spec)
  4. รัน test: ถ้าผ่านทั้งหมด ไปขั้นตอนถัดไป ถ้าไม่ผ่าน ให้แก้ไข spec หรือแก้ไขโค้ดโดยตรง (สามารถวนรอบเล็กได้ แต่ต้องบันทึกการเปลี่ยนแปลง)
  5. ตรวจสอบโดยมนุษย์: ตรวจสอบว่ามีฟังก์ชันนอกเหนือ spec หรือไม่ (scope creep) ตรวจสอบความปลอดภัย/ประสิทธิภาพ
  6. ทำให้เป็นหลักฐาน: นำเอกสาร 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 ทำหน้าที่เติมเต็มการนำไปใช้งาน ส่วนมนุษย์ควบคุมคุณภาพและทิศทางตลอดเวลา

评论

暂无已展示的评论。

发表评论(匿名)