การเขียน Spec ที่ดี
คุณแทบไม่เคยเขียน spec จากหน้าเปล่าเลย คุณอธิบายการเปลี่ยนแปลงด้วยภาษาทั่วไป แล้ว /opsx:propose จะร่างข้อกำหนดและสถานการณ์ให้ จากนั้นคุณก็ปรับให้ดีขึ้น หน้านี้พูดถึงส่วนสุดท้ายนั้น — ความหมายของ "ดี" คืออะไร และวิธีนำ AI ไปสู่จุดนั้น
หน้านี้เป็นเอกสารประกอบสำหรับ การทบทวนการเปลี่ยนแปลง: การทบทวนคือการหาจุดอ่อนในร่างแรก การเขียนคือการรู้ว่าสิ่งที่สร้างขึ้นมาคืออะไรที่แข็งแกร่ง
Spec คือพฤติกรรม ไม่ใช่โค้ด
Spec อธิบายว่าสิ่งที่ระบบของคุณ ทำ คืออะไร ในรูปแบบที่ใครก็สามารถตรวจสอบได้ — ไม่ใช่วิธีที่มันถูกสร้างขึ้นมา มันประกอบด้วย ข้อกำหนด (requirements) (คำอธิบายพฤติกรรม) และ สถานการณ์ (scenarios) (ตัวอย่างที่ชัดเจนที่พิสูจน์ว่าพฤติกรรมนั้นเป็นจริง)
markdown
### ข้อกำหนด: หมดเวลาเซสชัน
ระบบ SHALL หมดอายุเซสชันหลังจาก 30 นาทีที่ไม่มีการใช้งาน
#### สถานการณ์: หมดเวลาจากไม่ใช้งาน
- GIVEN เซสชันที่เข้าสู่ระบบแล้ว
- WHEN ผ่านไป 30 นาทีโดยไม่มีการใช้งาน
- THEN เซสชันจะถูกยกเลิกและผู้ใช้ต้องเข้าสู่ระบบใหม่เก็บส่วน วิธีทำงาน — คิว, ไลบรารี, โครงสร้างตาราง — ไว้ใน design.md หรือในโค้ด เมื่อพฤติกรรมและการนำไปใช้ใช้งานผสมกันอยู่ในข้อกำหนดเดียวกัน ข้อกำหนดนั้นจะไม่สามารถทดสอบได้ และเริ่มเก่าเป็นทันทีที่โค้ดมีการเปลี่ยนแปลง
สิ่งที่ทำให้ข้อกำหนดดีได้
ข้อกำหนดที่ดีคือพฤติกรรมเดียวที่อธิบายอย่างชัดเจนจนคุณสามารถส่งให้คนอื่นทดสอบได้
หนึ่งประโยค หนึ่ง
SHALL/MUSTหากข้อกำหนดมีสามประการที่ขึ้นต้นด้วย "และยัง" มันก็คือสามข้อกำหนดจริง แยกออกเป็นส่วนๆสามารถสังเกตได้ คนที่ไม่ได้เขียนโค้ดควรจะสามารถบอกได้ว่ามันเป็นจริงหรือไม่ "ระบบ SHALL แสดงแบนเนอร์ข้อผิดพลาดเมื่อการอัปโหลดเกิน 10 MB" สามารถสังเกตได้ "ระบบ SHALL จัดการการอัปโหลดไฟล์ขนาดใหญ่อย่างลื่นไหล" ไม่สามารถสังเกตได้
ความเข้มงวดที่เหมาะสม OpenSpec ใช้คำสำคัญจาก RFC 2119 และแต่ละคำมีความหมายต่างกัน:
คำสำคัญ ความหมาย MUST/SHALLข้อกำหนดที่แข็งแกร่ง ไม่สามารถต่อรองได้ SHOULDคำแนะนำที่เข้มงวด มีพื้นที่ยกเว้นหากมีเหตุผลที่สมควร MAYเป็นตัวเลือกจริงๆ ใช้
MUST/SHALLเป็นค่าเริ่มต้นโดยปริยาย ใช้SHOULDเฉพาะเมื่อคุณหมายถึง "เว้นแต่จะมีเหตุผลที่ดีที่ไม่ควรทำ" จริงๆ
วิธีทดสอบข้อกำหนด: นักทดสอบที่เคยเห็นโค้ดเลยสามารถบอกได้ว่ามันผ่านหรือไม่? หากไม่สามารถ ทำความชัดเจนขึ้น
สิ่งที่ทำให้สถานการณ์ดีได้
สถานการณ์คือจุดที่ข้อกำหนดแสดงคุณค่าของมัน ละสถานการณ์เป็น GIVEN / WHEN / THEN ที่ชัดเจนซึ่งสามารถแปลงเป็น automated test ได้
- ทดสอบข้อกำหนดของมันจริงๆ สถานการณ์ที่แค่อธิบายซ้ำข้อกำหนดด้วยคำอื่นไม่ได้ทดสอบอะไรเลย กำหนดให้เป็นสถานการณ์เฉพาะพร้อมผลลัพธ์เฉพาะ
- ครอบคลุมกรณีที่สำคัญ ไม่ใช่แค่เส้นทางปกติ การเข้าสู่ระบบที่ถูกต้องเป็นเรื่องง่าย การป้อนข้อมูลว่าง, โทเคนหมดอายุ, การคลิกครั้งที่สอง, สิ่งที่ผิดพลาด — นั่นคือจุดที่บั๊กอยู่ และสถานการณ์นั้นมีค่าที่สุดที่นั่น
- ตั้งชื่อกรณีไว้ในหัวข้อ "สถานการณ์: ปฏิเสธโทเคนหมดอายุ" บอกให้ผู้ทบทวนเห็นว่ามีอะไรครอบคลุมได้ทันที; "สถานการณ์: ทดสอบ 2" ไม่บอกอะไรเลย
นิสัยที่เป็นประโยชน์: ก่อนอนุมัติ ถาม กรณีไหนที่ฉันจะรู้สึกไม่ดีหากมันเสียหาย? — และตรวจสอบให้แน่ใจว่าสถานการณ์มีชื่อเรียกกรณีนั้น
เลือกประเภท delta ที่เหมาะสม
การเปลี่ยนแปลงอธิบายการแก้ไขกับ spec โดยใช้สามประเภทส่วน ใช้ประเภทที่ถูกต้องจะทำให้ spec ที่เก็บไว้ในอาร์ไคฟ์ถูกต้องตรงกับความเป็นจริง:
## ADDED Requirements— พฤติกรรมใหม่ที่ไม่มีอยู่มาก่อน## MODIFIED Requirements— พฤติกรรมที่มีอยู่ก่อนและกำลังมีการเปลี่ยนแปลง ใส่เวอร์ชันใหม่ทั้งหมด; โน้ตสั้นๆ ว่ามีอะไรเปลี่ยนจะช่วยให้ผู้ทบทวนเข้าใจง่ายขึ้น## REMOVED Requirements— พฤติกรรมที่กำลังจะลบออก พร้อมบรรทัดที่อธิบายเหตุผล
เมื่อเก็บลงอาร์ไคฟ์ ส่วน ADDED จะถูกเพิ่มต่อท้าย spec หลัก ส่วน MODIFIED จะแทนที่เวอร์ชันเก่า และส่วน REMOVED จะถูกลบออก หากคุณทำเครื่องหมายว่าการเปลี่ยนแปลงจริงเป็น ADDED คุณจะได้ข้อกำหนดที่ขัดแย้งกันสองชุด; หากคุณอธิบายพฤติกรรมใหม่เป็น MODIFIED จะไม่มีอะไรให้แทนที่ หากไม่แน่ใจ เปิด spec ปัจจุบันและดูว่ามีข้อกำหนดนั้นอยู่แล้วหรือไม่
ขนาดการเปลี่ยนแปลงที่เหมาะสม
ข้อผิดพลาดที่พบบ่อยที่สุดของผู้เขียนไม่ได้เป็นข้อกำหนดที่เขียนคำไม่ดี — นั่นคือการเปลี่ยนแปลงที่พยายามจะเป็นสามการเปลี่ยนแปลง
การเปลี่ยนแปลงที่ดีมีเจตนาเดียวที่คุณสามารถพูดออกมาในหนึ่งประโยค "เพิ่มสลับโหมดมืด" "จำกัดอัตราการเข้าถึงจุดสิ้นสุดการเข้าสู่ระบบ" "ย้ายเซสชันออกจากการใช้คุกกี้" หากการอธิบายการเปลี่ยนแปลงต้องการคำว่า "และยัง" หลายครั้ง นั่นเป็นสัญญาณว่าควรแยกออกเป็นส่วนๆ
สัญญาณว่าการเปลี่ยนแปลงมีขนาดใหญ่เกินไป:
- ขอบเขตของข้อเสนอดูเหมือนรายการคุณสมบัติที่ไม่มีความเกี่ยวข้องกัน
- การทบทวนมันจะต้องใช้เวลาเต็มบ่าย ดังนั้นไม่มีใครจะทำ
- สองคนไม่สามารถทำงานกับมันได้โดยไม่ชนกัน
- ครึ่งหนึ่งของงานสามารถส่งออกได้ด้วยตัวเอง
การเปลี่ยนแปลงที่เล็กกว่าเป็นเรื่องง่ายที่จะทบทวน ง่ายที่จะสร้างในหนึ่งเซสชันที่โฟกัส และง่ายที่จะเข้าใจหกเดือนต่อมาเมื่ออาร์ไคฟ์เป็นสิ่งที่เหลืออยู่เท่านั้น คุณสามารถรันหลายการเปลี่ยนแปลงพร้อมกันได้เสมอ — ดู การแก้ไขและทำซ้ำ และ เวิร์กโฟลว์
อีกด้านหนึ่งก็เกิดขึ้น: การแก้ไขพิมพ์ผิดหนึ่งบรรทัดไม่จำเป็นต้องมีสามข้อกำหนดและเอกสารออกแบบ กำหนดความพิธีตามความเสี่ยง
วิธีนำ AI ไปสู่ร่างแรกที่ดี
เนื่องจาก /opsx:propose ทำร่างแรก คุณภาพของสิ่งที่คุณได้รับกลับมาตามตามคุณภาพของสิ่งที่คุณให้กับมัน คุณไม่จำเป็นต้องเขียนข้อกำหนดด้วยตัวเอง — คุณต้องเป้าหมาย AI อย่างถูกต้อง:
- ระบุเจตนาและขอบเขต "เพิ่มสลับโหมดมืดที่ใช้การตั้งค่าของระบบปฏิบัติการเมื่อโหลดครั้งแรก — อย่าแก้ไข API ธีมที่มีอยู่เดิม" ส่วนที่ไม่อยู่ในขอบเขตมีความสำคัญเท่ากับส่วนที่อยู่ในขอบเขต
- ระบุกรณีที่คุณสนใจ "ตรวจสอบให้แน่ใจว่ามีสถานการณ์สำหรับผู้ใช้ที่เคยเลือกธีมด้วยตนเอง" AI จะครอบคลุมสิ่งที่คุณชี้ให้เห็น
- จากนั้นแก้ไข มันเป็น Markdown ธรรมดา ปรับ
SHALLที่ไม่ชัดเจนให้เข้มงวดขึ้น, ลบสถานการณ์ที่ไม่ได้ทดสอบอะไร, เพิ่มกรณีที่มันพลาด — หรือขอให้ AI ทำ: "ข้อกำหนดเกี่ยวกับหมดเวลาอย่างไม่ชัดเจน กำหนดให้เป็น 30 นาที"
ร่าง, ชัดเจน, ทำซ้ำ หลายรอบของกระบวนการนี้จะสร้าง spec ที่คุณเชื่อถือได้ ซึ่งคือจุดประสงค์ทั้งหมด
รายการตรวจสอบด่วน
- [ ] ข้อกำหนดแต่ละข้อเป็นพฤติกรรมที่สามารถสังเกตได้หนึ่งข้อพร้อมกับ
SHALL/MUST - [ ] ไม่มีรายละเอียดการนำไปใช้ใช้งานที่ฝังอยู่ในข้อกำหนด
- [ ] ข้อกำหนดทุกข้อมีอย่างน้อยหนึ่งสถานการณ์ที่ทดสอบมันจริงๆ
- [ ] กรณีขอบและข้อผิดพลาดที่สำคัญมีสถานการณ์ ไม่ใช่แค่เส้นทางปกติ
- [ ] Delta ใช้ ADDED / MODIFIED / REMOVED อย่างถูกต้องเทียบกับ spec ปัจจุบัน
- [ ] การเปลี่ยนแปลงทั้งหมดมีเจตนาเดียวที่คุณสามารถพูดออกมาในหนึ่งประโยค
ที่ต่อไปนี้
- การทบทวนการเปลี่ยนแปลง — การตรวจสอบสองนาทีที่จับสิ่งที่หลุดลอยผ่านมา
- แนวคิด — โมเดลที่ลึกยิ่งขึ้นเบื้องหลัง spec, การเปลี่ยนแปลง และ delta
- ตัวอย่างและสูตรปฏิบัติการ — การเปลี่ยนแปลงจริงตั้งแต่ต้นจนจบ