Free

3,000 บรรทัดใน commit เดียว: ทำไมฟีเจอร์ซับซ้อนต้องใช้ plan mode ก่อน

สัญชาตญาณเมื่อเจอฟีเจอร์ซับซ้อนคือ "ลองดูก่อน" — แต่การตัดสินใจเชิงสถาปัตยกรรมซ่อนอยู่ใน model ที่ 3, edge case ที่ 5 คุณค่าแท้จริงของ plan mode คือย้ายบทสนทนาระดับสถาปัตยกรรมไปที่ข้อความก่อนเขียนโค้ด เคสจริง: ระบบคณะลูกขุนชุมชนของ Pickful — 3,032 บรรทัด, 119 spec เขียวหมด, commit เดียว, ศูนย์ครั้งที่ต้องทำสถาปัตยกรรมใหม่หลังจากนั้น


เจอฟีเจอร์ซับซ้อน สัญชาตญาณของคนส่วนใหญ่คือ "ลองเขียนอะไรดูก่อน"

ปัญหาคือ ระบบซับซ้อนมีคุณสมบัติอย่างหนึ่ง—การตัดสินใจเชิงสถาปัตยกรรมซ่อนอยู่ในโมเดลที่ 3, edge case ที่ 5, กฎคะแนนที่ 8 การดำดิ่งลงไปในโค้ดแล้วไปสะดุดกับการตัดสินใจเหล่านั้นกลางทาง แล้วถอยกลับมาแก้ จะแพงกว่าการคุยให้จบในระดับข้อความตั้งแต่ต้น 10 เท่า

ผมใช้ plan mode ของ Claude Code สร้าง TopicReview ระบบคณะลูกขุนชุมชนใน Pickful และได้เห็นเวอร์ชันสุดโต่งของอสมการนี้: หนึ่ง commit, 3,032 บรรทัด, spec 119 ตัวเขียวหมด, ส่งขึ้นใช้งานครั้งเดียวจบ commit สิบกว่าตัวที่ตามมาไม่มีสักตัวที่เป็นการรื้อสถาปัตยกรรมใหม่—ทั้งหมดเป็นการจูนพารามิเตอร์, ขัด UI, ปะแปะ edge case ระบบนี้ทำงานได้มั่นคงมาตลอด และตอนนี้เป็นหัวใจของวิธีที่ชุมชนดูแลตัวเอง

บทความนี้พูดถึงว่าทำไมฟีเจอร์ซับซ้อนต้องใช้ plan mode ก่อน, ช่วง plan ทำอะไรจริง ๆ, และต้องคุยกันถึงระดับไหนจึงจะเริ่มเขียนโค้ดได้

ระบบซับซ้อนแค่ไหน

TopicReview คือการโหวตของชุมชนเพื่อตัดสินว่าโพสต์คุณภาพต่ำควรถูกลบหรือไม่ ประโยคเดียวก็จบ—แต่สเปกแผ่ออกเป็นชั้น ๆ:

  • 5 สถานะ: open → voting → decided → appealed → closed
  • 3 คำตัดสิน: remove / warn / keep
  • 2 ขั้น: ชั้นต้นโหวตโดยลูกขุน 12 คน; อุทธรณ์ตัดสินโดย judge 5 คน (จับฉลากจาก 20 ผู้ใช้คะแนนสูงสุด)
  • การไหลเวียนคะแนนหลายมิติ: ค่าปรับชั่วคราว 10 pt, stake อุทธรณ์ 10 pt, +5 ให้ลูกขุนที่โหวตตรงกับคำตัดสิน, +10 ให้ judge ที่โหวตตรงกับคำตัดสิน, +3 ให้ผู้รายงานที่รายงานได้รับการยืนยัน, คืนเงินเมื่อชนะอุทธรณ์ = stake + bonus + ค่าปรับชั่วคราว
  • 4 ประเภทของ job ที่กำหนดเวลา: หน้าต่างโหวตชั้นต้น 24 ชม., หน้าต่างอุทธรณ์ 24 ชม., หน้าต่างพิจารณาอุทธรณ์ 24 ชม., และ — คะแนนลูกขุนถูกเลื่อนออกไป 24 ชม. หลังคำตัดสิน remove (เพราะอุทธรณ์อาจพลิก)
  • การไหลเวียนแบบขนาน + rollback: ถ้าโหวตพลิกระหว่างช่วงลบชั่วคราว ต้องคืนโพสต์และคืนค่าปรับชั่วคราว; ถ้าอุทธรณ์พลิกคำตัดสิน คืน stake พร้อม bonus อาจคืนค่าปรับชั่วคราวด้วย และลูกขุนถูกคำนวณใหม่ตามคำตัดสินใหม่

