ข้าม​ไป​ยัง​เนื้อหา

Process & Design-Level EventStorming

สาม​บท​ที่​ผ่าน​มา​เรา​แปะ Post-it สี​ส้ม​เต็ม​ผนัง​ใน Big Picture EventStormingBig Picture EventStormingเวิร์กช็อป EventStorming รอบ​แรก​และ​กว้าง​ที่สุด เชิญ​คน​จาก​ทุก​ฝ่าย​มาระดม domain event ของ​ทั้ง​สาย​ธุรกิจ​ลง​บน​ไทม์​ไลน์​เดียว เป้าหมาย​คือ​เห็น​ภาพ​รวม ค้น​พบ​รอย​ต่อ​และ​จุด​ที่​ยัง​ไม่รู้ ไม่​เน้น​รายละเอียดProcess จน​เห็น​เรื่องราว​ของธุรกิจฟู้ด​เดลิ​เวอรี​ทั้ง​เส้น — ตั้งแต่ ItemAddedToCart ยาว​ไป​จนถึง OrderRated เรา​ขีด​เส้น​แบ่ง​ช่วง​ด้วย Pivotal EventPivotal Eventdomain event สำคัญ​ที่​แบ่ง​ไทม์​ไลน์​ออก​เป็น​ช่วง ๆ (เช่น OrderPlaced, FoodDelivered) มัก​ขีด​เส้น​แนว​ตั้ง​กำกับ ใช้​เป็น​เบาะแส​ของ​ขอบเขต bounded context ใน​ภายหลังProcess อย่าง OrderPlaced, PaymentCaptured, FoodDelivered และ​เก็บ​คำถาม​ค้าง​คา​ไว้​ใน Post-it สี​แดง (HotspotHotspotจุด​ที่​เป็น​ปัญหา ข้อ​ขัดแย้ง หรือ​คำถาม​ที่​ยัง​ตอบ​ไม่​ได้​ระหว่าง​เวิร์กช็อป แทน​ด้วย Post-it สี​แดง​วาง​เฉียง ๆ เก็บ​ไว้​กลับ​มา​คุย​ทีหลัง​โดย​ไม่​ขัดจังหวะ​การ​ไหล​ของ​กลุ่มProcess) เรียบร้อย

ภาพ​กว้าง​แบบ​นั้น “เห็น​ป่า​ทั้ง​ผืน” แต่​ยัง​เข้าไป​สร้าง​บ้าน​ไม่​ได้ บท​นี้​จะ​ซูม​กล้อง​จาก​ป่า​ลง​มา​ที่​ต้นไม้​ต้น​เดียว — เลือก Bounded ContextBounded Contextขอบเขต​ที่ model และ ubiquitous language หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ใน EventStorming มัก​ค้น​พบ​ขอบเขต​นี้​จาก pivotal event และ​กลุ่ม event ที่​เกาะ​กลุ่ม​กันStrategic Design หนึ่ง (จะ​ใช้ Ordering เป็น​หลัก) แล้ว​ขยาย​จน​ละเอียด​พอที่​โปรแกรมเมอร์​หยิบ​ไป​เขียน code ได้​ทันที เครื่องมือ​ที่​พา​เรา​ไป​ถึง​ตรง​นั้น​มี​สอง​ระดับ​ที่​ต่อ​กัน คือ Process ModelingProcess Modelingระดับ​กลาง​ของ EventStorming ที่​ต่อ​จาก Big Picture — เพิ่ม command, actor, policy และ read model เข้า​มา​เพื่อ​ให้​เห็น “กลไก” ที่​ทำให้​แต่ละ event เกิด​ขึ้น ก่อน​จะ​ลง​ลึก​ระดับ designProcess และ Design-Level EventStormingDesign-Level EventStormingEventStorming รอบ​เจาะ​ลึก​เข้าไป​ใน bounded context เดียว เพื่อ​ออกแบบ​ระดับ​ที่​พร้อม​เขียน code โดย​เรียง​ลำดับ command → aggregate → event และ policy อย่าง​ละเอียดProcess


