ทำให้โค้ดที่สร้างโดย AI ตรวจทานได้ด้วยการมาตรฐานโฟลเดอร์ การตั้งชื่อ และการจดกฎคงที่ (invariants) เพื่อให้ทีมมนุษย์รับช่วงต่อและปล่อยการเปลี่ยนแปลงได้อย่างปลอดภัย

userId vs userid vs user_id) ทำให้การค้นหาไม่เชื่อถือได้และทำให้พลาดบั๊กได้ง่าย\n- การตั้งค่าและ “ค่าลึกลับ” ถูกทำซ้ำ\n- การจัดการข้อผิดพลาดและการตรวจสอบความถูกต้องเบี่ยงเบน ทำให้กรณีมุมต่างกันทำงานต่างกันบนหน้าจอหรือ endpoints\n\nความไม่สอดคล้องเล็ก ๆ ทวีคูณเวลาในการดูแลรักษาเพราะบังคับให้ต้องตัดสินใจซ้ำ หากทุกหน้าจอใหม่มีตำแหน่งโฟลเดอร์ ชื่อคอมโพเนนต์ และสไตล์การดึงข้อมูลที่ต่างกัน ผู้ตรวจไม่สามารถสร้างแบบจำลองในใจที่มั่นคงได้ พวกเขาต้องเรียนรู้โค้ดใหม่ทุกครั้ง\n\nตัวอย่างที่สมจริง: ผู้ก่อตั้งที่ไม่ใช่สายเทคนิคใช้เครื่องมือ vibe-coding เพื่อสร้าง CRM ง่าย ๆ มันเดโมได้ดี แต่เมื่อทีมขนาดเล็กรับช่วงต่อ พวกเขาพบวิธีเก็บ auth state ถึงสามแบบ สไตล์การตั้งชื่อ React สองอย่าง และกฎธุรกิจที่กระจายอยู่ระหว่างโค้ด UI และตัวจัดการแบ็กเอนด์ ไม่มีอะไร “เสีย” แต่ทุกการเปลี่ยนรู้สึกเสี่ยงเพราะไม่มีใครรู้ว่าแพทเทิร์นไหนเป็นของจริง\n\nการส่งมอบจะง่ายขึ้นเมื่อคุณลดจำนวนตัวเลือก ทีมจะเคลื่อนที่เร็วขึ้นเมื่อรีโพมีสัญญาณบอกอย่างสม่ำเสมอว่าต้องทำอะไรต่อไป\n\n## ความหมายของ “ตรวจทานได้” ในทางปฏิบัติ\n\n“ตรวจทานได้” หมายความว่านักพัฒนาคนใหม่สามารถเปิดรีโพ หา nơiที่ถูกต้องเพื่อเปลี่ยนแปลง ทำการเปลี่ยนแปลง และยืนยันว่าไม่มีอย่างอื่นพัง นั่นเป็นพื้นฐาน และมันคือสิ่งที่โพรโทไทป์หลายชิ้นพลาด\n\nเพื่อทำให้โค้ดที่สร้างโดย AI ตรวจทานได้ ให้มุ่งเน้นน้อยลงกับความฉลาดและมากขึ้นกับความปลอดภัยเมื่อคนสัมผัสมันได้ ความสามารถในการตรวจทานคือการลดความเสี่ยงของการเปลี่ยนแปลง\n\n### สิ่งที่ผู้ตรวจต้องเห็น\n\nเมื่อเพื่อนร่วมทีมตรวจ pull request พวกเขาพยายามตอบคำถามไม่กี่ข้ออย่างรวดเร็ว:\n\n- การเปลี่ยนแปลงนี้มีไว้เพื่ออะไร อธิบายเป็นคำง่าย ๆ\n- พฤติกรรมนี้อยู่ที่ไหน (UI, API, database) และทำไมถึงอยู่ที่นั่น\n- ขอบเขตคืออะไร (สิ่งที่การเปลี่ยนนี้ไม่ควรมีผลกระทบ)?\n- ฉันจะยืนยันได้อย่างไร (เทสต์, ขั้นตอนด้วยมือ หรือทั้งสอง)?\n\n- แผนการย้อนกลับคืออะไรหากมันทำงานผิดพลาด?\n\nการ diff ขนาดเล็กช่วย แต่ “ขนาดเล็ก” ไม่ได้หมายถึงเพียงจำนวนบรรทัด มันหมายถึงขอบเขตที่มั่นคงเช่นกัน: การเปลี่ยนที่ส่วนหนึ่งไม่ควรต้องแตะไฟล์ที่ไม่เกี่ยวข้อง\n\n### สัญญาณว่ารีโพตรวจทานได้\n\nคุณไม่จำเป็นต้องสมบูรณ์แบบ คุณต้องการคอนเวนชัน เอกสารเล็กน้อย เทสต์บางอัน และแนวป้องกันที่ป้องกันการเบี่ยงเบนในอนาคต\n\nผู้ตรวจจะรู้สึกปลอดภัยขึ้นเมื่อพวกเขาสามารถสังเกตได้อย่างรวดเร็ว:\n\n- โครงสร้างและชื่อที่คาดเดาได้\n- เจตนาที่ชัดเจนในฟังก์ชันและคอมโพเนนต์ (ไม่มี helpers ปริศนา)\n- README สั้น ๆ สำหรับการรัน การทดสอบ และเวิร์กโฟลว์ทั่วไป\n- เทสต์ที่มีค่าสองสามชิ้นรอบ ๆ ฟลูว์สำคัญ\n- กฎชัดเจนสำหรับพฤติกรรมที่ “ห้ามทำให้พัง” (invariants)\n\nตัวอย่าง: คุณสร้าง frontend ด้วย React และ API ด้วย Go โพรโทไทป์ทำงานได้ แต่ฟลูว์ “สร้างลูกค้า” กระจายอยู่ในโค้ด UI, ตัวจัดการ API, และการเรียกฐานข้อมูลโดยมีชื่อฟิลด์ต่างกันเล็กน้อย การทำให้มันตรวจทานได้หมายถึงการปรับชื่อให้ตรงกัน รักษาขอบเขต API ให้ชัดเจน และจดกฎไว้ (เช่น “อีเมลต้องไม่ซ้ำ” และ “สถานะต้องเป็น active หรือ paused เท่านั้น”)\n\nอย่าเล็งที่จะเขียนใหม่ทั้งหมดจนมันดูเหมือนโครงการตำรา โค้ดที่พร้อมส่งมอบคือโค้ดที่ชัดเจน สอดคล้อง และปลอดภัยที่จะเปลี่ยน แม้มันจะยังไม่สวยที่สุดก็ตาม\n\n## โครงสร้างโฟลเดอร์ที่ทำให้การนำทางง่าย\n\nทีมสามารถให้อภัยโค้ดที่ไม่สมบูรณ์ได้ สิ่งที่พวกเขาลำบากคือการไม่รู้ว่าสิ่งใดอยู่ที่ไหน หากต้องการให้โค้ดที่สร้างโดย AI ตรวจทานได้ ให้ทำให้โปรเจกต์สแกนได้ง่าย: ชุดโฟลเดอร์ระดับบนขนาดเล็ก ชื่อที่สอดคล้อง และที่เดียวที่ชัดเจนสำหรับการตั้งค่า\n\n### โครงสร้างเรียบง่ายที่ใช้ได้จริง\n\nรักษาแผนที่ระดับบนให้คงที่เมื่อแอปเติบโต หลายการส่งมอบล้มเหลวเพราะโฟลเดอร์ใหม่ปรากฏสำหรับทุกการทดลอง แทนที่จะเป็นเช่นนั้น ให้แยกสามความกังวล: การประกอบแอป (screens, routes), กฎธุรกิจหลัก, และโครงสร้างพื้นฐาน\n\nนี่คือรูปแบบปฏิบัติที่คุณปรับได้ (ตัวอย่างเว็บแอป):\n\ntext\n/\n /app # routes/pages and UI composition\n /core # domain logic: entities, rules, use-cases\n /ui # reusable components, styles, design tokens\n /infra # db, api clients, queues, auth adapters\n /config # env schema, feature flags, app settings\n /scripts # local tooling, seed data, one-off tasks\n /docs # handoff notes, invariants, decisions\n\n\nถ้าตอนแรกเวอร์ชันถูกสร้างขึ้นอย่างรวดเร็ว ให้รักษาการแยกนั้นไว้ชัดเจน ใส่โมดูลที่อาจถูกสร้างใหม่ไว้ใต้ /generated และเก็บโมดูลที่แก้ไขด้วยคนไว้ใต้ /core หรือ /app จุดประสงค์คือเพื่อหลีกเลี่ยงการแก้ไขโดยไม่ตั้งใจในโค้ดที่คุณอาจจะสร้างใหม่อีกครั้งในภายหลัง\n\n### ทำให้คำตอบของ “สิ่งนี้อยู่ที่ไหน?” ตอบได้ภายใน 10 วินาที\n\nก่อนการส่งมอบ ให้ทำการทดสอบการนำทางอย่างรวดเร็วกับเพื่อนร่วมทีม (หรือกับตัวคุณในอนาคต) ถามว่า UI เข้าสู่ระบบอยู่ที่ไหน กฎการอนุญาตอยู่ที่ไหน การเข้าถึงฐานข้อมูลถูกนิยามที่ไหน ค่า base URL ของ API และ feature flags ตั้งค่าอยู่ที่ไหน และสคริปต์พิเศษอยู่ที่ไหน\n\nถ้าคำตอบใดเริ่มด้วย “แล้วแต่กรณี” หรือ “ค้นหาดู” ให้ปรับโครงสร้างจนแต่ละหัวข้อมีบ้านเดียวที่น่าเบื่อ บ้านที่น่าเบื่อนั้นแหละที่ทำให้การบำรุงรักษาเร็วและปลอดภัย\n\n## การตั้งชื่อที่มนุษย์เชื่อมั่นได้\n\nคอนเวนชันการตั้งชื่อคือสัญญา: ผู้ตรวจควรเดาได้ว่าสิ่งใดคืออะไร อยู่ที่ไหน และถูกใช้ยังไงก่อนเปิดไฟล์\n\nเริ่มจากชื่อไฟล์และยึดติดกับสไตล์หนึ่งทั่วรีโพ ค่าเริ่มต้นง่าย ๆ คือ: โฟลเดอร์เป็น kebab-case, คอมโพเนนต์ React เป็น PascalCase, และไฟล์ TypeScript ที่ไม่ใช่คอมโพเนนต์เป็น camelCase หยุดกฎเมื่อ ecosystem คาดหวังมัน (เช่น มาตรฐานของ Flutter หรือไฟล์มาตรฐานอย่าง README)\n\nชื่อต้องเผยเจตนา ไม่ใช่การทำงานภายใน:\n\n- ดี: BillingSummaryCard.tsx (บอกว่ามันแทนอะไร)\n- เสี่ยง: StripeCard.tsx (ผูกกับผู้ให้บริการ)\n- เสี่ยง: RenderBilling.tsx (อธิบายวิธี ไม่ใช่เหตุผล)\n\nเข้มงวดกับถังกว้าง ๆ ที่คลุมเครือ ไฟล์ชื่อ utils, helpers, หรือ common จะกลายเป็นลิ้นชักขยะเร็ว โดยเฉพาะเมื่อโค้ดถูกสร้างเป็นชุด หากต้องการโค้ดที่แชร์ ให้ตั้งชื่อโดยขอบเขตและจุดประสงค์ เช่น auth/tokenStorage.ts หรือ billing/billingCalculations.ts\n\n### โฟลเดอร์ตามฟีเจอร์ vs โฟลเดอร์ตามเทคนิค\n\nโฟลเดอร์ตามฟีเจอร์อธิบายพื้นที่ปัญหาของผู้ใช้ ส่วนโฟลเดอร์ตามเทคนิคอธิบายโครงสร้างข้ามส่วน การผสมกันจะซ่อนขอบเขต\n\nการแยกเชิงปฏิบัติได้คือฟีเจอร์อย่าง billing, onboarding, inventory และพื้นที่เทคนิคอย่าง api, db, routing, design-system เมื่อต้องมีลูกค้าหลายประเภท (web, server, mobile) การรักษาชื่อฟีเจอร์ให้เหมือนกันข้ามเลเยอร์ทำให้การเปลี่ยนแปลงง่ายต่อการติดตาม\n\n### เกณฑ์การตั้งชื่อด่วนสำหรับผู้ตรวจ\n\nใช้เกณฑ์สั้น ๆ นี้ในการตรวจโค้ด:\n\n- คุณบอกได้ไหมว่ามันคืออะไรใน 3 วินาทีจากชื่อเพียงอย่างเดียว?\n- ชื่อสอดคล้องกับระดับหรือไม่ (ชื่อฟีเจอร์สำหรับตรรกะธุรกิจ ชื่อเชิงเทคนิคสำหรับโครงสร้างพื้นฐาน)?\n- ชื่อยังคงมีความหมายถ้าการใช้งานเปลี่ยนไปหรือไม่?\n- มันสอดคล้องกับไฟล์และโฟลเดอร์ใกล้เคียงหรือไม่?\n\nเปลี่ยนชื่อแต่เนิ่น ๆ การเปลี่ยนชื่อถูกและง่ายในช่วงส่งมอบ แต่จะแพงหลังจากทีมเริ่มสร้างต่อจากความสับสน\n\n## จดกฎคงที่ (invariants) ไว้\n\nInvariant คือกฎที่แอปต้องพึ่งพาเพื่อให้ถูกต้องแม้ฟีเจอร์จะเปลี่ยนไป โค้ดที่สร้างโดย AI มัก “ทำงาน” เพราะเครื่องมือสร้างสมมติฐานบางชุด แต่สมมติฐานเหล่านั้นอาจอยู่แค่ใน prompt หรือในหัวของใครสักคน เขียนมันลงไปเพื่อให้ผู้ตรวจรู้ว่าตรงไหนที่ห้ามเปลี่ยนโดยเงียบ ๆ\n\nกฎคงที่ที่ดีคือเรียบ ๆ เฉพาะเจาะจง และทดสอบได้ หลีกเลี่ยงประโยคคลุมเครือเช่น “validate inputs” ให้ระบุชัดเจนว่าอะไรถูกต้อง ใครทำอะไรได้ และจะเกิดอะไรขึ้นเมื่อกฎถูกละเมิด\n\n### ตัวอย่าง invariant ที่มีประโยชน์ (ที่ผู้ตรวจมองหา)\n\nปัญหาการส่งมอบส่วนใหญ่มาจากพื้นที่เดียวกัน:\n\n- สิทธิ์: “เฉพาะเจ้าของโปรเจกต์เท่านั้นที่สามารถเชิญสมาชิก; admins เอาออกได้; สมาชิกดูได้แต่แก้บิลไม่ได้”\n- ความเป็นเจ้าของข้อมูล: “ทุก Task เป็นของ Project เดียวเท่านั้น ผู้ใช้เข้าถึง Task ได้เฉพาะสำหรับ Project ที่ตนเป็นสมาชิก”\n- กฎไอดีและฟอร์แมต: “Public IDs เป็น UUIDv4 สตริง ID ตัวเลขภายในจะไม่ออกไปใน response ของเซิร์ฟเวอร์”\n- การเปลี่ยนสถานะ: “สถานะคำสั่งซื้อสามารถไปได้จาก draft -> paid -> shipped; shipped จะไม่กลับไปเป็น paid”\n- ความสมบูรณ์ของข้อมูล: “Email ต้องไม่ซ้ำ (ไม่สนตัวพิมพ์) การลบโปรเจกต์เป็น soft-delete; task จะไม่ถูกลบแบบ hard-delete”\n\nถ้าคุณสามารถเปลี่ยนประโยคนั้นให้เป็น unit test หรือ API test ได้ แปลว่านั่นคือระดับที่ถูกต้อง\n\n### จะจด invariants ไว้ที่ไหนให้คนตรวจเห็น\n\nใส่ invariants ในที่ที่ผู้คนมักมองตอนตรวจ:\n\n- ใน README ของรีโพ: ส่วนสั้น ๆ “System rules” พร้อม invariant ชั้นนำ\n- ข้างโค้ดที่บังคับใช้: คอมเมนต์สั้น ๆ ใกล้กับการเช็ค auth, การ validate, และการเปลี่ยนสถานะ\n- ในบันทึกการตัดสินใจหน้าเดียวสำหรับกฎใหญ่: แบบโมเดล auth, การตัดสินใจโครงสร้างข้อมูล, สถานะเวิร์กโฟลว์\n\nหลีกเลี่ยงการซ่อน invariants ในเอกสารยาวที่ไม่มีใครเปิด ถ้ามันไม่โผล่ขึ้นในกระบวนการตรวจ PR ปกติ มันจะถูกมองข้าม\n\n### วิธีเขียน invariants (และเปลี่ยนอย่างปลอดภัย)\n\nเขียนแต่ละ invariant ด้วยขอบเขต กฎ และจุดบังคับใช้ ตัวอย่าง: “สำหรับทุก endpoints ภายใต้ /api/projects/:id ผู้เรียกต้องเป็นสมาชิกโปรเจกต์; บังคับใน auth middleware และเช็คอีกครั้งตอนอัปเดต task”\n\nเมื่อ invariant เปลี่ยน ให้ทำให้ชัดเจน อัปเดตบรรทัดในเอกสาร ชี้ไปยังที่ในโค้ดที่เปลี่ยน และเพิ่มหรืออัปเดตเทสต์ที่จะล้มภายใต้กฎเก่า ไม่เช่นนั้นทีมมักจะรักษาพฤติกรรมครึ่งหนึ่งของเก่าและครึ่งหนึ่งของใหม่\n\nถ้าคุณใช้แพลตฟอร์ม vibe-coding เช่น Koder.ai ขั้นตอนการส่งมอบที่มีประโยชน์คือถามมันให้ list invariants ที่มันสมมติขณะสร้างแอป แล้วเปลี่ยนสิ่งนั้นเป็นชุดกฎที่ทดสอบได้เล็ก ๆ ที่ทีมสามารถตรวจและรักษาไว้ได้\n\n## ทีละขั้นตอน: เปลี่ยนโพรโทไทป์ให้พร้อมส่งมอบ\n\nการส่งมอบไม่เหมือนกับ “มันรันบนเครื่องฉันได้” เป้าหมายคือทำให้โปรเจกต์อ่านง่าย ปลอดภัยต่อการเปลี่ยนแปลง และพยากรณ์ได้เมื่อคนใหม่เปิดมันขึ้นมา\n\nเริ่มจากการล็อกขอบเขต เลือกวันที่และรายการสั้น ๆ ของสิ่งที่ต้องนิ่ง (หน้าจอหลัก, ฟลูว์สำคัญ, การเชื่อมต่อหลัก) แล้วเขียนลงว่าสิ่งใดอยู่นอกขอบเขตเพื่อจะไม่มีใครเพิ่มฟีเจอร์ขณะคุณกำลังทำความสะอาด\n\nจากนั้นทำความสะอาดก่อนเพิ่มอะไรใหม่ นี่คือจุดที่ความสามารถในการตรวจทานเริ่มปรากฏ: รีโพเริ่มทำตัวเหมือนผลิตภัณฑ์ไม่ใช่เดโม\n\nลำดับปฏิบัติได้:\n\n- ล็อกขอบเขตการส่งมอบ: 3 ถึง 5 user journeys ที่ต้องทำงานได้ และ 3 ถึง 5 อย่างที่จะไม่เปลี่ยน\n- ปรับโฟลเดอร์และชื่อให้เป็นมาตรฐาน: ย้ายไฟล์ไปยังโครงสร้างที่คาดเดาได้, เปลี่ยนชื่อโมดูลที่ไม่ชัดเจน, ลบโค้ดที่ตายแล้ว\n- เพิ่มบันทึกโมดูลเล็ก ๆ ที่คนจะเห็น: “สิ่งนี้ทำอะไร” และ “สิ่งนี้ห้ามทำอะไรเป็นหลัก” เก็บให้สั้นเป็นไม่กี่บรรทัด\n- ใส่ invariants ใกล้จุดบังคับใช้: เขียนกฎไว้เหนือฟังก์ชัน คิวรี หรือคอมโพเนนต์ที่บังคับใช้มัน\n- สร้างแผนสโมคขั้นต่ำ: เช็คลิสต์สั้น ๆ ที่ตรงกับขอบเขตที่ล็อกและ invariants\n\nเก็บแผนสโมคให้เล็กแต่ใช้งานได้จริง สำหรับ React app กับ Go API และ Postgres อาจเป็น: ลงชื่อเข้าใช้ สร้างเรคคอร์ด รีเฟรช ยืนยันว่ามันถูกเก็บ และยืนยันว่าการกระทำที่ถูกจำกัดล้มเหลว\n\nทำรอบการตรวจหนึ่งรอบที่มุ่งเน้นความอ่านง่าย ไม่ใช่ฟีเจอร์ ขอให้เพื่อนร่วมทีมใช้เวลา 30 นาทีตอบคำถาม: “ฉันหาที่ต่างๆ เจอไหม?” “ชื่อสอดคล้องกับพฤติกรรมไหม?” “invariants ชัดเจนหรือเปล่า?” แก้สิ่งที่ทำให้ช้าลง แล้วหยุด\n\n## เช็คลิสต์ด่วนก่อนมอบให้ทีม\n\nก่อนส่งมอบ ให้ทำการทดสอบ "ตาใหม่" ขอคนที่ไม่ได้สร้างโพรโทไทป์เปิดรีโพและเล่าให้ฟังว่าพวกเขาคิดว่ามันทำอะไร ถ้าพวกเขาหาเริ่มต้นไม่ได้อย่างรวดเร็ว ทีมจะต้องจ่ายค่าตรงนั้นในการเปลี่ยนทุกครั้ง\n\nกฎง่าย ๆ: นักพัฒนาคนใหม่ควรหาจุดเริ่มต้นหลักได้ภายในสองนาที นั่นมักหมายความว่า README ชัดเจนที่บอกหนึ่งหรือสองที่ที่ต้องเริ่ม (entry ของเว็บแอป, entry ของ API, config) และไฟล์เหล่านั้นไม่ถูกฝัง\n\nยังต้องเช็คขนาดการตรวจทานด้วย ถ้าโมดูลสำคัญต้องเลื่อนยาวผู้ตรวจจะหยุดจับข้อผิดพลาด แยกไฟล์ยาว ๆ ให้แต่ละไฟล์มีหน้าที่เดียวและเข้าใจได้ภายในหนึ่งการอ่าน\n\nเช็คลิสต์สั้น ๆ ก่อนส่งมอบ:\n\n- จุดเริ่มต้นชัดเจน: ที่ที่แอปเริ่ม, ที่ที่ routes อยู่, ที่อ่านค่าตั้งแวดล้อม\n- ไฟล์ขนาดพอดี: ส่วนมากพอดีแสดงบนหน้าจอหนึ่งหรือสองหน้าจอ; ไม่มี "god files"\n- ชื่อสอดคล้องกับพฤติกรรม: validateUser ตรวจสอบความถูกต้อง ไม่ใช่เขียนลง DB ด้วย\n- Invariants ใกล้โค้ด: คอมเมนต์หรือบล็อกเอกสารเล็ก ๆ ที่บอกกฎที่ต้องรักษา\n- ทุกการเปลี่ยนง่ายต่อการยืนยัน: การเช็คเร็วที่พิสูจน์ว่าฟลูว์สำคัญยังทำงาน\n\n## สถานการณ์การส่งมอบที่สมจริง\n\nMaya เป็นผู้ก่อตั้งที่ไม่ใช่สายเทคนิค เธอสร้าง MVP โดยอธิบายผลิตภัณฑ์ในแชท: CRM ง่าย ๆ สำหรับธุรกิจบริการขนาดเล็ก มันทำงาน: เข้าสู่ระบบ ลูกค้า ดีล โน้ต และหน้าผู้ดูแลพื้นฐาน หลังจากไม่กี่สัปดาห์ เธอจ้างนักพัฒนาสองคนให้รับช่วงต่อจาก “รันบนแลปท็อปได้” เป็นสิ่งที่ธุรกิจเชื่อถือได้\n\nวันแรกพวกเขาไม่ได้เริ่มด้วยการเขียนใหม่ พวกเขาเริ่มจากทำให้โค้ดสามารถตรวจทานได้ การเคลื่อนไหวแรกคือแมปแอปเป็นสองถัง: โมดูลแกนหลัก (สิ่งที่ทุกฟีเจอร์พึ่งพา) และฟีเจอร์ (หน้าจอและเวิร์กโฟลว์ที่ผู้ใช้เห็น) นั่นให้ที่วางสำหรับการตัดสินใจ และที่วางสำหรับการเปลี่ยนแปลง\n\nพวกเขาตกลงแผนที่ฟีเจอร์ง่าย ๆ: core (auth, การเข้าถึง DB, สิทธิ์, logging, คอมโพเนนต์ UI) และ features (customers, deals, notes, admin)\n\nจากนั้นปรับโฟลเดอร์ให้ตรงกับแผนที่นั้น ก่อนหน้านี้ไฟล์กระจัดกระจายด้วยการตั้งชื่อผสมอย่าง CustomerPage.tsx, customer_view.tsx, และ custPageNew.tsx หลังจากนั้นทุกฟีเจอร์มีบ้านเดียวและโค้ดแกนแยกชัดเจน การตรวจทานเร็วขึ้นเพราะ PR มักอยู่ภายในโฟลเดอร์ฟีเจอร์เดียว และการเปลี่ยนแปลงแกนกลางชัดเจน\n\nกฎการตั้งชื่อเล็ก ๆ ช่วยได้มาก: “โฟลเดอร์เป็นคำนาม, คอมโพเนนต์เป็น PascalCase, ฟังก์ชันเป็นคำกริยา, และเราไม่ย่อ” ดังนั้น custPageNew.tsx กลายเป็น CustomerDetailsPage.tsx, และ doStuff() กลายเป็น saveCustomerNote()\n\n### Invariant หนึ่งข้อที่ป้องกันบั๊กเงียบ ๆ\n\nพวกเขาจดกฎสำคัญหนึ่งข้อและใส่ไว้ใน INVARIANTS.md สั้น ๆ ภายในโฟลเดอร์ฟีเจอร์\n\nตัวอย่าง invariant สำหรับ CRM:\n\nเฉพาะเจ้าของดีลหรือ admin เท่านั้นที่แก้ไขดีลได้ ผู้อื่นดูได้แต่แก้สถานะ ค่า หรือโน้ตไม่ได้\n\nประโยคนี้ชี้แนะเช็คในแบ็กเอนด์ คิวรีฐานข้อมูล และสถานะ UI เมื่อมีคนเพิ่ม “bulk edit” ผู้ตรวจจะรู้ได้ทันทีว่าอะไรห้ามพัง\n\n### หน้าตาที่ "พอใช้" ได้หลังหนึ่งสัปดาห์\n\nหลังหนึ่งสัปดาห์ โค้ดยังไม่สมบูรณ์แบบ แต่การส่งมอบเป็นจริง:\n\n- แต่ละฟีเจอร์อยู่ในโฟลเดอร์เดียวด้วยชื่อไฟล์ที่คาดเดาได้\n- โมดูลแกนกลางแยกและใช้ซ้ำ ไม่ใช่คัดลอก\n- Invariants ถูกเขียนไว้ที่ที่มีการเปลี่ยนแปลง ไม่ใช่ฝังในประวัติแชท\n- การเปลี่ยนใหม่ส่งผ่าน PR ขนาดเล็กที่ตรวจได้ง่าย\n\n## ความผิดพลาดทั่วไปที่ทำให้โค้ดจาก AI เปราะบาง\n\nAI ทำให้คุณได้โพรโทไทป์ที่ทำงานได้เร็ว ปัญหาคือ “ทำงานได้” มักพึ่งพาสมมติฐานที่ซ่อนอยู่ เมื่อทีมมาจับ การเปลี่ยนเล็กน้อยทำให้สิ่งต่าง ๆ พังในที่น่าประหลาดใจ\n\nความผิดพลาดทั่วไปคือการรีแฟคเตอร์ทุกอย่างพร้อมกัน การทำความสะอาดครั้งใหญ่ดูน่าพอใจแต่ทำให้ยากจะเห็นว่าอะไรเปลี่ยนและทำไม กำหนดขอบเขตก่อน: ตัดสินใจว่าโมดูลใดนิ่ง ที่ไหนอนุญาตให้โค้ดใหม่ แล้วปรับปรุงทีละส่วน\n\nอีกปัญหาคือแนวคิดที่ซ้ำซ้อนด้วยชื่อแตกต่างกัน AI จะสร้าง UserService และ AccountManager สำหรับงานเดียวกัน หรือ plan vs pricingTier สำหรับแนวคิดเดียว เลือกคำเดียวสำหรับแต่ละแนวคิดหลักและเปลี่ยนชื่อให้สอดคล้องข้าม UI, API, และ DB\n\nกฎที่ซ่อนอยู่ก็เป็นแหล่งปัญหาเช่นกัน ถ้าตรรกะธุรกิจจริง ๆ อยู่ใน prompt หรือประวัติแชท รีโพจะยากต่อการดูแล ใส่กฎไว้ในโค้ดเบสเป็นคอมเมนต์ เทสต์ หรือเอกสาร invariants สั้น ๆ\n\nโฟลเดอร์รวบรวมเช่น shared, common, หรือ utils มักกลายเป็นลิ้นชักขยะ หากต้องโมดูลแชร์ ให้กำหนดความเป็นเจ้าของ (input, output, ความรับผิดชอบ) และรักษาขอบเขตให้แคบ\n\nการผนวกกฎธุรกิจไว้ในโค้ด UI เป็นกับดักอีกอย่าง เงื่อนไขเล็ก ๆ ในคอมโพเนนต์ React อาจกลายเป็นที่เดียวที่มีกฎราคา ต่อมาจะเกิดความขัดแย้งกับแอปมือถือหรือแบ็กเอนด์ เก็บกฎธุรกิจในเลเยอร์เดียว (มักเป็นแบ็กเอนด์หรือโมดูลโดเมน) แล้วให้ UI เรียกใช้แทนการลงมือเขียนซ้ำ\n\nสุดท้าย โค้ดเปราะบางมักมาจากการข้ามขั้นตอนการตรวจทาน ทีมต้องการ diff ขนาดเล็ก commit ชัดเจน และเจตนาที่ชัดเจน แม้การเปลี่ยนเกิดจาก generator ก็ปฏิบัติเหมือน PR ปกติ: จำกัดขอบเขต อธิบายการเปลี่ยน และทำให้ง่ายต่อการยืนยัน\n\n## ขั้นตอนถัดไป: ทำให้การบำรุงรักษาเป็นเวิร์กโฟลว์ปกติ\n\nถือการส่งมอบเป็นจุดเริ่มต้นของการบำรุงรักษ ไม่ใช่เส้นชัย เป้าหมายยังคงเรียบง่าย: คนใหม่สามารถทำการเปลี่ยนแปลงเล็ก ๆ โดยไม่ทำให้กฎที่ซ่อนอยู่พัง\n\nเปลี่ยนความชอบของทีมให้เป็นค่าเริ่มต้นที่เขียนไว้: แผนที่โฟลเดอร์หนึ่งที่ทุกคนทำตาม, สไตล์การตั้งชื่อเดียว, และเทมเพลตหนึ่งสำหรับ invariants เมื่อตกลงกันไว้ล่วงหน้า ความเห็นในการตรวจทานจะไม่ใช่รสนิยมส่วนตัวอีกต่อไป แต่เป็นเกณฑ์ที่สอดคล้องกัน\n\nเก็บ “handoff README” ที่ชี้ไปยังไม่กี่ที่ที่สำคัญ: ที่ที่ invariants อยู่, วิธีรันแอป, วิธีเพิ่มฟีเจอร์อย่างปลอดภัย, และสิ่งที่ห้ามเปลี่ยนโดยไม่หารือ นักพัฒนาคนใหม่ควรหาคำตอบได้ภายในห้านาที\n\nถ้าเวิร์กโฟลว์ของคุณรองรับการย้อนกลับ ให้ใช้มัน ตัวอย่างเช่น Koder.ai รองรับ snapshots และ rollback ซึ่งอาจเป็นตาข่ายความปลอดภัยก่อนรีแฟคเตอร์หรืออัปเกรด dependency เมื่อพร้อมโอนความเป็นเจ้าของ การส่งออกรหัสจาก koder.ai ให้ทีมจะเป็นจุดเริ่มต้นที่สะอาดสำหรับการทำงานด้วย Git ปกติเริ่มจากทำให้โค้ดมีความคาดเดาได้ จัดโครงสร้างโฟลเดอร์ การตั้งชื่อ และขอบเขตให้สอดคล้อง เพื่อให้เพื่อนร่วมทีมสามารถเดาได้ว่าอะไรอยู่ที่ไหนและทำงานอย่างไรโดยไม่ต้องค้นทั่วทั้งรีโป
เลือกแพทเทิร์นเดียวสำหรับงานที่เกิดซ้ำบ่อย ๆ (สถานะการยืนยันตัวตน, การดึงข้อมูล, การตรวจสอบความถูกต้อง, การจัดการข้อผิดพลาด) แล้วใช้แบบเดียวกันทั่วทั้งโปรเจกต์ เป้าหมายคือความสม่ำเสมอ ไม่ใช่ความ “ดีที่สุด” เสมอไป
โค้ดที่ตรวจทานได้คือโค้ดที่นักพัฒนาคนใหม่สามารถหาที่จะเปลี่ยน เปิดการเปลี่ยนแปลงขนาดเล็ก และยืนยันความปลอดภัยของการเปลี่ยนแปลงได้ ถ้าการเปลี่ยนต้องส่งผลกระทบไปยังไฟล์ที่ไม่เกี่ยวข้องหรืออาศัยการคาดเดากฎธุรกิจ แปลว่ายังไม่ตรวจทานได้
ใช้ชุดโฟลเดอร์ระดับบนที่เล็กและคงที่ แล้วแยกความรับผิดชอบให้ชัดเจน เก็บการประกอบแอป (routes/screens), กฎธุรกิจหลัก, และโครงสร้างพื้นฐานแยกกัน เพื่อให้การนำทางใช้เวลาเป็นวินาที ไม่ใช่การสืบค้น
ใส่โค้ดที่อาจจะสร้างใหม่ซ้ำภายหลังไว้ในโฟลเดอร์ที่ชัดเจนเช่น /generated แล้วเก็บโค้ดที่แก้ไขด้วยคนไว้ในบริเวณคงที่อย่าง /core หรือ /app วิธีนี้ช่วยป้องกันการแก้ไขที่ถูกเขียนทับโดยไม่ตั้งใจและทำให้ความเป็นเจ้าของชัดเจนในระหว่างการตรวจสอบ
เลือกคอนเวนชันเดียวแล้วบังคับใช้ทุกที่: รูปแบบตัวพิมพ์สำหรับโฟลเดอร์และไฟล์ ให้ชื่อคอมโพเนนต์สอดคล้อง และใช้ชื่อฟิลด์เหมือนกันระหว่าง UI, API, และฐานข้อมูล ความสม่ำเสมอทำให้การค้นหาเชื่อถือได้และลดบั๊กที่เกิดจากชื่อไม่ตรงกัน
Invariants คือกฎที่ระบบต้องรักษาให้เป็นจริงขณะที่ฟีเจอร์เปลี่ยน เช่น สิทธิ์การเข้าถึง, ข้อจำกัดความเป็นเอกลักษณ์, และการเปลี่ยนสถานะต่าง ๆ การเขียนกฎเหล่านี้ออกมาเปลี่ยนสมมติฐานที่ซ่อนอยู่ให้เป็นข้อที่ผู้ตรวจสอบสามารถปกป้องได้
เก็บไว้ตรงที่คนมักจะเห็นระหว่างการตรวจ PR: ส่วนสั้น ๆ ใน README และบันทึกตรงโค้ดที่บังคับใช้กฎนั้น ถ้ากฎไม่ปรากฏในกระบวนการตรวจ PR ปกติ มันจะถูกลืม
ล็อกขอบเขตก่อน: เลือกเส้นทางผู้ใช้สำคัญไม่กี่อย่างที่ต้องใช้งานได้ แล้วทำให้โฟลเดอร์และชื่อเป็นมาตรฐาน ลบโค้ดที่ตายแล้ว เพิ่มแผนทดสอบสโมคสั้น ๆ แล้วทำรอบการตรวจหนึ่งรอบที่มุ่งเน้นความอ่านง่ายเท่านั้น
หลีกเลี่ยงการรีแฟคเตอร์ใหญ่ที่เปลี่ยนทุกอย่างในครั้งเดียว, โฟลเดอร์ catch-all เช่น utils, และกฎธุรกิจที่ฝังอยู่ในเงื่อนไข UI ตรวจหาความซ้ำซ้อนของแนวคิดที่มีชื่อแตกต่างกัน และระวังการเลื่อนของการตรวจสอบ/การจัดการข้อผิดพลาดระหว่าง endpoints และหน้าจอ