ข้าม​ไป​ยัง​เนื้อหา

Laws of Software Architecture

ทุก​อย่าง​คือ​การ​แลกเปลี่ยน · ทำไม​สำคัญ​กว่า​อย่างไร

สถาปัตยกรรม​ซอฟต์แวร์​เป็น​สาขา​ที่​กว้าง​มาก​จน​ดูเหมือน​ไม่มี​กฎ​ตายตัว แต่ Neal Ford และ Mark Richards ผู้​เขียน Fundamentals of Software Architecture และ Software Architecture: The Hard Parts ได้​กลั่น​ประสบการณ์​การ​เป็น​สถาปนิก​มา​หลาย​สิบ​ปี​ให้​เหลือ​กฎ​พื้นฐาน​เพียง​สอง​ข้อ ที่​พวก​เขา​เรียก​ตรง ๆ ว่า “กฎ” (Laws) เพราะ​เชื่อ​ว่า​มัน​เป็น​จริง​แทบ​จะ​ไม่มี​ข้อ​ยกเว้น

กฎ​ข้อ​ที่​หนึ่ง (First Law): ทุก​อย่าง​ใน​สถาปัตยกรรม​ซอฟต์แวร์​คือ​การ​แลกเปลี่ยน (Everything in software architecture is a trade-off)

หาก​สถาปนิก​คิด​ว่า​ค้น​พบ​สิ่ง​ที่​ไม่ใช่​การ​แลกเปลี่ยน แปล​ว่า​เขา​ยัง ไม่​พบ การ​แลกเปลี่ยน​นั้น​ต่างหาก มัน​มี​อยู่​เสมอ อย่าง​น้อย​ก็​ใน​รูป opportunity cost เพราะ​การ​เลือก​ใช้​สิ่ง​หนึ่ง​ย่อม​หมาย​ถึง​การ​เลือก​ไม่​ใช้​ทาง​เลือก​อื่น​ไป​โดย​ปริยาย

กฎ​ข้อ​ที่​สอง (Second Law): “ทำไม” สำคัญ​กว่า “อย่างไร” (Why is more important than how)

มี​หลาย​วิธี​ที่​จะ implement สถาปัตยกรรม​หนึ่ง ๆ ให้​สำเร็จ และ​รายละเอียด​การ implement ก็​สำคัญ​ไม่​น้อย แต่​สิ่ง​ที่​สำคัญ​กว่า​จาก​มุม​ของ​สถาปนิก​คือ​เหตุผล​เบื้องหลัง​ว่า ทำไม จึง​เลือก​แนวทาง​นั้น​เหนือ​ทาง​เลือก​อื่น เพราะ​บริบท ข้อ​จำกัด และ​เป้าหมาย​ทาง​ธุรกิจ​เปลี่ยน​ไป​ตาม​กาล​เวลา คน​ที่มา​ทีหลัง​ต้อง​เข้าใจ​เหตุผล​เดิม​ก่อน​จะ​แก้ไข​หรือ​รื้อ​สถาปัตยกรรม​นั้น

กฎ​ทั้ง​สอง​ข้อ​นี้​ทำงาน​เสริม​กัน ไม่ใช่​แยก​จาก​กัน กฎ​ข้อ​แรก​บอกว่า “ไม่มี​สถาปัตยกรรม​ที่​ดี​ที่สุด” มี​แต่​ชุด​ของ​การ​แลกเปลี่ยน​ที่​เหมาะ​กับ​บริบท​หนึ่ง ๆ Richards และ Ford ใช้​คำ​ว่า least worst architecture เพื่อ​สื่อ​ว่า​เป้าหมาย​ของ​สถาปนิก​ไม่ใช่​การ​ไล่​หา​คำ​ตอบ​ที่​สมบูรณ์​แบบ (ซึ่ง​ไม่มี​อยู่​จริง) แต่​คือ​การ​เลือก​ชุด​ของ​ข้อ​เสีย​ที่​ยอมรับ​ได้​มาก​ที่สุด​สำหรับ​ทีม งบประมาณ กำหนด​เวลา หนี้​ทาง​เทคนิค​ที่​มี​อยู่ และ​เป้าหมาย​ทาง​ธุรกิจ​ของ​ตน

