บทที่ 4 · Part 1 — Foundations and Economics

Ubiquitous Language in Practice

สร้างภาษาที่ใช้จริงใน conversation, examples, model, code และ tests พร้อมจัดการคำเดียวหลายความหมาย

Ubiquitous Language in Practice

ใน incident เดียว ทีม Operations บอกว่า transfer ถูก “ reversed” ทีม Accounting บอกว่าเป็น “ adjustment” และ provider ส่งสถานะ reversed ซึ่งจริง ๆ หมายถึง payment authorization ถูกคืน หากทุกคนแปลคำเป็น field เดียว ระบบอาจทำ financial correction ผิดชนิด Ubiquitous Language ไม่ได้มีไว้ตกแต่ง glossary แต่มีกติกาว่าคำที่ทีมพูดต้องเชื่อมกับ model และ behavior จริง

จบบทนี้คุณจะ

สร้าง Ubiquitous Language ที่มีขอบเขต เก็บทั้ง noun, verb, state, rule และ counterexample ตรวจ language drift ระหว่าง conversation, document, code และ tests และจัดการคำเดียวหลายความหมาย โดยไม่สร้าง enterprise-wide canonical vocabulary

ภาษาที่ใช้ทุกที่ใน Context

DDD Reference และ Ubiquitous Language ของ Martin Fowler เน้นว่าภาษาถูกใช้ร่วมกันโดย developer กับ domain experts ทั้งในการพูด การเขียน model และ code ถ้าเอกสารใช้ Beneficiary แต่ code ใช้ receiverUser และ database ใช้ customer2 การแปลยังเกิด ทุกครั้งและแต่ละคนอาจแปลไม่เหมือนกัน

Language entry ที่ใช้ได้ควรมี:

ช่องตัวอย่าง
TermTransfer Intent
ContextCustomer Transfer
Definitionคำขอของลูกค้าให้ส่ง Money ไปยัง Beneficiary ภายใต้เงื่อนไขที่ระบุ
Example statementCustomer confirms a Transfer Intent
State/verbsdraft, confirm, expire, cancel
Counterexampleprovider request ไม่ใช่ Intent
OwnerTransfer Product + Operations
Open questionยกเลิกได้ถึงเหตุการณ์ใด

Glossary ที่มีแต่ Transfer: การโอนเงิน ไม่ช่วยตัดสินอะไร ต้องมี statement และ counterexample เพื่อให้เห็น grammar ของ domain เช่น “ Intent expires” กับ “ Provider Attempt times out”

ภาษามีขอบเขต

คำว่า Account อาจหมายถึง:

  • Customer Profile: ความสัมพันธ์กับบุคคล/นิติบุคคล
  • Wallet: container ที่ถือสิทธิ์ใช้ funds
  • Ledger: หน่วยจัดกลุ่ม entries ตาม accounting semantics
  • Identity: credential หรือ login subject
  • Provider: merchant account ที่ vendor ออกให้

เป้าหมายไม่ใช่บังคับให้ทุก context ใช้ definition เดียว แต่ให้แต่ละ context สอดคล้องภายใน และแปลตรง boundary ชื่อที่ qualifier ชัด เช่น LedgerAccountID หรือ ProviderMerchantRef ลดการอ้าง accountID ที่ไม่มีใครรู้ authority

เส้นประแสดงคำที่ยังคลุมเครือ ส่วนเส้นทึบคือ contract ที่ตั้งใจแปลแล้ว Diagram จึงไม่ได้เสนอ Account กลาง แต่แสดงว่าทุก boundary ต้องระบุ reference และความหมายที่ผู้รับใช้ได้

Shared Word ไม่ได้แปลว่า Shared Model

คำเดียวกันอาจมี identity reference ร่วมแต่ behavior ต่างกัน การแชร์ struct Customer ระหว่าง Billing, Risk และ Wallet ทำให้ field ที่ไม่เกี่ยวกับแต่ละ decision รั่วและบังคับ release ร่วมกัน ให้แชร์ผ่าน contract ที่ตั้งใจหรือ map reference/snapshot ตาม semantics

หา Language จาก Conversation

ฟังคำที่เกิดใน 5 จุด:

  1. คำที่ผู้เชี่ยวชาญแก้ทันทีเมื่อคนอื่นใช้ผิด
  2. คำกำกวมอย่าง success, active, balance, cancel, post
  3. verb ที่เปลี่ยน state เช่น reserve, authorize, settle, reconcile
  4. policy sentence ที่มี “ถ้า…จึง…” หรือ “ห้าม…เมื่อ…”
  5. exception และ workaround ที่ไม่มีชื่อแต่ Operations ทำทุกวัน

