บทที่ 1 · Part 1 — Foundation

What System Design Is

Quality attribute, constraint และการ defend การตัดสินใจ — คำตอบ 4 แบบของ architect และ design loop

มีคำถามหนึ่งที่ทำให้ห้องประชุมเงียบได้ทุกครั้ง: "ทำไมต้องออกแบบแบบนี้" ถ้าคำตอบคือ "เพราะเป็น best practice" หรือ "เพราะ Netflix ทำแบบนี้" นั่นไม่ใช่ system design — นั่นคือการลอกโครงสร้างมาโดยไม่รู้ว่าโครงสร้างนั้นแก้ปัญหาอะไร

จบบทนี้คุณจะ

  • นิยาม system design ได้เป็นประโยคเดียวที่ใช้งานได้จริง
  • แยก quality attribute ออกจาก feature และรู้ว่าอันไหนกำหนดโครงสร้าง
  • รู้จักคำตอบ 4 แบบของ architect และรู้ว่าเมื่อไหร่ต้องใช้อันที่ 4
  • เข้าใจว่าทำไม design เป็น loop ไม่ใช่ waterfall

นิยามที่ใช้งานได้

System design คือการ เลือกโครงสร้าง ที่ทำให้ quality attribute เป็นจริง ภายใต้ constraint ที่มี และ defend การเลือกนั้นได้

ทั้งงานอยู่ในประโยคเดียวนี้ มี 3 คำที่ต้องขยาย

Quality attributes — สิ่งที่กำหนดโครงสร้างจริงๆ

Feature ไม่ค่อยกำหนดสถาปัตยกรรม แต่ quality attribute (หรือ non-functional requirement) กำหนด

"ระบบต้องโอนเงินได้" ไม่บอกอะไรเลยว่าต้องมีกี่ service ใช้ฐานข้อมูลอะไร แต่ "ต้องโอนได้ 1,000 tps ที่ p99 < 300 ms และห้ามเงินหายแม้ AZ ล่ม และต้องเก็บ audit trail 10 ปี" — อันนี้บังคับโครงสร้างแทบทั้งหมด

Quality attributeคำถามที่ต้องถามให้ได้ตัวเลขหน่วยที่ต้องได้กลับมา
Throughputpeak เท่าไหร่ ไม่ใช่ averagereq/s, txn/s, MB/s
Latencyp50/p99/p999 ของ endpoint ไหนms
Availabilityยอมล่มได้กี่นาทีต่อเดือน% หรือ นาที/เดือน
Consistencyข้อมูลเก่าได้กี่วินาที และเก่าตรงไหนไม่ได้เลยวินาที + รายชื่อ field
Durabilityยอมเสียข้อมูลย้อนหลังได้กี่นาทีRPO เป็นวินาที/นาที
Security & privacyข้อมูลอะไรเป็น sensitive ใครเข้าถึงได้classification + access matrix
Costเพดานงบต่อเดือน และต้นทุนต่อ transactionบาท/เดือน, บาท/txn
Operabilityทีมกี่คนดูแล มี on-call ไหมคน, ชั่วโมง/สัปดาห์
Time-to-marketต้องขึ้นเมื่อไหร่ และอะไรเลื่อนได้วันที่ + scope ที่ตัดได้

เทคนิคเปลี่ยนคำคลุมเครือให้เป็นตัวเลข

ทุกครั้งที่ได้ยินคำว่า "เร็ว" "เยอะ" "ห้ามล่ม" "real-time" ให้ถามกลับ 2 คำถาม: "วัดที่ไหน" และ "เท่าไหร่ถือว่าไม่ผ่าน" ถ้าตอบไม่ได้ requirement นั้นยังไม่มีอยู่จริง — มีแต่ความรู้สึก

Constraints — สิ่งที่ทำให้ design เป็นงานวิศวกรรม ไม่ใช่งานอดิเรก