Big Picture ให้​เรา​แค่ “event เกิด​อะไร​บ้าง เรียง​ยังไง” แต่​ไม่​ได้​บอกว่า event แต่ละ​อัน​เกิด​ขึ้น​ได้​อย่างไร ใคร​สั่ง? สั่ง​เพราะ​เห็น​ข้อมูล​อะไร? มี​กฎ​อะไร​มากระตุ้น​ให้​เกิด event ถัด​ไป​โดย​อัตโนมัติ?

Process Modeling คือ​ระดับ​กลาง​ที่มา​ตอบ​คำถาม​พวก​นี้ วิธี​ทำ​ง่าย​มาก — เดิน​ไป​ที​ละ event แล้ว “เติม​ของ​รอบๆ มัน” เข้าไป จน​เห็น​กลไก:

  • ข้าง​หน้า event มัก​มี CommandCommandความ​ตั้งใจ​หรือ​การ​ตัดสิน​ใจ​ที่ “สั่ง​ให้​เกิด” domain event เขียน​เป็นกริยา​คำ​สั่ง (เช่น PlaceOrder) แทน​ด้วย Post-it สี​ฟ้า มัก​มี actor เป็น​ผู้​ลงมือTactical Design (สี​ฟ้า) ที่​เป็น “ความ​ตั้งใจ​สั่ง​ให้​เกิด” เช่น​ก่อน​จะ​ได้ OrderPlaced ต้อง​มี​คน​สั่ง PlaceOrder
  • ข้าง​หลัง command มัก​มี ActorActorคน/บทบาท​ที่​ออก command (เช่น ลูกค้า ร้าน​อาหาร ไร​เด​อร์) แทน​ด้วย Post-it สี​เหลือง​แผ่น​เล็ก​แปะ​มุม​ของ command ช่วย​ตอบ​ว่า “ใคร​เป็น​คน​ทำ”Process (สี​เหลือง​แผ่น​เล็ก) คือ​คน​ที่​ลงมือ เช่น ลูกค้า ร้าน​อาหาร ไร​เด​อร์
  • ก่อน actor จะ​ตัดสิน​ใจ เขา​มัก​มอง​อะไร​บาง​อย่าง​อยู่ — นั่น​คือ Read ModelRead Modelข้อมูล/หน้า​จอ​ที่​ผู้​ใช้ “อ่าน” เพื่อ​ประกอบ​การ​ตัดสิน​ใจ​ก่อน​ออก command (เช่น ตะกร้า หน้า​ติดตามออเดอร์) แทน​ด้วย Post-it สี​เขียว เชื่อม​โยง​กับ​ฝั่ง Query ของ CQRSTactical Design (สี​เขียว) เช่น​หน้า​ตะกร้า (Cart) ที่​ให้​เห็น​ยอด​รวม​ก่อน​กด​สั่ง
  • บาง event ไม่​ได้​เกิด​จาก​คน แต่​เกิด​จาก​กฎ​อัตโนมัติ — PolicyPolicyกฎ​เชิง​ปฏิกิริยา​แบบ “whenever X → do Y” ที่​คอย​ฟัง event หนึ่ง​แล้ว​สั่ง command ต่อ​โดย​อัตโนมัติ (เช่น เมื่อ PaymentCaptured → แจ้ง​ร้าน​ให้​กด​รับ) แทน​ด้วย Post-it สี​ม่วง​อ่อนProcess (สี​ม่วง) แบบ “whenever event นี้ → สั่ง command โน้น”
  • และ​บาง command วิ่ง​ออก​ไป​หา External SystemExternal Systemระบบ​ภายนอก​ที่​เรา​ไม่​ได้​ควบคุม​แต่​ต้อง​คุย​ด้วย (เช่น Payment Gateway, บริการ​แจ้ง​เตือน, แผนที่) แทน​ด้วย Post-it สีชมพู ช่วย​ชี้​จุด​เชื่อม​ต่อ​และ​ความ​เสี่ยงArchitecture (สีชมพู) ที่​เรา​ไม่​ได้​คุม เช่น Payment Gateway

