951 คำ
5 นาที
เมื่อผมอยากทำซอฟต์แวร์ใช้เอง ภาค 2 ตอนที่ 8: codebase ที่ไม่เน่า
สารบัญ

ตอนที่แล้ว ผ่านด่านและถอยได้ ด่านกับทางถอยอยู่ครบใน repo แรก

ตอนนี้เราจะได้ template repo กับหน้ากติกาข้าม repo ให้ทุก repo ใหม่เกิดมาพร้อมของชุดนั้น

ตอนหน้าเมื่อระบบพังตอนตีสาม ทุก repo จะมีวิธีรู้และวิธีถอยแบบเดียวกัน

ทุกบทความในซีรีส์นี้มาจากการที่ผมคุยกับ AI แล้วค้นข้อมูลเพิ่มเติม ผมเป็นคนกำหนดทิศทาง ให้ AI ช่วยสรุป วิเคราะห์ และเรียบเรียงออกมาเป็นบทความครับ

เราอยู่ตรงไหนของแผนที่#

บนแถบ 5 ขั้น Design กับ Build สว่างอีกรอบ คราวนี้สำหรับ repo ที่สอง

ชิ้นจิ๊กซอว์ที่ 7 codebase ที่ไม่เน่า คือเรื่องที่ 6 ดูแล codebase เรื่องที่ 7 จัดการ repo และเรื่องที่ 8 dependency และ supply chain

หัวใจของตอนนี้#

กฎที่ต้องลอกเองทุกครั้งจะหาย กฎต้องติดมากับ repo ตั้งแต่เกิด

ทำไมเรื่องนี้สำคัญ?#

ตอน 4 ถึง 7 สร้างกฎ ตัวตน ช่องงาน และด่านไว้ใน repo แรกเท่านั้น

พอมี repo ที่สอง ทุกอย่างต้องเริ่มใหม่ด้วยมือ

agent แต่ละตัวจะทำตามแบบที่ต่างกัน และใครก็แก้ database ร่วมได้

หลัก 5 ข้อข้างล่างคือวิธีให้กฎติดมากับ repo

repo ที่สองที่เกิดมาเปล่าๆ#

มิวอยากได้หน้าจองคิว

ต้นบอก agent ว่า “เริ่มแอปใหม่ให้หน่อย”

agent เลือกภาษาใหม่ ใช้รูปแบบวันที่ของตัวเอง และไม่มี CI

มันเขียนลง Postgres ตัวเดียวกับแอปแรกตรงๆ แล้วเพิ่ม column ที่ code ของแอปแรกไม่รู้จัก (ตัวอย่าง)

repo ที่สองไม่รู้เลยว่ามี DR-01 เรื่องวันที่ หรือ DR-02 เรื่อง database

agent เดินทางที่ง่ายที่สุดเสมอ หน้าที่เราคือทำให้ทางที่ง่ายเป็นทางที่ถูก

lauren (@poteto) ก็ เล่า ว่ากำลังทำ “a new internal framework for our apps that imposes a lot of hard constraints on agents and makes the easy path the best path”

ภาพสองฝั่ง ซ้ายคือ app-booking ที่เกิดเปล่า ไม่มีกฎ ไม่มีด่าน เขียนตรงลง database ร่วมจนมีรอยร้าวสีแดง ขวาคือ app-booking ที่เกิดจาก template มีสมุดกฎและด่าน อ่านข้อมูลผ่าน app-ledger API

เรื่องจริงจาก Spotify

ปัญหานี้ไม่ได้เกิดแค่กับคนทำคนเดียว

ปี 2020 Spotify เล่า ว่าตอนบริษัทโต เขาเจอ “a fragmented ecosystem of developer tooling where the only way to find out how to do something was to ask your colleague”

เขาเรียกมันว่า rumour-driven development และสรุปว่า “We found that rumour-driven development simply wasn’t scalable.”

ทางแก้คือ Golden Path ซึ่ง “is the ‘opinionated and supported’ path to ‘build something’”

ของต้นเล็กกว่ามาก แต่ปัญหาเดียวกัน กฎที่อยู่ในหัวคนเดียว ไม่ติดไปกับ repo ใหม่

ด่านที่มีใน repo เดียวพอไหม?#