Constraint คือของที่คุณเปลี่ยนไม่ได้ในรอบนี้ และมันมักไม่ใช่เรื่อง technical:

  • ทีม — มีคนกี่คน รู้ภาษาอะไร ดูแล Kubernetes เป็นไหม มี on-call rotation ไหม
  • เงิน — งบ infra ต่อเดือน และงบสำหรับ vendor/license
  • Regulator — สำหรับ fintech ไทยคือ BOT, PDPA, และถ้าแตะบัตรก็ PCI-DSS ข้อกำหนดเรื่องที่เก็บข้อมูล (data residency) และระยะเวลาเก็บเป็น constraint แข็ง
  • สัญญาที่เซ็นไปแล้ว — vendor ที่ใช้อยู่, bank partner ที่ API เป็นแบบนี้แก้ไม่ได้
  • ระบบเดิม — ฐานข้อมูลอายุ 8 ปีที่ยังมี business logic อยู่ใน stored procedure
  • Deadline — วันที่ประกาศกับตลาดไปแล้ว

Design ที่ไม่พูดถึง constraint เลยคือ design ที่ยังไม่ถูกทดสอบว่าทำได้จริง

Defend — บอกได้ว่าแลกอะไรไป

Defend ไม่ได้แปลว่า "พิสูจน์ว่าถูก" แต่แปลว่า บอกได้ว่ายอมเสียอะไรเพื่อได้อะไร รูปประโยคที่ใช้ได้:

"เราเลือก eventual consistency สำหรับ notification feed ยอมรับความเก่าได้ถึง 5 วินาที เพราะผลกระทบทางธุรกิจคือ badge count ขึ้นช้า ไม่ใช่ยอดเงินผิด — ส่วนยอดเงินเราใช้ strong read จาก primary เสมอ"

สังเกตว่ามี 3 ส่วน: เลือกอะไร, ยอมเสียอะไรเป็นตัวเลข, เพราะผลกระทบคืออะไร

The three-sentence test

Design ที่คุณเสนอควรย่อเป็น 3 ประโยคได้: มันทำอะไร, มันอยู่รอดได้ยังไง, มันยอมเสียอะไร ถ้าย่อไม่ได้ แปลว่าคุณยังไม่เข้าใจ design ของตัวเอง ลองทำกับระบบที่คุณดูแลอยู่ตอนนี้เลย

คำตอบ 4 แบบของ architect

Engineer ที่ยังใหม่พยายามมีคำตอบให้ทุกคำถาม architect ที่โตแล้วมีคำตอบ 4 แบบ และใช้แต่ละแบบอย่างแม่นยำ

#รูปประโยคหมายความว่าสิ่งที่ต้องทำต่อ
1"นี่คือ design และนี่คือเหตุผล"คุณรู้จริงเขียนเป็น ADR
2"ขึ้นอยู่กับ X — ถ้า X เป็น A ใช้แบบ 1, ถ้าเป็น B ใช้แบบ 2"คุณรู้ทางแยก แต่ไม่รู้ inputไปหา X ให้ได้
3"ยังไม่รู้ — นี่คือวิธีที่จะหาคำตอบ และจะรู้เมื่อไหร่"คุณรู้ว่าไม่รู้spike / load test / ถาม vendor
4"อันนี้ไม่ใช่การตัดสินใจของผม"เรื่องนี้มีเจ้าของอื่นescalate พร้อมทางเลือก

คำตอบแบบที่ 4 สำคัญที่สุดในองค์กรที่ถูกกำกับดูแล และเป็นแบบที่ engineer มักข้าม ให้ฝึกจับสัญญาณ — เรื่องพวกนี้ ไม่ใช่ ของ architect คนเดียว:

  • เพดานการโอน/ถอนต่อวัน และเงื่อนไขที่ยอมให้ทำรายการได้
  • ระยะเวลาเก็บข้อมูลลูกค้าและข้อมูลธุรกรรม
  • KYC tier threshold และเกณฑ์ที่ถือว่าเป็นธุรกรรมน่าสงสัย
  • การยอมรับ security exception หรือ compensating control
  • การแถลงต่อสาธารณะเมื่อเกิด incident

อย่าคิดนโยบายขึ้นมาเองในโค้ด

การ hardcode if amount > 50000 { reject } โดยไม่มีเอกสารว่าใครอนุมัติเลข 50,000 คือการเขียนนโยบายบริษัทลงในไฟล์ Go — และเวลา auditor ถามว่า "ใครกำหนดเลขนี้" จะไม่มีคำตอบ ให้ทำ 2 อย่าง: ดึงเลขออกเป็น configuration และบันทึกว่าใครอนุมัติเมื่อไหร่

