บทที่ 22 · Part 4 — Model Behavior in Code
Domain Events without Event Hype
แยก business fact, internal Domain Event, Integration Event, audit record และ Event Sourcing ออกจากกัน
Domain Events without Event Hype
ทีมหนึ่ง publish event ทุกครั้งที่ column เปลี่ยนและเรียกระบบว่า event-driven แต่ consumers ต้องรู้ database semantics และเรียง events เอง อีกทีมใช้ EventStorming แล้วสรุปว่าต้อง Event Sourcing Domain Event ใน DDD คือ fact ที่มีความหมายต่อ domain ไม่ใช่ชื่อเดียวกับ broker message หรือ source of record
จบบทนี้คุณจะ
แยก Domain Event, Integration Event, Event Notification, audit record และ Event Sourcing ออกแบบ event จาก business meaning/authority รู้ว่า internal event อาจไม่ออกนอก process และแปล public contract หลัง transaction อย่างปลอดภัย
Domain Event
Domain Event ของ Martin Fowler อธิบายสิ่งที่ เกิดและมีความหมายต่อ domain:
type TransferIntentConfirmed struct {
IntentID string
Amount Money
Terms TermsVersion
At time.Time
}
ชื่อ past tense และเป็น fact ที่ model รับรอง ไม่ใช่ TransferRowUpdated
Domain Event ใช้ภายใน Aggregate/application เพื่อ decouple reactions ได้โดยไม่ต้องมี broker
Integration Event
Integration Event เป็น Published Language ที่ contexts อื่นพึ่งพา ต้องมี:
- producer authority
- stable schema/identity/causation
- minimum necessary data/privacy
- version/deprecation
- delivery/duplicate/order expectations
- consumer recovery semantics
อย่า serialize internal Domain Event ตรง ๆ เพราะ model ภายในต้อง evolve และ data อาจรั่ว
5 สิ่งที่มักเรียก Event
| สิ่ง | Purpose |
|---|---|
| Domain Event | business fact ภายใน model/context |
| Integration Event | public fact contract ข้าม context |
| Event Notification | บอกให้ consumer ไป query รายละเอียด |
| Audit Record | evidence ว่าใครทำอะไรภายใต้ control |
| Event-sourced Event | source-of-record transition ที่ต้อง replay/evolve |
Fowler: What do you mean by Event-Driven? เตือนว่าคำ event-driven ครอบหลาย patterns ที่ trade-off ต่างกัน
Event Authority
TransferCompleted เป็นชื่ออันตรายถ้าไม่มี context qualifier Payment Execution อาจ publish
ExecutionOutcomeEstablished ส่วน Ledger publish EntriesPosted และ Customer Journey ตัดสิน
เมื่อใดจะแสดง complete จาก facts เหล่านั้นตาม policy
Event ไม่โอน Authority โดยอัตโนมัติ
Consumer รับ fact ตาม contract แต่ต้องตัดสิน rule ของ context ตนเอง Portal ห้ามใช้ event/cache อนุมัติเงินหาก authority อยู่ Funds Context
Transaction และ Outbox
ถ้า local state save สำเร็จแต่ publish ล้ม event หาย Transactional Outbox บันทึก state+outbox ใน transaction เดียวแล้ว relay ภายหลัง Relay อาจส่งซ้ำ consumer จึง idempotent
Internal Domain Event อาจถูกแปลงเป็น Integration Event หลัง commit โดย application/translator
Ordering และ Time
อย่าพึ่ง global order ใช้ aggregate/entity version, occurredAt, producer sequence, causation/correlation ตาม need Callback จาก provider อาจไม่เรียง ให้ consumer query authoritative state หรือรับ transitions แบบ monotonic ตาม contract
EventStorming ไม่เท่ากับ Event Sourcing
Orange notes เป็น discovery grammar หลาย event ไม่ต้องถูก persisted/published Event Sourcing เลือกเมื่อ history/reconstruction/temporal value คุ้ม operational cost ซึ่งเรียนบท 27
แบบฝึกปฏิบัติ: Event Classification
จำแนก:
Transfer Confirmed
Risk Decision Stored
Provider Callback Received
Execution Outcome Established
Ledger Row Inserted
Entries Posted
Customer Screen Refreshed
Reconciliation Case Closed
ระบุ domain/integration/audit/technical, authority, public name, data, ordering, duplicate handling และเหตุผลที่บางอันไม่ publish
รายการตรวจสอบ
- Event เป็น business fact past tense
- Producer มี authority ต่อ fact
- Internal กับ integration models แยก
- Contract มี identity/version/delivery semantics
- Audit/log/event sourcing ไม่ถูกปน
- Outbox/consumer duplicate ถูกออกแบบเมื่อข้าม transaction
- EventStorming ไม่บังคับ broker/Event Sourcing
สรุปบทนี้
Domain Event ทำให้สิ่งที่ domain สนใจเป็น first-class fact แต่การเผยแพร่ข้าม context เพิ่ม contract, delivery และ governance Event-driven vocabulary ต้องระบุความหมายให้ชัด มิฉะนั้น row changes จะ กลายเป็น distributed coupling รูปแบบใหม่
อ่านเพิ่มเติม
- Domain Event — Martin Fowler
- What do you mean by Event-Driven?
- Transactional Outbox — Azure guidance