พอ​เติม​ครบ ไทม์​ไลน์​ที่​เคย​มี​แต่ Post-it สี​ส้ม​ก็​กลาย​เป็น “เรื่องราว​ที่​อธิบาย​กลไก​ตัวเอง” ได้ นี่แหละ​สะพาน​ที่​พา​เรา​จาก​ภาพ​รวม​ไป​สู่​ระดับ design

ทำไม​ต้อง​มี​ระดับ​กลาง​คั่น

ถ้า​กระโดด​จาก Big Picture ไป design-level เลย ทีม​มัก​เถียง​กัน​เรื่อง class กับ table เร็ว​เกิน​ไป​ทั้ง​ที่​ยัง​ไม่​เห็น​ภาพ​กลไก​ร่วม​กัน Process Modeling บังคับ​ให้​เรา​ตอบ “ใคร​สั่ง เพราะ​เห็น​อะไร กฎ​อะไร​ทำงาน​ต่อ” ก่อน แล้ว​ค่อย​ลง​รายละเอียด​โครงสร้าง — ลำดับ​นี้​ช่วย​กัน​เสีย​เวลา​ไป​กับ design ที่​ยัง​ไม่​เข้าใจ domain จริง


พอ​เข้า Design-Level EventStorming จะ​จัด​ของ​ทั้งหมด​ให้​เข้า​รูป​ประโยค​เดียว​ที่​ซ้ำ​ไป​ทั้ง​ผนัง เรียก​ว่า “ไวยากรณ์” ของ EventStorming:

actor เห็น read model แล้ว​ออก command → command วิ่ง​เข้า aggregate ตัว​หนึ่ง → aggregate ตัดสิน​ใจ​แล้ว​ปล่อย event ออก​มา

ลอง​ดู slice เดียว​จากฟู้ด​เดลิ​เวอรี — ตอน​ลูกค้า​กด​สั่ง​อาหาร:

flowchart LR
  RM["ตะกร้า Cart<br/>read model"] --> A["ลูกค้า<br/>actor"]
  A --> C["PlaceOrder<br/>command"]
  C --> AGG["Order<br/>aggregate"]
  AGG --> E["OrderPlaced<br/>event"]
  classDef rm fill:#86efac,stroke:#15803d,color:#1a1a1f;
  classDef act fill:#fde047,stroke:#a16207,color:#1a1a1f;
  classDef cmd fill:#3b82f6,stroke:#1e40af,color:#f8fafc;
  classDef agg fill:#fef3c7,stroke:#a16207,color:#1a1a1f;
  classDef evt fill:#e8743b,stroke:#b45309,color:#1a1a1f;
  class RM rm;
  class A act;
  class C cmd;
  class AGG agg;
  class E evt;

อ่าน​จาก​ซ้าย​ไป​ขวา: ลูกค้า​เห็น​ยอด​ใน​ตะกร้า จึง​ออก​คำ​สั่ง PlaceOrder คำ​สั่ง​นี้​ไม่​ได้​ลอย​ไป​ไหน มัน​วิ่ง​เข้าหา Order ซึ่ง​เป็น aggregate แล้ว Order เป็น​คน​ตัดสิน​ใจ​ว่า “รับ​ได้​ไหม” ถ้า​ผ่าน​กฎ​ก็​ปล่อย OrderPlaced ออก​มา — ประโยค​เดียว​นี้​ซ้ำ​เป็น​สิบๆ ครั้ง​ตลอด context จน​เห็น design ทั้ง​ก้อน

