บทที่ 4 · Part 1 — Architecture Starts with the Domain
Bounded Contexts and Ownership
หา language, model, policy และ ownership boundary โดยไม่รีบเท่ากับ microservice หรือ database
Bounded Contexts and Ownership
คำว่า Customer ปรากฏใน Checkout, Billing และ Wallet ทีมจึงสร้าง package กลางชื่อ
customer และตารางเดียวเพื่อ “ไม่ duplicate” ไม่นาน field status มี 3 ความหมาย
Checkout ต้องการ buyer contact, Billing ต้องการ legal/tax profile ส่วน Wallet ต้องการ
account eligibility การแก้ model กลางครั้งเดียวทำให้ 3 ทีม deploy พร้อมกัน
จบบทนี้คุณจะ
เสนอ Bounded Context จาก language, model, invariant, lifecycle, data และ ownership อธิบายว่า context ไม่เท่ากับ microservice และใช้ Context Map กับ Anti-Corruption Layer เพื่อออกแบบความสัมพันธ์ระหว่าง Customer, Payment และ Balance models
[!IMPORTANT] วิธีอ่านหลักฐานในบทนี้ คำที่เป็น Definition/Pattern มีแหล่งต้นทางอยู่ใกล้ claim ส่วน decision table, starting structure, checklist และ lab เป็น Heuristic/Trade-off หรือ Course Convention สำหรับฝึกตัดสินใจ ไม่ใช่มาตรฐานสากล เว้นแต่บทจะระบุแหล่งและขอบเขตไว้ชัดเจน
ขอบเขตของความหมาย
DDD Reference นิยาม Bounded Context เป็นขอบเขตที่ model หนึ่งมีความหมายสอดคล้องกัน ภายใน boundary ทีมต้องรู้ว่า term, rule และ lifecycle ใช้แบบใด ภายนอก boundary คำที่สะกดเหมือนกันไม่จำเป็นต้องเป็น object เดียว
ให้ค้นหาหลักฐาน 5 กลุ่ม:
- Language — คำเดียวมี definition หรือ statement ต่างกันหรือไม่
- Invariant — กฎใดต้องถูกบังคับพร้อมกันและใครมีอำนาจตัดสิน
- Lifecycle — object เกิด เปลี่ยน และสิ้นสุดด้วยเหตุการณ์ชุดเดียวกันหรือไม่
- Ownership — ทีมและ business owner ใดตอบคำถามและรับ incident
- Change pattern — requirement เปลี่ยนร่วมกันหรือทำให้หลายส่วน deploy พร้อมกันเสมอ
Boundary เป็น hypothesis จนผ่าน scenario หลายแบบ อย่าใช้ org chart เพียงอย่างเดียว เพราะทีมอาจถูกจัดตาม technology และอย่าใช้ database schema เป็นคำตอบ เพราะ schema อาจสะท้อน legacy coupling มากกว่า domain
คำเดียว หลาย Model
เปรียบเทียบ Customer 3 บริบท:
| Context | Model สนใจ | ไม่ควรเป็นเจ้าของ |
|---|---|---|
| Checkout | buyer contact, session relationship, consent snapshot | tax registration lifecycle |
| Billing | billing profile, invoice address, tax identity | Wallet account restriction |
| Wallet | account holder reference, eligibility, account state | invoice delivery preference |
แต่ละ context เก็บ reference หรือ snapshot ที่จำเป็นต่อ decision ของตนได้ โดยต้องระบุ source, freshness และ correction policy การคัดลอก field ไม่เท่ากับ duplicate business logic หาก model มีความหมายและ lifecycle ต่างกัน
Balance ยิ่งต้องระวัง Wallet อาจเป็นเจ้าของ ledger-derived posted/available balance
ขณะที่ Portal มี read model สำหรับ display การเรียกทั้งคู่ว่า Balance ไม่ทำให้ Portal
มีสิทธิ์อนุมัติ transfer จาก cache ของตน
Decision ต้องกลับไปหา owning context
การอนุมัติ Transfer หรือ Refund ต้องให้ context เจ้าของ authoritative state ตรวจ invariant ณ transaction/concurrency boundary ที่เหมาะสม Snapshot และ read model ใช้แสดงผลหรือเตรียมข้อมูลได้ แต่ห้ามกลายเป็นผู้ตัดสินเงินโดยไม่มี contract ชัด
Bounded Context ไม่ใช่ Deployment Unit
Bounded Context เป็น semantic/model boundary ส่วน module, process, service, repository และ database เป็น implementation/deployment decisions Context 2 อันอาจเริ่มใน modular monolith เดียวโดยมี package/API boundary ชัด ขณะเดียวกัน service หนึ่งที่รวมหลาย model โดยไม่มี language boundary ไม่ได้กลายเป็น context เพียงเพราะ deploy แยก
Microservice Trade-Offs เตือนถึงต้นทุน distribution เช่น remote call, operational complexity และ eventual consistency ดังนั้นคำถาม “ควรแยก service ไหม” ต้องตามหลังคำถาม “model และ ownership แยกหรือยัง”
ใช้ตารางนี้ป้องกันการปนระดับ:
| Decision | ตัวอย่าง | เปลี่ยนแยกได้หรือไม่ |
|---|---|---|
| Model boundary | Payment Attempt กับ Wallet Entry | ได้ |
| Code module | checkout, wallet packages | ได้ |
| Runtime process | binary เดียวหรือหลาย service | ได้ |
| Data deployment | schema/database เดียวหรือแยก | ได้ แต่ ownership ต้องชัด |
| Team ownership | Payments, Wallet teams | ได้ตามองค์กร |
ทำ Context Map ของความสัมพันธ์
Context Map ไม่ได้มีแค่กล่องและลูกศร ต้องบอก power, contract และ translation รูปแบบจาก Evans เช่น Customer/Supplier, Conformist, Published Language และ Anti-Corruption Layer ช่วยตั้งคำถามว่าฝ่ายใดกำหนด model
ตัวอย่าง Checkout เรียก Payment Integration:
ACL มีหน้าที่แปล vendor lifecycle, identifier และ error ให้เป็นภาษาที่ Checkout เป็นเจ้าของ มันอาจเป็น adapter ใน process เดียว ไม่จำเป็นต้องเป็น service แยก และไม่ควรแอบเป็นเจ้าของ refund policy ซึ่งอยู่ใน domain อื่น
สำหรับ integration แต่ละเส้น บันทึก:
- Upstream/downstream และ accountable owners
- Published command/event/query contract
- Identifier/correlation rule
- Translation และข้อมูลที่ตั้งใจไม่เผย
- Freshness, consistency และ failure expectation
- Versioning/deprecation policy
แบบฝึกปฏิบัติ: ท้าทายสมมติฐาน 3 Boundary
เริ่มจาก candidate contexts Customer, Payment, Wallet แล้วกรอกตาราง:
Candidate boundary:
Language and example statements:
Owned invariants:
Lifecycle:
Authoritative data:
Team / business policy owner:
Public contracts:
Dependencies and relationship pattern:
Counterexample that might merge or split it:
Deployment decision today:
จากนั้นทดสอบด้วย 2 scenario: customer เปลี่ยน legal name หลัง invoice ถูกออก และ payment confirmed แต่ Wallet credit ยังไม่เกิด หาก boundary อธิบายไม่ได้ว่าใครเก็บ historical snapshot ใครแก้ state และใคร reconcile แสดงว่ายังเป็นเพียงชื่อกล่อง
คะแนนแบบฝึกหัด:
- ผ่าน เมื่อทุก boundary มี language/invariant/owner มากกว่ารายชื่อตาราง
- ดี เมื่อ relationship มี contract, translation และ failure responsibility
- ควรทำใหม่ เมื่อกล่องทุกใบเท่ากับ service/team/database โดยไม่มี semantic evidence
รายการตรวจสอบ
- Boundary มี model และ language ที่สอดคล้องภายใน
- Shared term ถูกตรวจความหมาย ไม่แชร์ struct โดยอัตโนมัติ
- Invariant และ authoritative data มี owner เดียวที่ชัด
- Integration ระบุ contract และ translation
- Bounded Context ถูกแยกจาก module/service/database decision
- Boundary hypothesis ถูกท้าด้วย failure และ historical scenarios
สรุปบทนี้
Bounded Context ปกป้องความหมายของ model ไม่ใช่บังคับ topology เมื่อ boundary ชัด เราสามารถเริ่มด้วย module ใน process เดียวแล้วเลือก deployment ตาม scale, failure isolation และทีมภายหลัง Context Map ทำให้ความสัมพันธ์และ translation เป็นข้อตกลงที่ review ได้
อ่านเพิ่มเติม
- DDD Reference — Bounded Context, Context Map และ Anti-Corruption Layer
- Implementing Domain-Driven Design — strategic design และ context integration
- Microservice Trade-Offs — เหตุผลที่ deployment boundary มีต้นทุนอีกชุดหนึ่ง