ตัวอย่าง​คลาสสิก​ของ​การ​แลกเปลี่ยน เช่น การ​เพิ่ม​ความ​ปลอดภัย (เข้า​รหัส ตรวจสอบ​สิทธิ์​เพิ่ม​ชั้น) มัก​แลก​มา​ด้วย​ประสิทธิภาพ​ที่​ลด​ลง หรือ​การ​ออกแบบ​เพื่อ scalability สูง​มัก​เพิ่ม​ความ​ซับซ้อน​ใน​การ​ปฏิบัติ​งาน (operational complexity) และ​ต้นทุน​ที่​สูง​ขึ้น ไม่มี​ทาง​เลือก​ใด​ที่ “ได้​ทุก​อย่าง​โดย​ไม่​เสีย​อะไร” — นี่​คือ​เหตุผล​ที่​คำ​ตอบ​ยอด​ฮิต​ของ​คำถาม​ด้าน​สถาปัตยกรรม​เกือบ​ทุก​ข้อ​คือ “it depends”

กฎ​ข้อ​ที่​สอง​ขยาย​ผล​จาก​ข้อ​แรก เมื่อ​ทุก​การ​ตัดสิน​ใจ​คือ​การ​แลกเปลี่ยน สิ่ง​ที่​ทีม​ใน​อนาคต​ต้อง​รู้​ไม่ใช่​แค่ สิ่ง​ที่ ถูก​สร้าง​ขึ้น​มา แต่​คือ เหตุผล ที่​นำ​ไป​สู่​การ​เลือก​นั้น มิ​เช่น​นั้น​ทีม​จะ​ติด​อยู่​ใน​สิ่ง​ที่ Ford และ Richards เรียก​ว่า “Groundhog Day” anti-pattern คือ​การ​หยิบยก​การ​ตัดสิน​ใจ​เดิม​ขึ้น​มา​ถกเถียง​ซ้ำ​แล้ว​ซ้ำ​เล่า​เพราะ​ไม่มี​ใคร​จำ​ได้ (หรือ​ไม่​เคย​รู้) ว่า​ทำไม​จึง​ตัดสิน​ใจ​อย่าง​นั้น เครื่องมือ​ที่​ตอบ​โจทย์​นี้​โดยตรง​คือ Architecture Decision Records (ADR) ซึ่ง Michael Nygard เสนอ​ไว้​ตั้งแต่​ปี 2011 — เอกสาร​สั้น ๆ ที่​บันทึก บริบท (context), การ​ตัดสิน​ใจ (decision), และ​ผล​ที่​ตาม​มา (consequences) เก็บ​ไว้​ใน source control ใกล้​กับ code ที่​ได้​รับ​ผลกระทบ Martin Fowler อธิบาย​เสริม​ว่า​คุณค่า​ของ ADR ไม่​ได้​อยู่​แค่​ที่​การ​เก็บ​ประวัติ​ไว้​ให้​คน​รุ่น​หลัง​อ่าน แต่​อยู่​ที่ กระบวนการ​เขียน เอง​ก็​ช่วย​บีบ​ให้​ความคิด​ของ​ทีม​ชัดเจน​ขึ้น และ​มัก​เผย​ให้​เห็น​มุมมอง​ที่​ต่าง​กัน​ตั้งแต่​ก่อน​ลงมือ​ทำ