ไม่พอ

ด่านจากตอน 7 กับตัวตนของ agent จากตอน 5 อยู่ใน settings ของ repo แรก ส่วน AGENTS.md จากตอน 4 อยู่ในไฟล์ของ repo แรกเท่านั้น

repo ที่สองไม่ได้อะไรติดมาเลย ถ้าเราไม่ทำให้มันติด

หลัก 1: template repo ทำให้ทางที่ง่ายเป็นทางที่ถูก#

ข้อนี้คือหัวใจตรงๆ กฎต้องอยู่ใน repo ตั้งแต่วินาทีที่มันเกิด

GitHub เขียนว่า “Anyone with access to the template repository can create a new repository based on the template with the same directory structure, branches, and files”

CNCF Platforms white paper เรียก workflow ที่ “offered with an initial project template and documentation, a bundle often described as a golden path”

template ของต้นมี AGENTS.md, lint และ types, CI workflow, issue form กับ labeler, CODEOWNERS, rollback.md กับ emergency.md และลิงก์ไปหน้ากติกาข้าม repo

branch protection กับ secret เป็น settings ไม่ใช่ไฟล์ template จึงมี checklist “ตั้งค่าหลังสร้าง” 5 บรรทัดแนบไปด้วย

หลัก 2: ข้อมูลหนึ่งชุด มีเจ้าของ repo เดียว#

กฎเรื่องใครแก้ข้อมูลได้ ก็ต้องเขียนไว้ที่เดียว ไม่ใช่ให้แต่ละ repo เดาเอง

repo แรกเป็นเจ้าของ schema ของลูกค้า

repo ที่สองอ่านผ่าน API ของ repo แรก หรือใช้ key แบบ read-only และไม่แก้ schema เด็ดขาด

ต่อจากตอน 5 agent ของ repo ที่สองได้ key อ่านอย่างเดียว ต่อจากตอน 7 migration เป็น high และอยู่ใน repo เจ้าของเท่านั้น