จุด​สำคัญ​ที่​มือใหม่​มัก​พลาด คือ event ไม่​ได้​ต่อ​กับ event ตรงๆ เหมือน Big Picture อีก​ต่อ​ไป ระหว่าง event สอง​อัน​จะ​มี​กลไก (command + aggregate หรือ policy) คั่น​เสมอ ถ้า​เจอ event ต่อ event โดย​ไม่มี​อะไร​คั่น แปล​ว่า​เรา​ยัง​ขุด​กลไก​ไม่​ครบ


หัวใจ​ของ design-level คือ​คำ​ว่า AggregateAggregateกลุ่ม​ของ object ที่​ถือ​กฎ​ความ​สอดคล้อง (invariant) ไว้​ด้วย​กัน ใน EventStorming คือ “สิ่ง​ที่​รับ command แล้ว​ปล่อย event ออก​มา” (เช่น Order, Payment) แทน​ด้วย Post-it สี​เหลือง​แผ่น​ใหญ่Tactical Design ใน​ภาษา EventStorming มัน​คือ “ก้อน​ที่​รับ command เข้าไป แล้ว​ตัดสิน​ใจ​ว่า​จะ​ปล่อย event อะไร​ออก​มา” — และ​ที่​สำคัญ​กว่า​นั้น มัน​คือ ขอบเขต​ความ​สอดคล้อง (consistency boundary)

หมายความ​ว่า​อะไร? หมายความ​ว่า​กฎ​ธุรกิจ​ที่ “ต้อง​เป๊ะ​ทันที” จะ​ถูก​ปกป้อง​อยู่​ภายใน aggregate ตัว​เดียว ยก​ตัวอย่าง Order ต้อง​รับประกัน​ว่า “ยอด​รวม​ของออเดอร์ = ผล​บวก​ของ​ทุก​รายการ​อาหาร” กฎ​นี้​พลาด​ไม่​ได้​แม้แต่​วินาที​เดียว มัน​เลย​ต้อง​อยู่​ใน​กำแพง​ของ Order

กติกา​เหล็ก​ของ design-level มี​ข้อ​เดียว​ที่​ต้อง​จำ:

1 command เข้า 1 aggregate แล้ว​ปล่อย event ออก​มา ใน​หนึ่ง​การ​ทำงาน (1 transaction) เรา​แตะ aggregate แค่​ตัว​เดียว

ในฟู้ด​เดลิ​เวอรี​เรา​มี aggregate หลัก​สาม​ตัว แต่ละ​ตัว​คุม​กฎ​ของ​ตัวเอง:

  • Order — รับ PlaceOrder ปล่อย OrderPlaced ปกป้อง​กฎ​เรื่อง​รายการ​อาหาร​กับ​ยอด​รวม
  • Payment — รับ CapturePayment ปล่อย PaymentCaptured ปกป้อง​กฎ​ว่า​ตัด​เงิน​ได้​ครั้ง​เดียว​ต่อ​ออเดอร์
  • Delivery — รับ AssignRider/ConfirmDelivery ปล่อย RiderAssigned/FoodDelivered

สังเกต​ว่า Order ไม่​ได้​ไป​ยุ่ง​กับ​การ​ตัด​เงิน และ Payment ก็​ไม่รู้เรื่อง​รายการ​อาหาร ต่าง​คน​ต่าง​เฝ้า​กฎ​ของ​ตัวเอง — นี่​คือ​เหตุผล​ที่ aggregate ถูก​เรียก​ว่า “หน่วย​ความ​สอดคล้อง” เพราะ​มัน​คือ​หน่วย​ที่​เล็ก​ที่สุด​ที่​การันตีความ​ถูกต้อง​ได้​ใน​หนึ่ง​ครั้ง

กับดัก: aggregate ก้อน​เดียว​คุม​ทั้ง​โลก

