คุณไม่สามารถกดหยุดการพัฒนาได้ นั่นคือสิ่งแรกที่ต้องยอมรับ Ticket ยังคงหลั่งไหลเข้ามา ลูกค้าคาดหวังการส่งมอบ และโค้ดที่มีอยู่ของคุณก็ไม่ได้หยุดทำงานเพียงเพราะคุณตัดสินใจจะทำเอกสารประกอบ ไม่มี Engineering Manager คนไหนจะอนุมัติการหยุดพัฒนาเป็นเดือนๆ เพื่อให้ทีมเขียนสเปกที่ควรจะมีมาตั้งแต่วันแรก OpenSpec ถูกสร้างขึ้นมาเพื่อโลกแห่งความเป็นจริง ไม่ใช่เพื่อจินตนาการแบบโปรเจกต์ใหม่ที่ไร้ข้อจำกัด มันทำงานได้ดีที่สุดเมื่อคุณนำไปติดตั้งเข้ากับสิ่งที่คุณมีอยู่แล้ว รวมถึงลูกค้าของคุณด้วย
เป้าหมายที่นี่ไม่ใช่การเขียนโค้ดใหม่ (rewrite) แต่มันคือการขุดค้นทางโบราณคดีที่ซื่อสัตย์ คุณขุดค้นสิ่งที่กำลังรันอยู่ใน production จริงๆ อธิบายมันอย่างแม่นยำ และปล่อยให้คำอธิบายนั้นวิวัฒนาการไปพร้อมกับโค้ดของคุณ เมื่อสเปกของคุณตรงกับระบบ คุณจะช่วยให้ชีวิตของวิศวกรที่จะเข้ามาในไตรมาสหน้าและเครื่องมือ AI ที่อยู่ใน IDE ของคุณง่ายขึ้น นี่คือวิธีทำโดยไม่พลาดการปล่อย release แม้แต่ครั้งเดียว
เริ่มต้นจากสิ่งที่คุณทำจริงๆ
เปิด repository ของคุณ แล้วคุณจะเห็นโฟลเดอร์ที่ชื่อ controllers, models, services, และ utils สิ่งเหล่านี้คือเลเยอร์ทางเทคนิค และพวกมันกำลังหลอกคุณ พวกมันไม่ได้อธิบายว่าระบบของคุณทำอะไรให้กับธุรกิจ โฟลเดอร์ที่เต็มไปด้วยไฟล์ JavaScript ไม่ได้อธิบายว่าคำสั่งซื้อกลายเป็นรายการจัดส่งได้อย่างไร ในการนำ OpenSpec มาใช้ย้อนหลัง คุณต้องคิดในเชิง "ขีดความสามารถ" (capabilities)
มองหาการดำเนินงานทางธุรกิจที่มั่นคง ซึ่งจะยังคงอยู่แม้ว่าคุณจะเขียน stack ใหม่ทั้งหมดด้วยภาษาอื่นก็ตาม ในบริษัทผลิตภัณฑ์ส่วนใหญ่ สิ่งเหล่านี้จะปรากฏขึ้นซ้ำแล้วซ้ำเล่า: Orders, Billing, Inventory, Customers, และ Notifications จงระบุขีดความสามารถหลักเหล่านี้มาสัก 5 ถึง 8 อย่าง
สำหรับแต่ละอย่าง บังคับตัวเองให้ตอบคำถามเฉพาะเจาะจง 5 ข้อ: ขีดความสามารถนี้แก้ปัญหาในโลกความเป็นจริงอะไร? โค้ดอยู่ที่ไหนกันแน่—ในหนึ่ง service, สาม microservices, หรือโมดูลเก่า (legacy module) ที่ไม่มีใครอยากแตะ? อะไรเป็นตัวกระตุ้น (trigger): การคลิกของผู้ใช้, cron job ที่ตั้งเวลาไว้, หรือ inbound webhook? ข้อมูลอะไรที่ใส่เข้าไปและข้อมูลอะไรที่ออกมา? และสุดท้าย มีระบบอื่นใดบ้างที่ต้องพึ่งพามัน ซึ่งหมายความว่าอะไรจะพังถ้าส่วนนี้หยุดทำงาน?
จงซื่อสัตย์อย่างถึงที่สุด หากขีดความสามารถ "Customers" ของคุณกระจายอยู่ทั้งใน Rails monolith, Node API และ CRM ภายนอก ให้เขียนลงไปแบบนั้นเลย แผนที่ของคุณต้องดูเหมือนพื้นที่จริง ไม่ใช่ความฝันของสถาปนิก
เขียนความจริง ไม่ใช่รายการสิ่งที่อยากให้เป็น
ประโยคที่อันตรายที่สุดในความพยายามทำเอกสารใดๆ คือ "ในเมื่อเรากำลังเขียนเรื่องนี้อยู่ เราก็ถือโอกาสแก้ไขมันไปเลยแล้วกัน" หยุดก่อน คุณไม่ได้กำลังออกแบบ checkout flow ใหม่ คุณกำลังอธิบาย checkout flow ที่กำลังเรียกเก็บเงินจากบัตรเครดิตจริงๆ อยู่ในขณะนี้
หากการสั่งซื้อกระตุ้นให้มีการเรียกเก็บเงินทันทีและจากนั้นส่งอีเมลผ่าน background worker ให้บันทึกลำดับขั้นตอนที่แม่นยำนั้น อย่าใส่ event queue ที่คุณวางแผนจะเพิ่มในไตรมาสหน้าเข้าไป อย่าแสร้งทำว่าการตรวจสอบ (validation) เกิดขึ้นที่ API edge หากจริงๆ แล้วมันอยู่ลึกเข้าไปใน service class ความแม่นยำสำคัญกว่าความคาดหวังมาก
เอกสารที่ไม่ถูกต้องแย่ยิ่งกว่าไม่มีเลย มันจะฝึกพนักงานใหม่ให้คาดหวังพฤติกรรมที่ไม่มีอยู่จริง มันจะส่งเครื่องมือช่วยเขียนโค้ด AI ไปในเส้นทางที่จินตนาการขึ้นจากความปรารถนา เมื่อสเปกของคุณตรงกับ production คุณจะสร้างฐานข้อมูลที่เชื่อถือได้ การ debug จะเร็วขึ้นเพราะคุณไม่ต้องเดาเกี่ยวกับ flow ที่ "ตั้งใจ" ให้เป็น การ refactoring จะปลอดภัยขึ้นเพราะคุณรู้ว่าจุดเริ่มต้นคือของจริง
สกัดสัญญา (Contracts) จาก API ของคุณ
API endpoints ของคุณบังคับใช้กฎเกณฑ์อยู่แล้ว เพียงแต่พวกมันเป็นกฎที่แฝงอยู่ การนำ OpenSpec มาใช้ย้อนหลังหมายถึงการดึงกฎเหล่านั้นออกมาให้ชัดเจน
เริ่มจาก input และการตรวจสอบ (validation) จริงๆ แล้ว endpoint นั้นยอมรับอะไรบ้าง? จงบันทึกประเภทข้อมูล (types), ฟิลด์ที่จำเป็น (required fields), ความยาวสูงสุด, และความสัมพันธ์ระหว่างฟิลด์ (cross-field dependencies) จากนั้นอธิบายพฤติกรรมทางธุรกิจ เช่น การเรียกใช้งานนี้สร้าง record, กระตุ้น side effect, หรือเพียงแค่ตรวจสอบสถานะเทียบกับอีก service หนึ่ง? จงระบุให้ชัดเจน
สุดท้าย ให้ทำรายการ response สิ่งที่ส่งกลับมาเมื่อสำเร็จคืออะไร? รหัสข้อผิดพลาด (error codes) ที่แน่นอนคืออะไร และจะปรากฏขึ้นภายใต้เงื่อนไขใด? อย่าเขียนแค่ว่า "returns an error" แต่ให้เขียนว่า "returns 422 เมื่อที่อยู่ในการเรียกเก็บเงินหายไป และ 409 เมื่อสินค้าถูกจองโดยกระบวนการอื่นไปแล้ว" ความแม่นยำระดับนี้จะเปลี่ยน route ที่คลุมเครือให้กลายเป็นสัญญาที่ทีม frontend, วิศวกร QA และเครื่องมืออัตโนมัติต่างไว้วางใจได้
ตามล่ากฎที่ซ่อนอยู่
Some of the most expensive knowledge in your system lives in the gaps. It is buried in conditional blocks inside service classes, tucked into database triggers, or written into stored procedures that no one has touched in two years. These are your business rules, and they are usually rediscovered during outages or by cornering the one engineer who has been there since the beginning.
Pull them into daylight. Start with the ones you already know. Orders above a certain value need manager approval before they proceed. Inactive user accounts cannot create new orders. Refunds are only permitted before settlement completes. Write each rule next to the capability it governs, in language clear enough that a product manager could read it without a translator.
When you centralize these rules, you do more than document them. You expose duplication. You reveal conflicts. And you give the entire team a single place to debate policy before someone commits a one-line change that accidentally violates a constraint you forgot existed.
Map the Plumbing
Modern systems run on events. An action in one service ripples through half a dozen others before anything visible reaches the user. You need to chart those ripples. Map the flow from one event to the next for your core workflows. Order created leads to inventory reserved, which waits for payment confirmed. Draw the full chain, even if some links feel fragile or use different protocols.
Do not stop at internal traffic. External services are part of your system whether you treat them that way or not. For each integration, record its purpose, how your application authenticates, and how it fails. Does the payment gateway timeout after thirty seconds and return a generic 500? Does the shipping API return malformed JSON on weekends? Does the identity provider revoke refresh tokens earlier than its own documentation claims? These details look trivial