ใส่ CODEOWNERS ที่ migrations/** เพราะ “Code owners are automatically requested for review when someone opens a pull request that modifies code that they own” (GitHub Docs)

database customers ทรงกระบอกที่ app-ledger เป็นเจ้าของ มีป้ายเจ้าของ ต้น มีลูกศรเขียนและ migrate จาก app-ledger ซึ่งแก้ schema ได้ repo เดียว ส่วน app-booking มีลูกศรเส้นประป้ายว่าอ่านผ่าน API หรือ read-only key

หลัก 3: ภาษาไหนก็ได้ แต่ต้องมีเหตุผลเขียนไว้#

เหตุผลที่อยู่ในหัวคือกฎที่ลอกไม่ได้ ต้องเขียนลงไฟล์

ต่อจาก DR-01 ถึง DR-04 ในตอน 3 ทุก repo ในหน้ากติกามีช่อง stack กับเหตุผลหนึ่งบรรทัด ชี้ไปที่ ADR

adr.github.io อธิบายว่า “An Architectural Decision Record (ADR) captures a single AD and its rationale”

ภาษาต่างกันได้ แต่สัญญากลางต้องเหมือนกัน รูปแบบวันที่ (DR-01) auth (DR-03) และรูปแบบ API (DR-04)

หลัก 4: dependency ดูแลตัวเองได้#

library ที่ไม่มีใครอัปเดต คือกฎอีกข้อที่ต้องจำเอง ให้เครื่องจำแทน

Dependabot “You can use Dependabot to keep the packages you use updated to the latest versions”

และ “When Dependabot raises pull requests, these pull requests could be for security or version updates”

PR ของมันเข้าคิวตอน 6 เป็น low หรือ medium แล้วผ่านด่านตอน 7 เหมือน PR อื่น

ไกลกว่านั้นคือ supply chain SLSA “is a set of incrementally adoptable guidelines for supply chain security” (หน้านี้เป็นฉบับ v1.0 ที่ถูกแทนแล้ว ผมยกมาแค่แนวคิด)

หลัก 5: คนสวนดึงทุก repo กลับเข้าแบบ#

template copy ไฟล์ครั้งเดียวตอนเกิด หลังจากนั้นแต่ละ repo ก็ค่อยๆ เพี้ยน ต้องมีคนดึงกลับ

ต้นตั้ง agent คนสวนให้เปิด PR เล็กๆ สัปดาห์ละครั้ง (ตัวอย่าง) เช่น repo ที่ขาด workflow, code ที่ไม่ได้ใช้, flag เก่าจากตอน 7 และ AGENTS.md ที่ล้าสมัย

PR พวกนี้เป็น low เลย auto-merge ผ่านกฎ

lauren แนะนำ ว่า “routines can be expensive if they fire too often. hourly is the most frequent interval i would recommend for scheduled ones”

งานคนสวนสัปดาห์ละครั้งก็พอ และเป็นเรื่องที่จะกลับมาในตอน 10 ตอนคุมค่าใช้จ่าย

template และหน้ากติกาของต้นหน้าตาเป็นยังไง?#

template checklist (ตัวอย่าง)

ไฟล์/การตั้งค่ามาจากตอนไหนบังคับด้วยอะไรrepo ไหนยังไม่มี
AGENTS.mdตอน 4lint step ใน CIไม่มี
CI workflowตอน 4, 7required checkไม่มี
issue form + labelerตอน 6workflowไม่มี
CODEOWNERSตอน 6, 7branch protectionไม่มี
rollback.md + emergency.mdตอน 7ลิงก์ใน PR templateไม่มี
dependabot.ymlตอน 8Dependabotไม่มี
branch protection + key ของ agentตอน 5, 7setup scriptทำมือ

หน้ากติกาข้าม repo (ตัวอย่าง)

repoเจ้าของเป็นเจ้าของข้อมูลstack + เหตุผลใครแก้ schemadependency policy
app-ledgerต้นcustomers, paymentsTypeScript (DR-02)repo นี้เท่านั้นDependabot รายสัปดาห์
app-bookingต้นbookingsPython เพราะ library ปฏิทินที่มิวใช้ (DR-05 ใหม่)ห้าม อ่าน customers ผ่าน APIDependabot รายสัปดาห์

ตารางหน้ากติกาข้าม repo เทียบ app-ledger กับ app-booking ทั้งสองมีเจ้าของคือต้น app-ledger เป็นเจ้าของข้อมูล customers กับ payments ใช้ TypeScript ตาม DR-02 แก้ schema ได้ที่ repo นี้เท่านั้น app-booking เป็นเจ้าของ bookings ใช้ Python เพราะ library ปฏิทินที่มิวใช้ ตาม DR-05 ใหม่ ช่องใครแก้ schema เขียนว่า ห้าม อ่าน customers ผ่าน API ทั้งสองใช้ Dependabot รายสัปดาห์ ท้ายภาพเขียนว่ารับมาจากตอน 3 4 5 6 7 และส่งต่อให้ตอน 9 10 และ 13

ตาราง template checklist ของ repo ใหม่ มีคอลัมน์ไฟล์หรือการตั้งค่า ตอน และบังคับด้วยอะไร เจ็ดแถวคือ AGENTS.md, CI workflow, issue form กับ labeler, CODEOWNERS, rollback.md กับ emergency.md, dependabot.yml และ branch protection กับ key ที่มีป้ายว่าทำมือ หัวภาพเขียนว่ารับมาจากตอน 3 4 5 6 7 ท้ายภาพเขียนว่าส่งต่อให้ตอน 9 10 และ 13

มาตรฐานว่ายังไง

ISO/IEC TR 29110-5-1-2 (ฉบับปี 2011) มีเป้าหมายข้อหนึ่งของ Project Management เขียนว่า “A software Version Control Strategy is developed.” และ “Modifications and releases of the items are controlled and made available to the Customer and Work Team including the storage, handling and delivery of the items.”

12207 มี Configuration management ในกลุ่ม Technical management และมี Life cycle model management กับ Infrastructure management ในกลุ่ม Organizational project-enabling

ข้อนี้ผมเทียบเอง platform team กับ golden path ของบริษัทใหญ่ ก็คือ template repo กับหน้ากติกาหน้าเดียวของต้น แนวคิดเดียวกัน แค่ทำคนเดียว

จิ๊กซอว์ชิ้นที่เติมแล้ว#

ชิ้นที่ 7 codebase ที่ไม่เน่า เติมแล้ว

ทุก repo เกิดมาพร้อมกฎ และใครเป็นเจ้าของข้อมูลอะไรถูกเขียนไว้แล้ว

ชิ้นถัดไปคือวิธีรู้ตัวและกู้คืนเมื่อระบบพัง

สิ่งที่ผมได้จากตอนนี้#

ลองทำเอง#

ใช้ test repo ที่ทิ้งได้เท่านั้น ใช้ราว 20-30 นาที (ตัวอย่าง) (1) ตั้ง test repo เป็น template ที่ Settings → Template repository (2) ใส่ AGENTS.md, CI workflow, .github/dependabot.yml และ CODEOWNERS (3) กด “Use this template” สร้าง repo ใหม่ แล้วดูว่าไฟล์ไหนติดมา settings ไหนไม่ติด เช่น branch protection และ secret (4) รอหรือสั่งให้ Dependabot เปิด PR

ผมลองแล้ว: __ นาที ฿0 repo ใหม่ได้ไฟล์ __ ชิ้น ตั้งค่าที่ไม่ติดมา: __ Dependabot เปิด PR __ อัน

เก็บศัพท์#

คำความหมายสั้นๆ
template repositoryrepo ต้นแบบที่ใช้สร้าง repo ใหม่
golden pathทางที่แนะนำและมีคนดูแล
CODEOWNERSไฟล์บอกว่าใครเป็นเจ้าของ code ส่วนไหน
data ownershipข้อมูลแต่ละชุดมีเจ้าของคนเดียว
ADRบันทึกการตัดสินใจและเหตุผล
dependencylibrary ที่ code เราพึ่ง
Dependabotbot ของ GitHub ที่เปิด PR อัปเดต dependency
supply chainทุกอย่างที่ไหลเข้ามาเป็นส่วนหนึ่งของ software เรา
SLSAแนวทางความปลอดภัยของ supply chain
driftrepo ค่อยๆ เพี้ยนออกจากแบบ
gardeneragent ที่คอยดึง repo กลับเข้าแบบ

จดบันทึก#

repo ใหม่ทุกตัวเกิดจาก template และข้อมูลหนึ่งชุดมีเจ้าของ repo เดียว

ถ้าต้นเริ่มใหม่ เขาจะทำเรื่องนี้ตั้งแต่วันแรกไหม?

template ไม่ต้องทำวันแรก เพราะมี repo เดียวยังไม่มีอะไรให้ลอก แต่ทันทีที่วางแผน repo ที่สอง ให้เปลี่ยน repo แรกเป็น template ก่อน ส่วนเจ้าของข้อมูลกับ dependabot.yml ทำวันแรกเลย ใช้ราว 20 นาที ฿0 (ตัวอย่าง)

ตอนต่อไป#

ตีสาม หน้าจองคิวของมิวล่ม (ตัวอย่าง)

มิวรู้จากลูกค้าก่อนต้นจะรู้ และ backup ที่มีอยู่ไม่เคยถูกลอง restore เลยสักครั้ง

ตอนหน้า ทุก repo จะได้วิธีรู้ตัวก่อนลูกค้า วิธีถอย และ backup ที่พิสูจน์แล้วว่ากู้ได้

คำถามที่พบบ่อย#

monorepo ดีกว่าไหม?

หลายครั้งใช่ Matt Pocock ตอบไว้ ว่า “Monorepo is usually better - single commit history, single directory. But TBH agents can do fine working across multiple repos too.” แยกเมื่อมีเหตุผล และเขียนเหตุผลไว้ในหน้ากติกา

แก้ template แล้ว repo เก่าได้ด้วยไหม?

ไม่ได้ ไฟล์ถูก copy ครั้งเดียว นี่คือเหตุผลที่ต้องมีคนสวน

ใช้หลายภาษาได้ไหม?

ได้ ถ้าเขียนเหตุผลไว้ และสัญญากลางใช้ร่วมกัน

Dependabot PR ท่วมจะทำยังไง?

รวม update เป็นกลุ่ม ให้ low auto-merge และใช้เพดานงานจากตอน 6

Next → ภาค 2 ตอนที่ 9: ถ้าระบบพังตอนตีสาม