บทที่ 28 · Part 5 — From Model to Running System
Event Sourcing Selectively
ประเมิน history, temporal query และ audit value เทียบกับ schema evolution, projection และ operational cost
Event Sourcing Selectively
เพราะ domain มี events ไม่ได้แปลว่าต้องใช้ Event Sourcing Pattern นี้เก็บ event sequence เป็น source of record และ derive current state จึงให้ temporal/history power แต่เพิ่ม schema evolution, projection, replay, privacy และ operational complexity เลือกเฉพาะ context/aggregate ที่ value ชนะ cost
จบบทนี้คุณจะ
แยก Event Sourcing จาก Domain/Integration Events ประเมิน temporal/audit/reconstruction value ออกแบบ event stream, optimistic concurrency, projections, upcasting/migration และ correction พร้อมอธิบายเมื่อ CRUD state + audit log ง่ายกว่า
Pattern คืออะไร
Azure Event Sourcing Pattern อธิบายการ append events ที่อธิบาย state changes และ rebuild state โดย replay Current state ไม่ใช่ source หลัก
TransferIntentOpened
BeneficiarySelected
TransferIntentConfirmed
CancellationRequested
TransferIntentCancelled
events ต้องเป็น durable facts สำหรับ stream ไม่ใช่ทุก technical notification
ภาพนี้แยก 2 path: command replay stream เพื่อใช้ authoritative model ตัดสิน ส่วน query อ่าน projection ที่ rebuild ได้ การมี event bus หรือ integration events ยังเป็นอีก concern ไม่ได้เกิดฟรี
Value Hypotheses
Event Sourcing อาจคุ้มเมื่อ:
- ต้องตอบ state ณ เวลา/decision ย้อนหลัง
- business ให้ value กับ complete change history
- rules เปลี่ยนและต้อง recompute projections
- event stream เป็น natural model ของ domain
- audit/explainability requirement ได้รับการยืนยัน
ไม่ควรเลือกเพียงเพราะ “ Fintech ต้อง audit” Audit record ที่ immutable แยกอาจพอ และ compliance owner ต้องกำหนด evidence/retention/access จริง
Costs
- event schema immutable-like และ evolution ยาก
- replay code ทุก version ต้องถูก
- projections lag/rebuild/monitoring
- event store operations/backup
- deletion/privacy conflicts
- debugging temporal behavior
- team skill/tooling/on-call
- integration events ยังแยกจาก internal stream
Stream Boundary และ Concurrency
มัก stream ต่อ Aggregate ID ใช้ expected version เพื่อ optimistic concurrency:
append events to stream transfer-intent/T-104 expectedVersion=7
conflict ต้องกลับ domain semantics ไม่ blind merge
Event Design
Events past tense, capture fact/context พอ replay และไม่ผูก UI/vendor DTO:
{
"type": "transfer-intent-confirmed.v2",
"intentId": "T-104",
"amountMinor": 150000,
"currency": "THB",
"termsVersion": "terms-2026-08",
"occurredAt": "2026-08-11T10:04:00Z"
}
ค่าคือ scenario illustrative ไม่ใช่ policy
Evolution
ทางเลือก:
- upcast old event on read
- transform/migrate stream อย่างควบคุม
- support multiple handlers
- add corrective event แทน rewrite history
- snapshot เพื่อ performance แต่ stream ยัง authority
ต้องมี test fixtures historical และ rebuild rehearsal
Immutable ไม่ได้แปลว่าเก็บได้ตลอด
Personal/sensitive data retention, deletion, encryption/key destruction และ access ต้องมาจาก accountable privacy/compliance/security owners พร้อม jurisdiction/version/date Event Sourcing ไม่ทำให้ compliant อัตโนมัติ
Projection และ Decision
Projection สำหรับ query/display อาจ eventual อย่าใช้ stale projection ตัดสิน invariant หาก Aggregate replay authoritative stream เพื่อ command หรือมี consistency strategy ชัด
Event Sourcing vs Audit Log
| Need | Simpler option | Event Sourcing |
|---|---|---|
| ใครแก้ record | audit log | อาจเกินจำเป็น |
| current CRUD state | table | ไม่คุ้มโดย default |
| rebuild state at any time | hard | strong fit |
| temporal business model | awkward | potential fit |
| external event integration | outbox | separate concern |
แบบฝึกปฏิบัติ: Decision Record
ประเมิน Transfer Intent, Payment Execution, Ledger, Customer Profile, Notification:
Temporal/history need:
Alternative (state + audit):
Stream boundary:
Event examples:
Schema/privacy evolution:
Projection/rebuild operations:
Team capability:
Decision / rejected alternative / review trigger:
เลือกอย่างมาก 1 candidate และอธิบายว่าทำไมส่วนอื่นไม่ใช้
รายการตรวจสอบ
- ES แยกจาก Domain/Integration Event
- Value hypothesis มี owner/requirement
- Stream boundary/concurrency ชัด
- Events เป็น durable domain facts
- Schema evolution/replay tested
- Privacy/retention มี authority
- Projection ไม่ใช้ authoritative decision โดยเงียบ
- Simpler alternative ถูกเปรียบเทียบ
สรุปบทนี้
Event Sourcing เป็น persistence/model pattern ที่ทรงพลังเมื่อ temporal history/reconstruction เป็น core need แต่มี lifetime operational cost สูง DDD ไม่ได้บังคับใช้ เลือกแคบ ทดลอง replay/evolution และยอมใช้ state+audit เมื่อพอ
อ่านเพิ่มเติม
- Event Sourcing Pattern — Azure
- What do you mean by Event-Driven?
- DDD Reference — Domain Event แยกจาก Event Sourcing