Design เป็น loop ไม่ใช่ waterfall

Design ที่แย่ส่วนใหญ่มาจากการรับ requirement ที่ไม่เคยเป็นเรื่องจริงมาตั้งแต่ต้น การประมาณตัวเลขเร็วๆ คือวิธี push back ด้วยหลักฐานแทนที่จะเถียงด้วยความเห็น

ตัวอย่างที่เกิดบ่อย: business บอกว่า "วันแรกจะมีผู้ใช้ 1 ล้านคน" คุณคำนวณ 10 นาทีแล้วพบว่าถ้าเป็นจริงต้องมี 40 node กับ Kafka cluster พอเอาตัวเลขไปคุย ปรากฏว่าตัวเลขจริงคือ 20,000 คนในไตรมาสแรก — design ทั้งหมดเปลี่ยน และคุณประหยัดงบไปหลายแสนต่อเดือน

จุดที่ควรวน loop ให้เร็วที่สุด

วน requirements → estimate ให้จบก่อนเริ่มวาด box ใดๆ การวาด architecture ทำให้คนในห้องรู้สึกว่าตกลงกันแล้ว ทั้งที่ยังไม่มีใครรู้ว่าระบบต้องรับโหลดเท่าไหร่

สิ่งที่ system design ไม่ใช่

ไม่ใช่เพราะ
การเลือก tech stackstack เป็นผลลัพธ์ของ requirement ไม่ใช่จุดเริ่ม
การวาด box กับลูกศรให้สวยdiagram คือเครื่องมือสื่อสาร ไม่ใช่ตัว design (บทที่ 20)
การ copy สถาปัตยกรรมของบริษัทใหญ่บริษัทเหล่านั้นมี constraint ต่างจากคุณสิ้นเชิง
การหาคำตอบที่ "ถูกที่สุด"มีแต่คำตอบที่เหมาะกับ constraint ชุดนี้ ณ เวลานี้
งานที่ทำครั้งเดียวจบระบบเปลี่ยน โหลดเปลี่ยน ทีมเปลี่ยน — design ต้องถูกทบทวน

Resume-driven design

อาการ: เลือกเทคโนโลยีเพราะอยากใช้ ไม่ใช่เพราะปัญหาต้องการ วิธีตรวจตัวเอง — ตอบคำถามนี้ให้ได้ว่า "ถ้าไม่ใช้ของนี้ อะไรจะพัง และพังเมื่อโหลดเท่าไหร่" ถ้าตอบไม่ได้ คุณยังไม่มีเหตุผลที่จะใช้มัน (รายการ anti-pattern ทั้งชุดอยู่ในบทที่ 17)

Lab 1 — ทดสอบ design ที่คุณมีอยู่

หยิบระบบที่คุณดูแลอยู่จริง 1 ตัว แล้วทำ 3 อย่าง (ใช้เวลาประมาณ 20 นาที):

  1. เขียน three-sentence test — มันทำอะไร / อยู่รอดได้ยังไง / ยอมเสียอะไร ถ้าประโยคที่ 3 เขียนไม่ออก แปลว่าไม่มีใครเคยตัดสินใจเรื่องนั้นอย่างตั้งใจ
  2. ลิสต์ quality attribute ที่มีตัวเลขจริง — เทียบกับตารางด้านบน ช่องไหนว่างคือความเสี่ยงที่ยังไม่ถูกวัด
  3. หา "คำตอบแบบที่ 4" ที่ซ่อนอยู่ในโค้ด — ค่า threshold, retention, limit ที่ไม่มีเอกสารว่าใครอนุมัติ เขียนรายการนี้ไว้ แล้วเอาไปคุยกับเจ้าของเรื่อง

สรุปบทนี้

System design คือการเลือกโครงสร้างให้ quality attribute เป็นจริงภายใต้ constraint แล้วอธิบายได้ว่าแลกอะไรไป — ตัวเลขมาก่อนกล่อง, constraint มาก่อนเทคโนโลยี, และเรื่องที่มีเจ้าของอื่นต้อง escalate ไม่ใช่ตัดสินเองในโค้ด บทถัดไป คือตัวเลขที่ต้องจำเพื่อทำ loop นี้ให้เร็วพอใช้งานในห้องประชุม