บทที่ 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

แยก:

ElementCandidate
IntentConfirm Transfer
Factscustomer, beneficiary, Money, policy decision, funds state
Decisionsconfirm ได้ไหม, reserve ได้ไหม, execution outcome รู้อะไร
State changesDraft → Confirmed; Attempt → Indeterminate
Invariantintent เดียวไม่สร้าง accepted execution effect ซ้ำ
Unknownprovider 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:

  1. expert เล่า command และ expected fact
  2. developer ใช้ model language อธิบาย decision
  3. expert ให้ counterexample
  4. ทีมแก้ language/model/example
  5. บันทึกสิ่งที่ 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

อ่านเพิ่มเติม