แก่นของความซับซ้อนไม่ได้อยู่ในกฎใดเดี่ยว ๆ—มันอยู่ที่ กฎโต้ตอบกันอย่างไร ทุกกฎที่เพิ่มเข้ามาอาจ trigger rollback ที่อื่น

กำแพงที่คุณชนโดยไม่มี plan

เวลาเขียนรวดเดียว ปัญหาที่ยากที่สุดไม่ใช่ข้อเท็จจริงที่เห็น—มันคือคำถามที่คุณไม่ได้คิดจะถาม อ่านโค้ด TopicReview ย้อนกลับ จะเห็นอย่างน้อยสี่กำแพงที่คุณจะชนแน่หากข้าม plan ไป:

กฎคุณสมบัติของลูกขุน. ดูผิวเผินก็แค่ User.jurors_and_judges.sample(12) แต่กฎจริงคือ: กันผู้เขียนโพสต์, กันผู้ที่รายงานโพสต์, กันผู้ที่โหวตในรอบต้นแล้ว (เพื่อคนเดิมจะไม่โหวตในชั้นอุทธรณ์ด้วย) การกันสามชั้นซ้อน เขียน model รวดเดียว มักจะหายไปหนึ่งหรือสองข้อ

การจ่ายคะแนนเลื่อน. คำตัดสิน remove ปกติจะทริกเกอร์การจ่ายคะแนนให้ลูกขุน แต่การอุทธรณ์อาจพลิก remove ได้—เมื่อพลิก ลูกขุนที่โหวตตามคำตัดสินเก่าจะไปอยู่ฝั่งที่ผิด ต้องคำนวณการจ่ายใหม่ตามคำตัดสินใหม่ ดังนั้นคำตัดสิน remove ต้อง รอให้หน้าต่างอุทธรณ์ 24 ชม. ปิดก่อน จึงจะจ่ายลูกขุน ถ้าข้ามการเขียนกฎนี้ จ่ายไปก่อน จะไปคว้าคะแนนกลับคืน—ยุ่งกว่าการจ่ายช้า 10 เท่า

การออกแบบ interface ของ job ที่กำหนดเวลา. CloseTopicReviewJob ดูเหมือนแค่ "ปิด review" แต่จริง ๆ แล้วจัดการสามสถานการณ์:

# หน้าต่างโหวตชั้นต้นหมดเวลา
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# จ่ายลูกขุนเลื่อนหลังคำตัดสิน remove
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# หน้าต่างอุทธรณ์หมดเวลา
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)

ไม่วางแผนก่อน จะเขียน signature แรก แล้วพอถึงกรณีที่สองพบว่าต้องออกแบบ interface ใหม่ทั้งหมด

กำแพงที่แพงที่สุด: ช่วงลบชั่วคราวอุทธรณ์ได้ไหม? เมื่อโหวต remove ข้ามเกณฑ์ โพสต์ถูกซ่อนทันที (ชั่วคราว) แต่ review ทั้งหมดยังอยู่ในสถานะ voting—ยังไม่ decided ผู้ใช้อุทธรณ์ได้เลยหรือไม่?

  • ได้ → ต้องขยาย transition ระหว่าง decided กับ appealed
  • ไม่ได้ → UX แย่: โพสต์ถูกซ่อนและผู้ใช้ต้องรอ 24 ชม. ถึงจะประท้วงได้
  • ตัวเลือกจริงของ TopicReview: ได้, อนุญาตให้อุทธรณ์ในช่วงลบชั่วคราว—แต่ review ต้องเดินผ่าน finalize → decided ก่อนถึงจะเปิดอุทธรณ์

การตัดสินใจนี้ครั้งเดียวแผ่กลับไปกระทบการตรวจสอบพารามิเตอร์ใน open_appeal! และตรรกะของ state machine การตัดสินใจกลางทาง = เขียนระบบใหม่ครึ่งระบบ