มือใหม่​มัก​ออกแบบ Order ก้อน​ยักษ์​ที่​ถือ​ทั้ง​รายการ​อาหาร การ​จ่าย​เงิน ที่​อยู่​จัด​ส่ง และ​สถานะ​ไร​เด​อร์ไว้​ใน​ตัว​เดียว ผล​คือ​ทุกๆ การ​อัปเดต​เล็กน้อย​ต้อง​ล็อก​ทั้ง​ก้อน แก้​ชน​กัน​ตลอด กฎ​คือ ถ้า​สอง​สิ่ง​ไม่​จำเป็น​ต้อง​ถูกต้อง​พร้อม​กัน ณ วินาที​เดียวกัน ก็​แยก​เป็น​คนละ aggregate แล้ว​ค่อย​เชื่อม​กัน​ด้วย policy (หัวข้อ​ถัด​ไป)


ถ้า​แต่ละ aggregate แตะ​ได้ที​ละ​ตัว​ต่อ transaction แล้ว event ที่ Payment ปล่อย​ออก​มา​จะ​ไป​สั่ง​ให้​ร้าน​กด​รับ​ได้​ยังไง? คำ​ตอบ​คือ Policy — Post-it สี​ม่วง​ที่​อ่าน​ว่า “whenever <event> → <command>”

Policy คือ​กฎ​เชิง​ปฏิกิริยา​ที่นั่ง​ฟัง event หนึ่ง​อยู่​เงียบๆ พอ event นั้น​เกิด​ปุ๊บ มัน​ก็​ยิง command ตัว​ใหม่​ออก​ไป​หา aggregate อีก​ตัว​โดย​อัตโนมัติ นี่​คือ​กลไก​ที่​ทำให้​กระบวนการ “ไหล​ต่อ” ข้าม​ขอบเขต​ของ aggregate ได้ โดย​ไม่​ต้อง​แตะ2 aggregate พร้อม​กัน

ในฟู้ด​เดลิ​เวอรี​มี policy หลาย​ตัว​ที่​คอย​ส่ง​ไม้​ต่อ​ให้​กระบวนการ​เดิน​เอง เช่น:

  • whenever OrderPlaced → ตัด​เงิน (นำ​ไป​สู่ CapturePayment)
  • whenever PaymentCaptured → แจ้ง​ร้าน​ให้​กด​รับ (นำ​ไป​สู่ AcceptOrder)
  • whenever OrderAcceptedByRestaurant → หา​ไร​เด​อร์ (นำ​ไป​สู่ AssignRider)

ลอง​วาง​สอง​ตัว​แรก​เป็น​โซ่​ต่อ​กัน​ตั้งแต่​ลูกค้า​กด​สั่ง จน​กลไก​วิ่ง​ข้าม3 aggregate ด้วย​ตัวเอง:

flowchart LR
  A["ลูกค้า"] --> C1["PlaceOrder"]
  C1 --> O["Order aggregate"]
  O --> E1["OrderPlaced"]
  E1 --> P1["whenever OrderPlaced<br/>ตัดเงิน"]
  P1 --> C2["CapturePayment"]
  C2 --> PAY["Payment aggregate"]
  PAY --> E2["PaymentCaptured"]
  E2 --> P2["whenever PaymentCaptured<br/>แจ้งร้านให้กดรับ"]
  P2 --> C3["AcceptOrder"]
  C3 --> O2["Order aggregate"]
  O2 --> E3["OrderAcceptedByRestaurant"]
  classDef act fill:#fde047,stroke:#a16207,color:#1a1a1f;
  classDef cmd fill:#3b82f6,stroke:#1e40af,color:#f8fafc;
  classDef agg fill:#fef3c7,stroke:#a16207,color:#1a1a1f;
  classDef evt fill:#e8743b,stroke:#b45309,color:#1a1a1f;
  classDef pol fill:#c4b5fd,stroke:#6d28d9,color:#1a1a1f;
  class A act;
  class C1 cmd;
  class C2 cmd;
  class C3 cmd;
  class O agg;
  class PAY agg;
  class O2 agg;
  class E1 evt;
  class E2 evt;
  class E3 evt;
  class P1 pol;
  class P2 pol;

