Skip to content

15.11 Guardrails

บทนี้รวบรวม "กฎ" ที่จะป้องกันไม่ให้ debt ใหม่เกิดขึ้นอีกในระบบ แต่ละข้อ map กลับไปยัง debt ในบทก่อนหน้า

หลักการ

ทุก debt ใน Volume นี้สะท้อนการตัดสินใจหรือการละเว้นการตัดสินใจบางอย่าง Guardrails คือกฎที่บังคับให้การตัดสินใจครั้งต่อไปเป็นไปในทิศทางที่ดีกว่า

กฎทั้งหมดนี้ต้องสามารถตรวจสอบได้อัตโนมัติ (CI/CD) ไม่ใช่แค่เอกสารปฏิบัติ

15 Guardrail

G1 · ไม่มี console.log ใน production code

ป้องกัน: LEG-24

ใช้ structured logger (slog, zerolog, pino, winston) เท่านั้น

การตรวจ: ESLint rule no-console (ยกเว้นใน dev-only file), golangci-lint forbidigo

G2 · ไม่มี execSync / shell-out ใน request handler

ป้องกัน: SEC-1, PERF-1

ถ้าจำเป็นต้องเรียก binary ใช้ arg-array form (execFile, os/exec ที่ไม่ผ่าน shell)

การตรวจ: ESLint no-restricted-syntax สำหรับ execSync, code review

G3 · ไม่มี secret ใน source

ป้อลง: SEC-3, SEC-4, SEC-11

ใช้ secret manager หรือ environment variable เท่านั้น

การตรวจ: pre-commit hook ที่ scan pattern ของ secret (เช่น trufflehog, gitleaks)

G4 · engines.node / go.mod version บังคับ

ป้องกัน: LEG-18

CI ตรวจ engines field และ version ที่ใช้จริง

การตรวจ: CI step ที่ run node --version และ compare กับ engines

G5 · Lockfile commit + CI ตรวจ drift

ป้องกัน: LEG-15, LEG-16

CI รัน yarn install --frozen-lockfile (หรือ npm ci) ถ้า lockfile drift ให้ fail

การตรวจ: CI โดยตรง

G6 · Strict types

ป้องกัน: LEG-17

Go strict-by-default; TypeScript strict: true สำหรับ TS ที่เหลือ

การตรวจ: tsc --noEmit + golangci-lint

G7 · Migration forward-only

ป้องกัน: CORR-6

ไม่มี ORM auto-sync ใน prod migration ใช้ golang-migrate, goose, atlas

การตรวจ: CI step ที่รัน migration บน test DB

G8 · design system / icon / DnD / date library ตัวเดียวต่อแอป

ป้องกัน: LEG-26

policy document + dependency audit ใน CI

การตรวจ: lint rule + manual review

G9 · ไม่มี _bk / _copy files

ป้องกัน: LEG-14

.gitignore + pre-commit hook ที่ปฏิเสธไฟล์ที่ตรง pattern

การตรวจ: pre-commit + CI

G10 · PII ไม่อยู่ใน URL

ป้องกัน: SEC-8

ตัวระบุ sensitive อยู่ใน POST body หรือ signed token เท่านั้น

การตรวจ: code review + log scanner ที่หา pattern ของ identityCard, empCode ใน URL

G11 · CORS allow-list explicit

ป้องกัน: SEC-5

ไม่มี origin: '*' ใน production

การตรวจ: lint + integration test

G12 · Rate limit ทุก public endpoint

ป้องกัน: SEC-10

middleware ที่ apply rate limit โดย default route ที่ต้องการ exempt ต้องระบุชัดเจน

การตรวจ: code review + integration test

G13 · Casbin policy test สำหรับทุก (role × menu × action)

ป้องกัน: CORR-4

test matrix ที่ cover ทุกกรณี ส่งผลใน CI

การตรวจ: test suite

G14 · Bounded context < 400 LOC ต่อไฟล์

ป้องกัน: PERF-6, LEG-21, LEG-23

god file fail CI

การตรวจ: lint rule max-lines

G15 · i18n ที่ presentation layer

ป้องกัน: LEG-30

error carry code ไม่ carry message ในภาษาใดภาษาหนึ่ง

การตรวจ: code review + lint

ตารางสรุป Guardrail → Debt

GuardrailDebt ที่ป้องกันการตรวจEffort เริ่มต้น
G1LEG-24ESLint, golangci-lint1 วัน
G2SEC-1, PERF-1ESLint, review1 วัน
G3SEC-3, SEC-4, SEC-11gitleaks, pre-commit1 วัน
G4LEG-18CI0.5 วัน
G5LEG-15, LEG-16CI0.5 วัน
G6LEG-17tsc, golangci-lint0.5 วัน
G7CORR-6CI1 วัน
G8LEG-26lint, reviewongoing
G9LEG-14pre-commit, CI0.5 วัน
G10SEC-8review, log scanongoing
G11SEC-5lint, test0.5 วัน
G12SEC-10test1 วัน
G13CORR-4test2-3 วัน
G14PERF-6, LEG-21, LEG-23lint0.5 วัน
G15LEG-30review, lintongoing

Effort รวมเริ่มต้น: ~2 สัปดาห์ เพื่อตั้ง guardrail ทั้งหมด

กลยุทธ์การนำไปใช้

ลำดับความสำคัญ

  1. เริ่มจาก G3, G5, G7 — ป้องกันความเสี่ยงที่ร้ายแรงที่สุด (secret, lockfile, migration)
  2. ตามด้วย G1, G2, G4, G6 — พื้นฐานของ code quality
  3. ตามด้วย G9, G11, G14 — lint ที่ลด noise
  4. สุดท้าย G8, G10, G12, G13, G15 — ที่ต้องการ culture change

อย่าเข้มงวดเกินไปตอนเริ่ม

ถ้านำ guardrail ทั้ง 15 มาใช้พร้อมกัน CI จะ fail ทันทีเพราะ debt เดิม — แนะนำ:

  1. เปิด guardrail เป็น warning ก่อน (ไม่ block)
  2. แก้ debt ที่ flag ทีละรายการ
  3. ค่อยเปลี่ยนเป็น error เมื่อ debt ลดลง

กรรมวิธี "grandfathering"

สำหรับ debt ที่มีอยู่แล้วและยังไม่ได้แก้ ใช้ inline comment ที่ mark ว่ายกเว้น:

javascript
// eslint-disable-next-line no-console (LEGACY: LEG-24, แก้ใน Wave 1)
console.log('debug info');

แต่ละ exception ต้องมี:

  • debt ID ที่เชื่อมโยง
  • Wave ที่จะแก้
  • วันที่จะ review อีกครั้ง

Guardrail เป็นพื้นฐานของ engineering culture

Guardrails ไม่ใช่แค่ lint rule — เป็นวิธีที่ทีมตกลงกันว่าจะทำงานอย่างไร เมื่อ guardrail ทำงาน CI จะบังคับ และนักพัฒนาใหม่จะเรียนรู้ได้จาก error message

ถ้าไม่มี guardrails, debt จะกลับมาสะสมอีก แม้หลัง Wave 0/1/2/3 เสร็จ

บทถัดไปจะสรุป scorecard ที่เปรียบเทียบสถานะปัจจุบัน vs หลัง Wave 0-1 vs หลัง Wave 2-3