ช่วง plan ทำอะไรจริง ๆ

plan mode ของ Claude Code คือโหมดที่ ห้ามเขียนโค้ด—Claude อ่าน repo ได้ คิดวิธีได้ คุยกับคุณได้ แต่การแก้ไขไฟล์ใด ๆ จะถูก hard-block จนกว่าคุณจะอนุมัติ plan

ข้อจำกัดเชิงกลไกนั้นคือแก่น: มัน บังคับให้บทสนทนาระดับสถาปัตยกรรมเกิดขึ้นในตัวอักษร

สิ่งที่ช่วง plan ทำจริงในทางปฏิบัติ:

1. วาด state machine และบทบาท 5 สถานะ, 4 บทบาท (ลูกขุน / judge / ผู้เขียนโพสต์ / ผู้รายงาน), แต่ละบทบาททำและไม่ทำอะไรในแต่ละสถานะ—ทั้งหมดอยู่ใน markdown ไม่กี่บรรทัด ไม่กี่บรรทัด vs หลายสิบไฟล์ ต้นทุนการแก้ต่างกันสองลำดับความสูง

2. Walkthrough flow ของแต่ละบทบาท:

  • ลูกขุน: ได้รับแจ้งเตือน → เปิด review → อ่านโพสต์และเหตุผล → โหวตพร้อม reasoning → รับคะแนน
  • ผู้เขียนโพสต์: ได้รับแจ้งเตือน → เห็นคำตัดสิน → ถ้า remove พิจารณาอุทธรณ์ → วาง stake → รอ
  • Judge: รับ appeal ที่จับฉลากจาก top-20 → โหวต → รับคะแนน

จุดที่การเดินสะดุด จะมีคำถามซ่อนอยู่โผล่ขึ้นมา: "ลูกขุนเห็นโหวตของลูกขุนคนอื่นได้ไหม?", "ผู้เขียนทำอะไรได้ในช่วงลบชั่วคราว?"

3. สอบสวน edge case ช่วง plan ไม่ใช่ออกแบบ "เส้นทางปกติ"—แต่จงใจถามคำถามที่ปกติไม่ได้นึกถึง:

  • หน้าต่างหมดเวลาโดยไม่มีโหวต? (ตัดสินใจสุดท้าย: default keep)
  • อุทธรณ์หมดเวลาโดยไม่มีโหวต? (dismissed; stake หมด)
  • Judge โหวตโพสต์ที่ตัวเองรายงานได้ไหม? (ไม่ได้—กฎกันคนเดิม)
  • ลูกขุนหลายคน trigger finalize พร้อมกัน race จะจ่ายซ้ำไหม? (เพิ่มฟิลด์ juror_points_awarded ให้ idempotent)

คำถามเหล่านี้ 95% ไม่ขึ้นมาตามธรรมชาติระหว่างเขียนโค้ด ช่วง plan บังคับให้คุณตอบทีละข้อ

4. บัญชีคะแนน ระบบคะแนนซับซ้อนจนคุยอย่างเดียวไม่พอ—ต้อง วาดตารางจริง ๆ: แต่ละการไหลของคะแนนพร้อมเงื่อนไข trigger + จำนวน + เส้นทาง rollback เมื่อบัญชีลงตัว ทุก edge case (คืนค่าปรับชั่วคราว, คืนอุทธรณ์, bonus) เข้ากันได้หมด

คุยถึงระดับไหนจึงเริ่มเขียนโค้ดได้

เกณฑ์แข็ง:

  • เดินทุกเส้นทางได้โดยไม่ติด—ทุกการจัดเรียงจากการเปิด review จนถึง closed (keep / remove / warn × มี / ไม่มีอุทธรณ์ × ชั่วคราว / ไม่ชั่วคราว)—เล่าได้ตั้งแต่ต้นจนจบ
  • edge case ทุกตัวมีพฤติกรรมชัดเจน—ไม่ใช่ "เดี๋ยวค่อยว่า" แต่คือ "0 โหวต default keep", "ชั่วคราวอนุญาตให้อุทธรณ์แต่ต้อง finalize ก่อน"
  • ไม่มี "อ้อ อันนี้ยังไม่ได้คิด"—ทุกคำถามที่คุณตั้งได้มีคำตอบพร้อมแล้ว