อ่าน​โซ่​นี้​แล้ว​จะ​เห็น “จังหวะ​หายใจ” ของ​ระบบ: คน​เริ่มต้น​แค่​ครั้ง​เดียว (PlaceOrder) จาก​นั้น policy สี​ม่วง​ทำ​หน้าที่​เป็น​กาว ส่ง​ต่อ​จาก event ของ aggregate หนึ่ง​ไป​เป็น command ของ​อีก aggregate อย่าง​ต่อ​เนื่อง​จน​กระบวนการ​เดิน​เอง​ได้ ตรง​นี้​แหละ​ที่ design-level เผย​กลไก​ซึ่ง Big Picture มอง​ไม่​เห็น

🍔 อ่าน​ผนัง Ordering ของฟู้ด​เดลิ​เวอรี​ให้​เป็น​ประโยค

ลอง​อ่าน slice Ordering ออก​เสียง​เป็น​ภาษา​คน: “ลูกค้า​เห็น​ตะกร้า จึง PlaceOrder; Order รับ​แล้ว​ปล่อย OrderPlaced; whenever OrderPlaced ระบบ CapturePayment; Payment ปล่อย PaymentCaptured; whenever PaymentCaptured แจ้ง​ร้าน​ให้ AcceptOrder; Order ปล่อย OrderAcceptedByRestaurant” — ถ้า​อ่าน​ทั้ง​ผนัง​แล้ว​ลื่น​เป็น​เรื่อง​เล่า​แบบ​นี้ แปล​ว่า design ครบ​พอ​จะ​ลง code แล้ว ถ้า​สะดุด​ตรง​ไหน แปล​ว่า​ตรง​นั้น​ยัง​มี​กลไก​ที่​ทีม​ยัง​ไม่​เข้าใจ​ตรง​กัน


ทีนี้​ย้อน​ไป​ที่ Post-it สี​เขียว — Read Model มัน​ไม่ใช่​ของ​ประดับ แต่​เป็น​ครึ่ง​หนึ่ง​ของ​ภาพ​ที่​คน​มัก​ลืม

สังเกต​ว่า​ใน​ไวยากรณ์​ของ​เรา event เป็น​ผลลัพธ์​ของ​การ “เขียน” (command เปลี่ยน​สถานะ) แต่ actor จะ​ออก command ได้​ก็​ต่อ​เมื่อ “อ่าน” อะไร​บาง​อย่าง​ก่อน เช่น​ลูกค้า​ต้อง​เห็น​ตะกร้า​ก่อน ถึง​จะ​กด​สั่ง; ต้อง​เห็น​หน้า​ติดตามออเดอร์ (Order tracking) ก่อน ถึง​จะ​รู้​ว่า​ต้อง​รอ​อีก​นาน​ไหม

พอ​แยก​สอง​ฝั่ง​นี้​ออก​จาก​กันชัดๆ เรา​ก็ได้​แนวคิด​ที่​ชื่อ CQRS (Command Query Responsibility Segregation) — แยก “ความ​รับผิดชอบ​ของ​การ​สั่ง (Command)” ออก​จาก “ความ​รับผิดชอบ​ของ​การ​ถาม (Query)” คนละ model คนละ​เส้นทาง:

flowchart LR
  subgraph WRITE["ฝั่งเขียน Command หรือ Write"]
    A["ลูกค้า"] --> CMD["PlaceOrder"]
    CMD --> AGG["Order aggregate"]
    AGG --> EV["OrderPlaced"]
  end
  subgraph READ["ฝั่งอ่าน Query หรือ Read"]
    A2["ลูกค้า"] --> RM["หน้าติดตามออเดอร์<br/>read model"]
  end
  EV -.->|"อัปเดต projection"| RM
  classDef act fill:#fde047,stroke:#a16207,color:#1a1a1f;
  classDef cmd fill:#3b82f6,stroke:#1e40af,color:#f8fafc;
  classDef agg fill:#fef3c7,stroke:#a16207,color:#1a1a1f;
  classDef evt fill:#e8743b,stroke:#b45309,color:#1a1a1f;
  classDef rm fill:#86efac,stroke:#15803d,color:#1a1a1f;
  class A act;
  class A2 act;
  class CMD cmd;
  class AGG agg;
  class EV evt;
  class RM rm;

