บทที่ 9 · Part 2 — Discover the Domain Together
Example Mapping: Rules and Questions
เปลี่ยน story ให้เป็น rules, concrete examples, counterexamples และ questions ก่อนสร้าง model หรือ code
Example Mapping: Rules and Questions
Requirement “อนุญาตให้ยกเลิก transfer ที่ยังไม่สำเร็จ” ดูง่ายจนถามว่า successful ของ provider
กับ posted ของ Ledger ต่างกันหรือไม่ หาก customer กดยกเลิกตอน provider timeout จะตอบอย่างไร
Example Mapping ทำให้ story ถูกแยกเป็น rules, examples, counterexamples และ questions ก่อนที่
ทีมจะซ่อนความกำกวมไว้ใน if หลายชั้น
จบบทนี้คุณจะ
ใช้ Example Mapping เจาะ story หนึ่งเป็น business rules, concrete examples และ questions เปลี่ยน examples เป็น invariant/state transition candidates ระบุ policy owner และแยกสิ่งที่ทีมรู้ ออกจาก assumption โดยไม่บังคับทุก example ให้เป็น automated test แบบเดียวกัน
4 ชนิดของ Card
- Story — outcome ที่กำลังสำรวจ
- Rule — constraint หรือ behavior ที่ต้องเป็นจริง
- Example — concrete case ที่แสดง rule
- Question — สิ่งที่ยังตอบไม่ได้
ตัวอย่าง Story: Cancel a Transfer Intent
Rule: Customer may cancel before execution becomes irrevocable
Example: No provider attempt exists -> cancellation accepted
Example: Provider rejected attempt -> cancellation accepted
Example: Provider outcome is indeterminate -> cancellation pending review
Question: Which provider evidence makes execution irrevocable?
Question: Who owns the definition for each rail/jurisdiction?
อย่าเขียน rule จากสิ่งที่ Engineer คิดว่าน่าจะสมเหตุผล เจ้าของ product/policy ต้องยืนยันและ question ต้องมีชื่อคนรับผิดชอบ
ต้นไม้นี้ทำให้เห็นว่า Story หนึ่งมีหลาย Rules ได้ Rule หนึ่งต้องมีหลาย Examples และ Question ไม่ใช่ช่องว่างที่ Engineer เติมเอง แต่เป็นงานค้นคว้าที่มี owner
Concrete ก่อน Abstract
Example ที่ดีมี values และ context พอให้เกิด disagreement:
Given Transfer Intent T-104 has Money{150000, THB}
And Provider Attempt P-77 timed out at 10:04
And no authoritative provider outcome is available at 10:05
When Customer requests cancellation at 10:06
Then the system records Cancellation Requested
And does not claim that funds were returned
And opens reconciliation under the owning policy
จำนวนเป็น scenario input แบบ illustrative ไม่ใช่ threshold Example ทำให้เห็น time axis และ distinction ระหว่าง “รับคำขอยกเลิก” กับ “เงินไม่ถูกส่ง”
Rule, Policy และ Invariant
แยก:
- Rule: behavior ที่ story ต้องทำตาม
- Policy: decision ซึ่งอาจเปลี่ยนตาม owner/version/context
- Invariant: เงื่อนไขที่ model boundary ต้องไม่ยอมให้ผิด
ตัวอย่าง “ห้าม post debit ซ้ำสำหรับ accepted execution เดียว” เป็น invariant candidate ส่วน “ transfer amount ระดับใดต้อง review” เป็น policy ที่ต้องมี owner/source/date Example Mapping ไม่ได้ตัดสินว่า invariant อยู่ Aggregate ใด แต่ให้ evidence สำหรับ Tactical Modeling
ห้ามทำ Policy Placeholder ให้กลายเป็น Fact
ถ้า owner ยังไม่ตอบ ให้เก็บ Question: approval threshold? Owner: Risk Policy
อย่าใส่ตัวเลขชั่วคราวใน acceptance test เพราะมันมักกลายเป็น production rule โดยไม่มี authority
หา Counterexample อย่างมีระบบ
ใช้ dimensions:
| Dimension | Questions |
|---|---|
| Identity | duplicate request, reused idempotency key, wrong tenant |
| Time | expired, late callback, policy version changed |
| Money | zero, currency mismatch, amount already partially used |
| State | draft, reserved, submitted, indeterminate, reconciled |
| Authority | stale read model, missing evidence, unauthorized actor |
| Integration | timeout, duplicate, out-of-order, contradictory report |
| Human | manual override, maker-checker, abandoned case |
Counterexample ไม่ได้มีไว้เพิ่ม test count แต่เพื่อท้าทาย language และ model เช่นถ้า Cancel
หมายถึง 3 business actions ควร rename ก่อนสร้าง state machine ใหญ่
จาก Examples สู่ Executable Specification
เลือก automation level ตาม claim:
- pure domain examples ตรวจ invariant/policy behavior
- application tests ตรวจ orchestration, authorization และ transaction
- adapter contract tests ตรวจ translation ของ provider
- integration tests ตรวจ persistence/concurrency
- journey tests ตรวจ critical cross-context outcome
ไม่ต้อง automate ทุก workshop card บาง question ต้องใช้ research/interview และบาง scenario เป็น documentation ที่คนตรวจ ความสำคัญคือ trace rule → example → model/test/owner
จำกัด Scope ด้วย Questions
ถ้า story มี rules มากเกิน session ให้ split ตาม outcome ไม่สร้าง story “ Manage Transfer” ขนาดใหญ่ ใช้ red question เป็นผลลัพธ์ที่มีค่า เพราะบอกว่าทีมยังไม่พร้อม implement หรือควรทำ spike
Definition of Ready แบบ DDD ไม่ควรบังคับว่าทุก question ต้องปิด แต่ critical policy/invariant ต้องมี answer/owner และ unknown ต้องไม่ถูกซ่อน
แบบฝึกปฏิบัติ: Indeterminate Cancellation
สร้าง Example Map ของ Request Transfer Cancellation อย่างน้อย:
1 story
3 rules
2 examples per rule
1 counterexample per rule
4 open questions with owners
1 policy version question
1 invariant candidate
จากนั้นเลือก 2 examples แปลงเป็น Given/When/Then และบอกว่าควรทดสอบที่ domain, application หรือ integration seam พร้อมเหตุผล
รายการตรวจสอบ
- Story มี outcome เฉพาะ
- Rule มาจากผู้รับผิดชอบ ไม่ใช่ technical assumption
- Example concrete พอเผย disagreement
- Counterexample ครอบ identity, time, money, state และ integration
- Question มี owner และไม่ถูกปิดด้วยค่าชั่วคราว
- Rule, policy และ invariant ถูกแยก
- Automation seam ตรงกับ claim ที่ต้องพิสูจน์
สรุปบทนี้
Example Mapping ย่อ conversation ให้เจาะจงจาก story ไป rule, example และ question มันเชื่อม discovery กับ model/test โดยไม่ทำให้ acceptance criteria เป็นเพียง prose และทำให้สิ่งที่ ทีมยังไม่รู้มี owner แทนการซ่อนใน implementation
อ่านเพิ่มเติม
- Example Mapping — official Cucumber guidance
- BDD Discovery — collaboration, discovery และ examples
- DDD Starter Modelling Process — feedback ระหว่าง discovery กับ code