ทั้ง​สอง​กฎ​ยัง​เตือน​สถาปนิก​ให้​ระวัง​กับดัก​สอง​แบบ: (1) การ​ไล่​หา​สถาปัตยกรรม​ใน​อุดมคติ​ที่​ไม่มี​ข้อ​เสีย ซึ่ง​นำ​ไป​สู่ analysis paralysis และ (2) การ​ใช้ pattern หรือ tool หนึ่ง​กับ​ทุก​ปัญหา​โดย​ไม่​ทบทวน​บริบท ซึ่ง​คือ Golden Hammer anti-pattern

  • Microservices เทียบ​กับ Monolith — microservices ให้ decoupling และ scalability ระดับ​บริการ​สูง แต่​แลก​มา​ด้วย​ความ​ซับซ้อน​ของ​ระบบ​กระจาย (network latency, distributed transaction, observability ที่​ต้อง​ลงทุน​เพิ่ม) ส่วน monolith ให้​ความ​เรียบ​ง่าย​ใน​การ deploy และ debug แต่​แลก​มา​ด้วย​ข้อ​จำกัด​เรื่อง scaling แยก​ส่วน​และ blast radius ที่​กว้าง​กว่า​เมื่อ​เกิด bug
  • Event-driven architecture — ให้​ความ​สามารถ scale และ decouple ระหว่าง​บริการ​ได้​ดี​เยี่ยม แต่​แลก​มา​ด้วย​ความ​ยาก​ใน​การ debug workflow แบบ end-to-end และ​การ​จัดการ error handling / eventual consistency
  • CQRS (ดู CQRS) คือ​ตัวอย่าง​รูปธรรม​ของ​กฎ​ข้อ​แรก: การ​แยก model สำหรับ​อ่าน​และ​เขียน​แลก​ความ​เรียบ​ง่าย​ของ CRUD model เดียว​ไป​กับ​ความ​สามารถ​ใน​การ optimize การ​อ่าน​และ​เขียน​แยก​กัน ทีม​ต้อง​รู้ ทำไม จึง​ยอมรับ​ความ​ซับซ้อน​นี้ ไม่ใช่​แค่​รู้ วิธี implement
  • Conway’s Law ใน​ทาง​ปฏิบัติ (ดู Conway’s Law) — เวลา​สถาปนิก​เลือก​ว่า​จะ​แบ่ง​ระบบ​เป็น​กี่​บริการ ก็​มัก​ถูก​จำกัด​โดย​โครงสร้าง​ทีม​ที่​มี​อยู่​จริง การ​ฝืน​เลือก “สถาปัตยกรรม​ที่​ดี​ที่สุด​ใน​ทาง​ทฤษฎี” โดย​ไม่​คำนึง​ถึง​ทีม​ที่​ต้อง​ดูแล​มัน​ใน​ระยะ​ยาว มัก​เป็นการ​แลกเปลี่ยน​ที่​ไม่​คุ้ม
  • ทีม​ที่​นำ ADR มา​ใช้​จริง​ใน​องค์กร (เช่น​แนวทาง​ที่ ThoughtWorks และ​ทีม​วิศวกรรม​จำนวน​มาก​ใช้) รายงาน​ว่าการ​ถกเถียง​ซ้ำ​เรื่อง​เดิม (“ทำไม​เรา​ไม่​ใช้ X แทน”) ลด​ลง​อย่าง​ชัดเจน เพราะ​มี​เอกสาร​อ้างอิง​บริบท​และ​เหตุผล ณ เวลา​ที่​ตัดสิน​ใจ
flowchart LR
  Drivers[Business Drivers] --> Options[Candidate Options]
  Options --> Tradeoff[Tradeoff Analysis]
  Tradeoff --> Choice[Least Worst Option]
  Choice --> ADR[Document Why in ADR]
  • เมื่อ​ถูก​ถาม​ว่า “สถาปัตยกรรม​ไหน​ดี​ที่สุด” ให้​ตอบ​กลับ​ด้วย​คำถาม​ว่า “ดี​ที่สุด​สำหรับ quality attribute ไหน ใน​บริบท​ไหน” แล้ว​ชี้​ให้​เห็น​การ​แลกเปลี่ยน​ที่​ต้อง​เลือก
  • ทุก​ครั้ง​ที่​เลือก​สถาปัตยกรรม​หรือ pattern ให้​ถาม​ตัวเอง​ว่า “เรา​กำลัง​แลก​อะไร​กับ​อะไร” หาก​ตอบ​ไม่​ได้ แปล​ว่า​ยัง​วิเคราะห์​ไม่​ลึก​พอ ไม่ใช่​ว่า​ไม่มี​การ​แลกเปลี่ยน
  • เขียน ADR สั้น ๆ ทุก​ครั้ง​ที่​มี​การ​ตัดสิน​ใจ​สำคัญ โดย​เน้น​ที่ context และ why ให้​ชัด​กว่า​ฝั่ง how เก็บ​ไว้​ใน repository ใกล้ code ที่​เกี่ยวข้อง เพื่อ​ป้องกัน Groundhog Day anti-pattern
  • อย่า​ไล่​ตาม “สถาปัตยกรรม​ที่​สมบูรณ์​แบบ” เป้าหมาย​ที่​เป็น​จริง​คือ least worst architecture ที่​เหมาะ​กับ​ทีม งบ เวลา และ​หนี้​ทาง​เทคนิค​ที่​มี​อยู่​จริง
  • ทบทวน ADR เก่า​เป็น​ระยะ บริบท​ทาง​ธุรกิจ​เปลี่ยน การ​แลกเปลี่ยน​ที่​เคย​คุ้ม​ค่า​อาจ​ไม่​คุ้ม​ค่า​อีก​ต่อ​ไป — แต่​การ supersede ควร​มี​เอกสาร​ใหม่​อ้างอิง​ของ​เก่า ไม่ใช่​แก้​ทับ​ของ​เดิม