ฝั่ง​เขียน (ซ้าย) มีหน้าที่​เดียว — รับ command ปกป้อง​กฎ ปล่อย event มัน​ไม่​ต้อง​แคร์​ว่า​หน้า​จอ​จะ​โชว์​สวย​แค่​ไหน ส่วน​ฝั่ง​อ่าน (ขวา) มีหน้าที่​เดียว​เช่น​กัน — เอา event ที่​เกิด​ขึ้น​มา “ปั้น” เป็น​หน้า​จอ​ที่​ตอบ​คำถาม​ผู้​ใช้ได้​เร็ว (เรียก​ว่า projection) เส้น​ประจาก OrderPlaced ไป read model คือ​การ​บอกว่า “ทุก​ครั้ง​ที่​ฝั่ง​เขียน​ปล่อย event ฝั่ง​อ่าน​จะ​อัปเดต​หน้า​จอ​ตาม”

ข้อดี​ที่​จับ​ต้อง​ได้: ฝั่ง​อ่าน​ปรับ​แต่ง​ให้​เร็ว​ได้​อิสระ (cache ทำ index ตามใจ) โดย​ไม่​กระทบ​กฎ​ธุรกิจ​ฝั่ง​เขียน​เลย และ​เวลา​ทำ EventStorming จะ​เห็น​ชัด​ว่า read model แต่ละ​อัน​ถูก​ป้อน​ด้วย event ตัว​ไหน​บ้าง — ทำให้​ตอบ​ได้​ทันที​ว่า “ถ้า​อยาก​ได้​หน้า​จอ​นี้ ต้อง​มี event อะไร​เกิด​ก่อน”

กับดัก: policy เยอะ​จน​กลาย​เป็น​เส้น​สปาเกตตี

พอ​สนุก​กับ policy หลาย​ทีม​เริ่ม​โยง event ทุก​อัน​เข้าหา​กัน​จน​ผนัง​กลาย​เป็น​ชาม​สปาเกตตี วิธี​กัน​คือ​ถาม​ทุก​เส้น​สี​ม่วง​ว่า “กฎ​นี้​เป็น​ของ domain จริง​ไหม หรือ​แค่​รายละเอียด​เทคนิค” และ “ใคร​เป็น​เจ้าของ​กฎ​นี้” ถ้า​ตอบ​ไม่​ได้ ให้​แปะ​เป็น Hotspot สี​แดง​ไว้​ก่อน อย่า​เพิ่ง​ลาก​เส้น


ปิด​ท้าย​ด้วย​การ​เทียบ​สอง​ระดับ​ให้​เห็น​ชัด เพื่อ​ไม่​ให้​สับสน​ว่า​ตอน​ไหน​ควร​อยู่​ระดับ​ไหน:

  • ขอบเขต — Big Picture กวาด​ทั้ง​สาย​ธุรกิจ​หลาย context; design-level ซูม​เข้า context เดียว (เช่น Ordering) แล้ว​เจาะ​ให้​ลึก
  • คนใน​ห้อง — Big Picture เชิญ​คน​ทุก​ฝ่าย​มาระดม; design-level เหลือ​ทีม​ที่​จะ​ลงมือ​สร้าง​จริง (dev + domain expert ที่​เกี่ยวข้อง)
  • หน่วย​บน​ผนัง — Big Picture มี​แทบ​แต่ event สี​ส้ม; design-level ครบ​ทุก​สี — command, aggregate, policy, read model, external
  • ความ​ละเอียด — Big Picture ตอบ “เกิด​อะไร​บ้าง”; design-level ตอบ “เกิด​ได้​ยังไง ใคร​สั่ง กฎ​ไหน​ทำงาน” จน​พร้อม​แปลง​เป็น code
  • ผลลัพธ์ — Big Picture ได้​ภาพ​รวม​และ pivotal event ที่​บอกใบ้​ขอบเขต; design-level ได้​พิมพ์เขียว​ของ aggregate, command, event ที่​หยิบ​ไป​ออกแบบ class/ตาราง​ได้​เลย