พอถึงเกณฑ์นี้ การเขียนโค้ดกลายเป็นการแปล plan เป็น Ruby

ช่วง execute รวดเดียวเป็นยังไง

การ ship ครั้งแรกของระบบนี้:

d162f1e Add community moderation system with jury/judge review and appeals
  63 files changed, 3032 insertions(+)
  119 specs, 0 failures

63 ไฟล์, 3,032 บรรทัด, spec 119 ตัวเขียวหมด ส่งขึ้นใช้งานครั้งเดียวจบ

commit สิบกว่าตัวที่ตามมายืนยันว่าสถาปัตยกรรมยืนหยัด:

Apply legacy penalty (1pt) for posts created before 2026-03-26
Fix topic review appeal bugs: window mismatch and verdict not updated
Add topic_removed status for posts removed by community review
Default to keep verdict when review expires with zero votes
Reduce provisional removal penalty to 1pt during trial period
Allow topic creator to withdraw active reviews
Add handled tab to jury dashboard, fix tabs styling

แต่ละอันคือ tune / fix / polish / ฟีเจอร์เล็ก ไม่มีอันไหนเป็น "กลับไปออกแบบ state machine ใหม่" หรือ "ต้องเปลี่ยนโมเดลคะแนน" โครงกระดูกถูกต้องหมด

นี่คือผลตอบแทนจริงของ plan: การ execute ไม่ถูกขัดจังหวะ ไม่มี "เดี๋ยว เส้นนี้จัดการยังไง"—plan เขียนไว้แล้ว ไม่มี "ไม่ได้คิดถึง edge case นี้"—ช่วง plan ถามแล้ว ไม่มี "interface นี้ต้องออกแบบใหม่"—plan จัดไว้เรียบร้อย

หลายชั่วโมงเขียนโค้ด ทำอย่างเดียว: แปลดีไซน์ที่ชัดเจนลงคีย์บอร์ด

เมื่อไรไม่ควรใช้ plan

ไม่ใช่ทุกงานคุ้มกับ plan:

  • แก้บั๊กง่าย ๆ—หาตำแหน่ง + แก้ + เพิ่ม regression test; ไม่ต้องคุยล่วงหน้า
  • Refactor เชิงกลไก—เปลี่ยนชื่อ, ดึงฟังก์ชัน, ย้ายไฟล์; เส้นทางเดียว plan เป็นขั้นตอนเกิน
  • มีเส้นทางชัดเจนเพียงหนึ่ง—เพิ่ม GET endpoint หนึ่งตัว, UI toggle หนึ่งตัว; ไม่มีอะไรให้ถกเถียง
  • Prototype สำรวจ—คุณเองยังไม่รู้ว่าต้องการอะไร; ทำเวอร์ชันหยาบให้ run ดีกว่าคิดต่อ

ผลกำไรของ plan mode มาจาก การลดต้นทุนการเขียนใหม่ ถ้างานไม่มีความเสี่ยงเขียนใหม่ plan เป็นเพียงค่าโสหุ้ย

สรุป

"คิดก่อนทำ" ฟังเหมือนคำแนะนำเรื่องนิสัย plan mode ไม่ใช่แบบนั้น

plan mode คือทำให้ บทสนทนาระดับสถาปัตยกรรม เกิดขึ้นในที่ที่ 10 คำเปลี่ยนได้—ไม่ใช่ในที่ที่ต้องเปลี่ยน 30 ไฟล์

ภายใต้ความซับซ้อน ต้องกลับด้านคำคมเก่าของวงการ "words are cheap, code is expensive"—มันไม่ได้หมายความว่า "เขียนโค้ดก่อนแล้วค่อยดู" (นั่นใช้ได้เมื่อส่วนต่างต้นทุนเล็ก) แต่หมายถึงใช้ประโยชน์จากส่วนต่างต้นทุน: ยกบทสนทนาที่แพงไปข้างหน้า ในสื่อที่ถูก

3,000 บรรทัดใน commit เดียวรู้สึกยอดเยี่ยม ไม่ใช่เพราะผมเขียนเร็ว—แต่เพราะ plan เปลี่ยน "การเขียน" ให้เป็นการกระทำเชิงกลไกล้วน ๆ