บทที่ 17 · Part 4 — Model Behavior in Code
From Scenario to Model
เปลี่ยน examples เป็น behavior, state transition, invariant และ model alternatives ที่พิสูจน์ด้วย tests ได้
From Scenario to Model
หลัง discovery ทีมมี events และ glossary มากมาย แต่การสร้าง class ตาม sticky ทุกใบทำให้ได้ data model ที่ไม่มี behavior ขั้น Tactical Modeling เริ่มจาก scenario และ question ว่า model ต้องตัดสินอะไร แล้วเสนอ concepts/relationships ที่ทำให้ rules กับ invalid states มองเห็น
จบบทนี้คุณจะ
เปลี่ยน scenario เป็น state, behavior, rule และ invariant candidates เสนอ model alternatives ใช้ executable examples เป็น feedback และเลือก Aggregate/Entity/Value Object ภายหลังแทนการ map noun ทุกคำเป็น class
เริ่มจาก Decision Slice
Scenario:
Customer confirms Transfer Intent จำนวน 150,000 สตางค์ใน THB ระบบต้องยืนยัน beneficiary, ตรวจ policy version ที่รับผิดชอบ และ reserve funds ก่อนส่ง provider หาก provider timeout execution ต้องเป็น indeterminate และเข้าสู่ reconciliation
แยก:
| Element | Candidate |
|---|---|
| Intent | Confirm Transfer |
| Facts | customer, beneficiary, Money, policy decision, funds state |
| Decisions | confirm ได้ไหม, reserve ได้ไหม, execution outcome รู้อะไร |
| State changes | Draft → Confirmed; Attempt → Indeterminate |
| Invariant | intent เดียวไม่สร้าง accepted execution effect ซ้ำ |
| Unknown | provider timeout ไม่เท่ากับ failed |
จำนวนเป็น scenario input illustrative ไม่ใช่ policy threshold
จาก Example ไป Behavior
เขียน examples ก่อน type tree:
Given a Draft Transfer Intent with a valid Beneficiary and Money
When the Customer confirms it
Then it becomes Confirmed once
And records which terms/policy references were used
Given an Execution Attempt with no authoritative outcome after timeout
When timeout is observed
Then outcome becomes Indeterminate
And blind retry with a new business identity is forbidden
ถามว่า object ใดควรรับ message/behavior เพื่อรักษา invariant ไม่ถามว่า table ใดมี columns เหล่านี้
Model Alternatives
One Transfer Model
รวม intent, risk, funds, execution เหมาะกับ simple business แต่ state combinations มากและปน authority
Intent + Attempt
แยก customer lifecycle จาก provider attempts ทำ retry/unknown ชัด แต่ต้องนิยาม relationship และ process ที่ coordinate
Context-specific Models
Transfer context ถือ Intent, Payment Execution ถือ Attempt, Funds context ถือ Reservation semantic ชัดแต่ cross-context consistency/recovery มีต้นทุน
เลือกผ่าน examples, change pattern, authority และ failure— not จากความชอบ object design
Model Probe ใน Code
type TransferIntent struct {
id string
status IntentStatus
beneficiary Beneficiary
amount Money
}
func (t *TransferIntent) Confirm() error {
if t.status != IntentDraft {
return ErrIntentNotDraft
}
t.status = IntentConfirmed
return nil
}
Code เล็กนี้เปิดคำถาม: policy/risk/funds อยู่ตรงไหน Confirm หมายถึง customer commitment หรือพร้อม execute ถ้าความหมายหลังยังไม่ชัด อย่าเพิ่ม parameters จน method รับทุก context ให้กลับไป language
State Machine เป็นเครื่องมือ ไม่ใช่ Model ทั้งหมด
State diagram ช่วยหา transition แต่ domain behavior ยังรวม:
- identity และ causation
- Money/currency value
- policy version/evidence
- actor/authorization
- time/expiry
- cross-context facts
อย่าสร้าง enum กลาง 20 ค่าให้ทุก context conform
ภาพนี้เป็น state hypothesis ของ Transfer Intent ไม่ใช่ status enum กลางของ Risk, Provider,
Ledger และ Portal ทุก transition ยังต้องถาม actor, command, evidence, policy version และ invariant
Invariant Candidate
เขียนรูป:
Within [boundary], after [command], [condition] must always hold.
ตัวอย่าง:
Within Transfer Intent, after Confirm, beneficiary and Money cannot be replaced silently.
Within Payment Execution, one provider idempotency identity cannot represent different parameters.
จากนั้นถาม concurrency/persistence evidence ในบท Aggregate/transaction ภายหลัง
Domain Test ไม่ยืนยัน Policy Authority
Test ทำให้ rule executable แต่ค่าจริงของ transfer limit, KYC หรือ approval ต้องมาจาก owner/source/date อย่าทำ fixture illustrative ให้กลายเป็น production policy
Model Review ด้วย Domain Expert
อย่า review class diagram อย่างเดียว ให้เล่น scenario:
- expert เล่า command และ expected fact
- developer ใช้ model language อธิบาย decision
- expert ให้ counterexample
- ทีมแก้ language/model/example
- บันทึกสิ่งที่ model ไม่รับผิดชอบ
ถ้า expert ต้องแปลชื่อ code ทุกประโยค Ubiquitous Language ยังไม่ถึง model
แบบฝึกปฏิบัติ: Transfer Modeling Notebook
ส่ง:
- scenarios 3 เรื่อง
- rules/questions จาก Example Mapping
- model alternatives 3 แบบ
- state transitions พร้อมคำที่ไม่ใช้ร่วม
- invariant candidates 4 ข้อ
- Go probe เล็ก 1 ชิ้นและสิ่งที่มันเปิดเผย
- choice ตอนนี้ + rejected alternatives + review trigger
รายการตรวจสอบ
- เริ่มจาก decision slice ไม่ใช่ entity list
- examples แยก known/unknown outcome
- มี model alternatives
- state machine ไม่ปน authorities
- invariant ระบุ boundary/command/condition
- code เป็น modelling feedback
- Domain Expert review ผ่าน scenario
สรุปบทนี้
Tactical Modeling แปลง scenario เป็น behavior และ invariants ผ่านหลาย model alternatives Pattern names ตามมาหลังเข้าใจ force Code/example ทำหน้าที่ทดสอบ theory และส่ง contradiction กลับ discovery loop
อ่านเพิ่มเติม
- DDD Reference — Model-Driven Design และ building blocks
- The Whirlpool — scenario/model/code feedback
- Aggregate Design Canvas — decision/invariant exploration