ทั้ง​สอง​ไม่ใช่​คู่แข่ง แต่​เป็น​กล้อง​คนละ​กำลัง​ขยาย เรา​เริ่ม​จาก​เลนส์​กว้าง​เพื่อ​ไม่​ให้​หลง​ป่า แล้ว​ค่อย​เปลี่ยน​เป็น​เลนส์​มาโคร​เมื่อ​รู้​แล้ว​ว่า​จะ​เจาะ​ต้น​ไหน

หัวใจ​ของ​บท​นี้
  • Process Modeling เป็น​สะพาน — เดิน​ที​ละ event แล้ว​เติม command/actor/read model/policy/external รอบๆ จน​เห็น​กลไก​ที่​ทำให้ event เกิด
  • ไวยากรณ์ design-level — actor เห็น read model → ออก Command → เข้า 1 Aggregate → ปล่อย Domain EventDomain Eventสิ่ง​ที่ “เกิด​ขึ้น​แล้ว” และ​มี​ความหมาย​ต่อ​ผู้เชี่ยวชาญ​ธุรกิจ เขียน​เป็นกริยา​อดีต (เช่น OrderPlaced, PaymentCaptured) แทน​ด้วย Post-it สี​ส้ม เป็น​หน่วย​ตั้งต้น​ของ EventStorming ทุก​แบบTactical Design; event ไม่​ต่อ event ตรงๆ อีก​ต่อ​ไป
  • Aggregate = ขอบเขต​ความ​สอดคล้อง — 1 command เข้า 1 aggregate ต่อ1 transaction; สิ่ง​ที่​ต้อง​ถูกต้อง​พร้อม​กัน​เท่านั้น​จึง​อยู่​ก้อน​เดียวกัน
  • Policy เชื่อม​ข้าม​ขอบเขต — “whenever event → command” ทำให้​กระบวนการ​ไหล​ข้าม aggregate โดย​ไม่​ต้อง​แตะ​สอง​ตัว​พร้อม​กัน
  • Read Model + CQRS — ฝั่ง​เขียน (command/aggregate/event) แยก​จาก​ฝั่ง​อ่าน (read model/projection) คนละ model คนละ​เส้นทาง
🔗 อ้างอิง​เพิ่มเติม​ใน DevIQ

เจาะ​ลึก​แนวคิด​ต่อ​ได้ที่​คลัง​อ้างอิง DevIQ:

  • Aggregate — ขอบเขต​ความ​สอดคล้อง​ที่ design-level ยึด​เป็น​หน่วย 1 command เข้า 1 aggregate ตรง​กับ​หัวใจ​ของ​บท​นี้
  • CQRS — แนวคิด​แยก​ฝั่ง​เขียน (command) ออก​จาก​ฝั่ง​อ่าน (read model) แบบ​เต็มๆ ต่อยอด​จาก​หัวข้อ Read Model
  • Event Aggregator — กลไก pub/sub เบื้องหลัง​ที่​ทำให้ policy คอย​ฟัง event แล้ว​ยิง command ต่อ​ได้​จริง​ใน code

เช็กความเข้าใจ — บทที่ 4

ข้อ 1 / 3

ใน Design-Level EventStorming aggregate เป็น “ขอบเขต” ของอะไรเป็นอันดับแรก?