อย่า normalize เร็วเกินไป หาก Finance พูด reverse entry และ Support พูด undo transfer ให้ขอ scenario จริงก่อน อาจเป็น action เดียวกัน หรืออาจคนละ context ซึ่งผลทางบัญชีต่างกัน

Language Test

ใช้ test 4 ชั้น:

  • Conversation test: Domain Expert เล่า scenario โดยใช้คำเหล่านี้หรือไม่
  • Example test: Given/When/Then ระบุ state และ result โดยไม่ใช้คำกำกวมหรือไม่
  • Code test: type/method/event สื่อ verb และ rule เดียวกันหรือไม่
  • Operation test: dashboard, alert และ runbook ใช้คำที่ชี้ owning context ได้หรือไม่

ตัวอย่างที่ drift:

Conversation: Transfer became indeterminate
Code:         status = FAILED
Dashboard:    payment_error_total
Runbook:      retry transaction

แก้ด้วยการตกลงว่า Indeterminate Execution หมายถึงไม่มี evidence พอจะสรุป success/failure และ operation ต่อไปคือ Reconcile Execution ไม่ใช่ retry แบบสร้าง side effect ใหม่ทันที

รักษา Language ให้มีชีวิต

เก็บ glossary ใกล้ context owner และ version ร่วมกับ examples/code เมื่อทำได้ แต่ไม่ต้องบังคับ format เดียวทั้งองค์กร ตั้ง owner และ review trigger:

  • feature เพิ่ม state transition ใหม่
  • incident พบคำไม่ตรงกัน
  • provider/standard เปลี่ยน contract
  • policy version หรือ jurisdiction เปลี่ยน
  • context ถูก split/merge หรือทีม ownership เปลี่ยน

หากคำเก่าเลิกใช้ ให้ deprecate พร้อมเหตุผลและ migration ไม่แก้ history เงียบ เอกสาร contract อาจยังต้องรองรับชื่อเก่าแม้ model ภายในใช้ภาษาใหม่

Language กับ Translation Boundary

Published Language เช่น ISO 20022 message หรือ provider schema ช่วยสื่อสารข้ามองค์กร แต่ไม่ควร ถูกใช้เป็น model ภายในทั้งหมด ACL แปล external status, identifiers และ amounts เป็น concept ที่ context เป็นเจ้าของ พร้อมเก็บ source version ถ้า semantics เปลี่ยนได้

คำทาง Compliance ต้องมี Authority

Verified, Eligible, High Risk และ Approved ห้ามกำหนดจากความรู้สึกของ Engineer ต้องระบุ policy owner, source, version, jurisdiction และ effective date Language ช่วยทำให้การตัดสิน trace ได้ แต่ไม่แทน Legal/Risk interpretation

แบบฝึกปฏิบัติ: Balance Language Clinic

เก็บคำว่า Balance จาก 4 ฝ่าย: Customer Support, Wallet, Accounting และ Portal แล้วกรอก:

Statement actually spoken:
Meaning in this context:
Time axis / freshness:
Authoritative source:
Decision allowed:
Decision forbidden:
Example:
Counterexample:
Preferred qualified term:
Owner:

ต้องได้อย่างน้อย 3 terms เช่น Posted Balance, Available Funds, Displayed Balance แล้วเขียน scenario ที่ทั้ง 3 ค่าไม่เท่ากันเพื่อพิสูจน์ว่าความแตกต่างมีผลจริง

รายการตรวจสอบ

  • Language มี boundary และ owner
  • เก็บ noun, verb, state, rule และ exception
  • ทุก term มี statement กับ counterexample
  • คำเดียวต่าง context ไม่ถูกแชร์ model อัตโนมัติ
  • Conversation, examples, code และ operation ใช้ความหมายสอดคล้อง
  • External/standard language ถูกแปลที่ boundary
  • Language drift มี review trigger และ deprecation path

สรุปบทนี้

Ubiquitous Language คือระบบ feedback ระหว่างคนกับ model ไม่ใช่พจนานุกรมกลาง เมื่อคำถูกใช้จริง ใน scenario, code, tests และ operation ความกำกวมจะปรากฏเร็วขึ้น ภาษาที่ดีมีขอบเขต ยอมรับ polysemy และเปลี่ยนได้เมื่อความเข้าใจเปลี่ยน

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