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

Model-Driven Design

ใน​บท​ก่อน เรา​ได้​กลั่น problem domain จน​เห็น Core DomainCore Domainsubdomain ที่​สำคัญ​และ​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน​มาก​ที่สุด เป็น​เหตุผล​ที่​เรา​ต้อง​สร้าง​ซอฟต์แวร์​เอง​แทน​การ​ซื้อ ควร​ทุ่ม​ทีม​เก่ง​ที่สุด​ลง​ตรง​นี้Strategic Design และ​เข้าใจ​ว่า​ควร​ทุ่ม​แรง​ตรง​ไหน ตอน​นี้​ถึง​เวลา​ก้าว​เข้า​สู่ solution space — แต่​มี​กับดัก​รอ​อยู่ กระบวนการ​พัฒนา​แบบ​ดั้งเดิม​มัก​แยก “model ที่​ใช้​คุย​กับ​ธุรกิจ” (analysis model) ออก​จาก “model ที่​อยู่​ใน code จริง” (code model) ผล​คือ​สิ่ง​ที่ build ออก​มากลับ​เบน​ห่าง​จาก​พิมพ์เขียว​ที่​วาง​ไว้​แต่​แรก

Model-Driven Design คือ​คำ​ตอบ​ของ DDD ต่อ​ปัญหา​นี้ — มัน​คือ กระบวนการ​ผูก analysis model เข้า​กับ code model ให้​เป็น model เดียวกัน โดย​ใช้ Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design เป็น​กาว​ยึด​ทั้ง​สอง​ให้ sync กัน​ตลอด​อายุ​ของ​ระบบ บท​นี้​จะ​พา​ไป​สำรวจ​ว่า domain model คือ​อะไร ทำไม UL จึง​เป็น​หัวใจ และ​เรา​จะ​สร้าง domain model ที่​ได้​ผล​จริง​ได้​อย่างไร


Domain ModelDomain ModelModel ของ Domain ที่​ฝัง​กฎ​และ​กระบวนการ​ทาง​ธุรกิจ​ไว้​ใน code จริง หัวใจ​ของ DDD คือ​การ​พัฒนา domain model ที่ “เข้าใจ​ธุรกิจ​อย่าง​ลึกซึ้ง”Strategic Design อยู่​ตรง​ศูนย์กลาง​ของ DDD มัน​เกิด​ขึ้น​ครั้ง​แรก​ใน​รูป​ของ analysis model จาก​การ​ที่​ทีม​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ​ร่วม​กัน บด​เคี้ยว​ความ​รู้Knowledge Crunchingการ​บด​เคี้ยว​ความ​รู้ — ศิลปะ​การกลั่น​ข้อมูล​ที่​เกี่ยวข้อง​ออก​จาก problem domain ร่วม​กับ domain expert เพื่อ​สร้าง model ที่​มี​ประโยชน์​ต่อ business use caseProcess model นี้​ไม่ใช่​ภาพ​สะท้อน​ความ​จริง​ทั้งหมด — มัน​เป็น “มุมมอง” ของ problem domain ที่​ออกแบบ​มา​เพื่อ​ตอบ business use case เท่านั้น

คุณค่า​ของ domain model ไม่​ได้​อยู่​ที่​มัน​เหมือน​ชีวิต​จริง​แค่​ไหน แต่​อยู่​ที่​ความ​สามารถ​ใน​การ​ถ่ายทอด​ตรรกะ​และ​นโยบาย​อัน​ซับซ้อน​ของ​ธุรกิจ​ออก​มา​เพื่อ​แก้​ปัญหา และ​มัน​ต้อง วิวัฒน์​ไป​พร้อม​กับ​ธุรกิจ​อยู่​เสมอ จึง​จะ​คง​คุณค่า​นั้น​เอา​ไว้​ได้

รูปที่ 4-1: บทบาทของ domain model — UI ส่งคำขอผ่าน application layer (ตัวแทน use case) ลงไปยัง domain layer ซึ่งบรรจุตรรกะ กระบวนการ และแนวคิดของ domain ไว้

🛒 ตัวอย่าง — คูปอง​ส่วนลด​ใน​ตะกร้า

ลอง​ดู​รูป​ที่ 4-1: หน้า​จอ​ตะกร้า​มี​ช่อง​กรอก​คูปอง use case คือ “ใส่​คูปอง​เพื่อ​รับ​ส่วนลด”

  • application layer เป็น client ของ domain layer — มัน​แทน use case ของ​ระบบ รับคำ​สั่ง​จาก UI แล้ว​เรียก domain
  • domain model คือ​ที่​ที่​ตรรกะ​ของ​คูปอง​อยู่​จริง: คูปอง​นี้​ใช้ได้​ไหม คำนวณ​ส่วนลด​ของ​ตะกร้า​อย่างไร

ตรรกะ​ส่วนลด​ไม่​ควร​กระจัดกระจาย​อยู่​ใน UI หรือ controller — มัน​ต้อง​อยู่​ใน domain model

นี่​คือ​ความ​แตก​ต่าง​ที่​คน​สับสน​บ่อย:

  • DomainDomainขอบเขต​ของ​ปัญหา​หรือ​ธุรกิจ​ที่​ซอฟต์แวร์​ของ​เรา​เข้าไป​แก้ไข เช่น การ​ขนส่ง​สินค้า การ​ธนาคาร e-commerce — คือ “โลก​ของ​ผู้​ใช้” ที่​โปรแกรม​ต้อง​เข้าใจStrategic Design คือ ความ​จริง — ขอบเขต​ของ​ปัญหา​ที่​เรา​กำลัง​ทำงาน​อยู่ มัน​มี​อยู่​ก่อน​เรา​จะ​เขียน code
  • Domain ModelDomain ModelModel ของ Domain ที่​ฝัง​กฎ​และ​กระบวนการ​ทาง​ธุรกิจ​ไว้​ใน code จริง หัวใจ​ของ DDD คือ​การ​พัฒนา domain model ที่ “เข้าใจ​ธุรกิจ​อย่าง​ลึกซึ้ง”Strategic Design คือ abstraction ของ problem domain ที่​แสดงออก​เป็น code — เป็น “มุมมอง” ไม่ใช่​ความ​จริง

รูปที่ 4-2: Domain คือความจริงในฝั่ง problem space ส่วน Domain Model คือ projection ของมันในฝั่ง solution space — เป็น abstraction ที่ออกแบบมาเพื่อจัดการความซับซ้อนของ business case เฉพาะ

domain model มี​อยู่​เพื่อ​ช่วย​เรา​แก้​ปัญหา​เท่านั้น มัน​จึง​ต้อง ชัดเจน​และ​ปลอด​จาก​ความ​ซับซ้อน​ทาง​เทคนิค เพื่อ​ให้​ทั้ง​ฝั่ง​ธุรกิจ​และ​ฝั่ง​พัฒนา​ออกแบบ​มัน​ร่วม​กัน​ได้

Analysis ModelAnalysis Modelmodel เชิง​วิเคราะห์ — ภาพ​การ​ออกแบบ​เชิง​ตรรกะ​และ​โครงสร้าง​ของ​ซอฟต์แวร์​ที่​คน​ไม่ใช่​สาย​เทคนิค​ก็​เข้าใจ​ได้ (เช่น ภาพร่าง​หรือ UML) ใน DDD จะ​ถูก​ผูก​เข้า​กับ code model ผ่าน Ubiquitous LanguageStrategic Design (บางที​เรียก business model) คือ​กลุ่ม​ของ artifact ที่​อธิบาย model ของ​ระบบ — ตั้งแต่​ภาพร่าง​หลัง​ซอง​จดหมาย​ไป​จนถึง UML แบบ​ไม่​เป็น​ทางการ มัน​มี​อยู่​เพื่อ​ช่วย​ให้​ทั้ง​สอง​ฝ่าย​เข้าใจ problem domain ตรง​กัน ไม่ใช่​พิมพ์เขียว​สำหรับ implement

DDD ไม่​ได้​บอก​ให้​ทิ้ง analysis model — ตรง​กัน​ข้าม มัน​มี​คุณค่า​มาก แต่ DDD เน้น​ให้ Code ModelCode Modelmodel ใน code — การ​แสดงออก​ของ domain model ใน code จริง DDD ถือว่า code model คือ “การ​แสดงออก​หลัก” (primary expression) ของ domain model ไม่ใช่​ไดอะแกรม​หรือ​เอกสารStrategic Design (ตัว implementation จริง) อยู่​ใน synergy ใกล้​ชิด​กับ analysis model โดย​ให้​ทั้ง​คู่​อธิบาย​ด้วย UL ร่วม​กัน

รูปที่ 4-3: code model (ฝั่ง C#) และ analysis model (ฝั่ง UML) ถูกผูกเข้าด้วยกันด้วย Ubiquitous Language ที่อยู่ตรงกลาง — การสื่อสารเกิดขึ้นได้เพราะภาษากลางนี้

code คือ model, code คือ​ความ​จริง

code model คือ การ​แสดงออก​หลัก (primary expression) ของ domain model หาก implement แล้ว​พบ​ว่า​ตรรกะ​ไม่​ลงตัว นั่น​คือ​สัญญาณ​ว่า analysis model มี​จุด​บกพร่อง — จง​กลับ​ไป​คุย​กับ domain expert แล้ว​แก้​ทั้ง2 model ให้​ตรง​กัน​เสมอ “the code is the model; the code is the truth”


Model-Driven Design คือ​กระบวนการ พิสูจน์ model ด้วย​การ​ลงมือ​ทำ​จริง — เพราะ​การ​มี model สวย​หรู​ที่ implement ไม่​ได้​นั้น​ไร้​ความหมาย มัน​ต่าง​จาก DDD ตรง​ที่ MDD โฟกัส​ที่ implementation และ​ข้อ​จำกัด​ทาง​เทคนิค​ที่​อาจ​บังคับ​ให้​ต้อง​แก้ model ส่วน DDD โฟกัส​ที่​ภาษา การ​ร่วมมือ และ​ความ​รู้​ของ domain — ทั้ง​สอง​เสริม​กัน

Specification คือ​อะไร

ระหว่าง​ทาง คุณ​จะ​เจอ specification บ่อยๆ มัน​คือ object ที่​แทน​กฎ​ธุรกิจ​หนึ่ง​ข้อ ซึ่ง​บาง​ส่วน​ของ domain model ต้อง​ทำให้​เป็น​จริง และ​ยัง​ใช้​เป็น​เงื่อนไข​ใน​การ query ได้​ด้วย เช่น “หา​ทุก object ที่​ตรง​ตาม specification นี้”

ใน​อดีต การ​เก็บ requirement ถูก​มอง​เป็น​กิจกรรม​ที่​ทำ​เสร็จ​ก่อน​เริ่ม​เขียน code นานๆ: business expert คุย​กับ business analyst → analyst คุย​กับ architect → architect ปั้น analysis model แล้ว​ส่ง​ต่อ​ให้ developer พร้อม wireframe ไป​สร้าง​ระบบ

ปัญหา​คือ​เมื่อ developer เริ่ม implement พวก​เขา​มัก​เจอ​ช่องว่าง​ระหว่าง artifact ระดับ​สูง​กับ​ความ​จริง​ของ​การ​สร้าง​ระบบ — และ​มัก​ไม่มี feedback loop ให้​กลับ​ไป​คุย​กับ​ธุรกิจ ผล​คือ code ค่อยๆ เบน​ออก​จาก analysis model จน​คำ​ศัพท์​และ​แนวคิด​สำคัญ​ของ domain หล่น​หาย

รูปที่ 4-4: ปัญหาของ upfront design — analysis model (iteration 0) ถูกส่งต่อให้ทีมพัฒนา แล้ว code model ค่อยๆ เบนออกในแต่ละ iteration จนถึง iteration 4 ที่ code model ไม่สะท้อน analysis model อีกต่อไป และ analysis model กลายเป็นของไร้ค่า

ปัญหา​จะ​เผย​ตัว​ตอน​ที่​การ​เพิ่ม feature ใน​อนาคต​เริ่ม​ทำได้​ยาก เพราะ​ธุรกิจ​กับ developer ต่าง​ถือ “model คนละ​ตัว” อยู่​ใน​หัว code จึง​ขาด synergy กับ​กระบวนการ​ธุรกิจ และ​ไม่​อุดม​ด้วย​ความ​รู้​ของ domain

กับดัก: architect ที่​ไม่​เขียน code

ถ้า​คุณ​เป็น​คน​ปั้น analysis model หรือ code model คุณ​ต้อง​ลงมือ​เขียน code ด้วย DDD เปิด​ที่ทาง​ให้ architect แต่ architect คน​นั้น ต้อง​เป็น​คน​ที่ code เป็น — ไม่​เช่น​นั้น analysis model จะ​หลุด​จาก​ความ​จริง​ของ implementation

DDD เสนอ​วิธี​ที่​ร่วมมือ​กัน​มากกว่า: เน้น​ให้ ทั้ง​ทีม — developer, tester, business analyst, architect และ business expert — ทำงาน​เป็น​หนึ่ง​เดียว​ใน knowledge-crunching sessions

หัวใจ​ของ​การ model ร่วม​กัน​คือ feedback ที่​ไหล​เวียน​อย่าง​ต่อ​เนื่อง จาก business expert ซึ่ง​นำ​ไป​สู่​การ​ค้น​พบ​แนวคิด​สำคัญ และ​ช่วย​ให้​ทีม​เห็น​ชัด​ว่า​อะไร “ไม่​สำคัญ” แล้ว​ตัด​ออก​จาก model ได้ จุด breakthrough มัก​มา​ใน​รูป​ของ abstraction เรียบ​ง่าย​ที่​ทำให้​แนวคิด​อัน​ซับซ้อน​กระจ่าง​ขึ้น​ใน​พริบตา

รูปที่ 4-6: team modeling — code model และ analysis model หมุนวนอยู่ใน synergy เดียวกัน การ knowledge crunch, feedback และความร่วมมืออย่างต่อเนื่องช่วยปั้นทั้ง2 model ไปพร้อมกัน การเปลี่ยน model หนึ่งย่อมทำให้อีก model เปลี่ยนตาม

🚢 ตัวอย่าง — ค้น​พบ Route Specification จาก​การ model ร่วม​กัน

ใน​ระบบ​ขนส่ง​สินค้า ทีม​และ domain expert พูด​คุย​กัน​ผ่าน​ภาพ​และ​ตัวอย่าง​จริง จน​พบ​ว่า “ความ​ต้องการ​ของ​ลูกค้า” (ต้นทาง ปลายทาง กำหนด​เวลา​ถึง) เป็น​แนวคิด​ที่​ควร​มีชื่อ​เรียก​ชัดเจน — จึง​เกิด​เป็น Route SpecificationRoute SpecificationValue Object ที่​ระบุ “ความ​ต้องการ​ของ​ลูกค้า”: ต้นทาง ปลายทาง และ​กำหนด​เวลา​ถึง — มี method isSatisfiedBy() ตรวจ​ว่า​แผน​เดินทาง​ตรง​ตาม​นี้​หรือ​ไม่Tactical Design ขึ้น​ใน UL

แนวคิด​นี้​ไม่​ได้​โผล่​มา​จาก wireframe แต่ ผุด​ขึ้น​ระหว่าง​การ model ร่วม​กัน แล้ว​ถูก​ป้อน​กลับ​ให้ domain expert ยืนยัน นี่​คือ team modeling ใน​การ​ทำงาน​จริง


คุณค่า​ที่แท้​จริง​ของ​การ​ทำ​ตาม​ปรัชญา DDD อยู่​ที่​การ​ร่วมมือ​กัน​ระหว่าง developer และ domain expert เพื่อ​เข้าใจ domain ให้​ลึก​ขึ้น — code เป็น​เพียง artifact ของ​กระบวนการ​นั้น และ​สิ่ง​ที่​จะ อยู่​ยง​คงกระพัน​แม้ code จะ​ถูก​เขียน​ใหม่ คือ Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design

ภาษา​จะ​อยู่​ยืนยาว​กว่า​ซอฟต์แวร์​ของ​คุณ — มัน​นิ​ยามชัดๆ ว่า​ธุรกิจ​ทำ​อะไร เผย​ให้​เห็น insight ที่​ลึก​ขึ้น​ของ​กระบวนการ และ​ทำให้การ​สื่อสาร​ทาง​ธุรกิจ​ดี​ขึ้น

ทุก domain มี “ภาษา​ลับ” ของ​มัน — ช่างไม้ เทรดเดอร์การเงิน ทหาร หรือ​แม้แต่​ร้าน​ขาย​ผ้า​ม่าน (pleated, hang length, interlining) ล้วน​มี​คำ​เฉพาะ​ที่​ทำให้​คุย​เรื่อง​ซับซ้อน​ได้​กระชับ ทีม​พัฒนา​ต้อง​เข้าใจ​และ​ร่วม​สร้าง​ภาษา​นี้ แล้ว​ใช้​มัน ตั้ง​ชื่อ class, method และ namespace ใน code ด้วย

ถ้า developer ไม่​ใช้​ภาษา​ของ​ธุรกิจ พวก​เขา​จะ​สร้าง​ภาษา​และ abstraction ของ​ตัวเอง​ขึ้น​มา​แทน ผล​คือ​ต้อง​คอย “แปล” จาก​แนวคิด domain ไป​เป็น​แนวคิด​เชิง​เทคนิค​อยู่​ตลอด — ซึ่ง​ทั้ง​ช้า สิ้น​เปลือง และ​ผิดพลาด​ง่าย และ​ทุก​ครั้ง​ที่​แปล insight สำคัญ​ของ domain ก็​มี​โอกาส​หล่น​หาย​ไป โดย​เฉพาะ​เมื่อ​คน​เขียน code กับ domain expert ถือ model กัน​คนละ​ตัว

คนละ model ใน​หัว = bug

เมื่อ developer คิด​ด้วย “technical abstraction และ design pattern” ขณะ​ที่ domain expert คิด​ด้วย “กระบวนการ​ธุรกิจ” บทสนทนา​ย่อม​เดิน​สวน​ทาง​กัน และ​ทุก​ครั้ง​ที่​ทีม​แปล​ตรรกะ​ซับซ้อน​คลาดเคลื่อน bug ก็​แทรก​ตัว​เข้า code ได้​ทันที — ทางออก​คือ developer ต้อง​คิด​ด้วย​คำ​ของ domain ไม่ใช่​คำ​ทาง​เทคนิค


ภาษา​ที่​ธุรกิจ​ใช้​คือ “วัตถุดิบ” อย่าง​หนึ่ง​ของ UL แต่​ตอน​สร้าง model และ implement ลง code คุณ​อาจ​ต้อง สร้าง​แนวคิด​และ​คำ​ใหม่ ด้วย ทีม​ต้อง​ไม่​เพียง​เรียน​คำ​ที่​ธุรกิจ​พูด​ออก​มาชัดๆ แต่​ต้อง​ช่วย​กัน ตั้ง​ชื่อ​ให้​แนวคิด​ที่​ซ่อน​อยู่ (implicit) ซึ่ง​ยัง​ไม่มี​คำ​เรียก แล้ว​นำ​เข้า UL ร่วม​กัน

วิธี​ที่​ดี​คือ​หยิบ​ตัวอย่าง​กระบวนการ​ธุรกิจ​จริง​มา​พูด​คุย​กัน โดย​ต้อง​เผย เจตนา​ของ​กระบวนการ​ธุรกิจ ไม่ใช่​วิธี implement ลอง​ดู​คำ​อธิบาย​แบบ​ที่ business user มัก​พูด:

ลูกค้า​ที่​ไม่​ได้​รับ​ของ​จะ login เข้า​บัญชี กด​ปุ่ม “ฉัน​ยัง​ไม่​ได้​รับ​สินค้า” ถ้า​ระบบ flag ไว้​แล้ว​ว่า​เคย​ได้​ของ​ฟรี ก็​ขอ​อีก​ไม่​ได้​จนกว่า​จะ​คุย​กับ customer service ไม่​งั้น​เรา​จะ​ส่ง​ของ​ฟรี​ให้​แล้ว​อัปเดต database…

สังเกต​ว่า​ประโยค​นี้​เต็ม​ไป​ด้วย “วิธี implement” (login, กด​ปุ่ม, อัปเดต database, flag) ซึ่ง​ไม่​ได้​เผย insight ใดๆ เกี่ยว​กับ domain เลย หาก​ทีม​ละเลย domain แล้ว implement ตาม​คำ​บอกนั้นตรงๆ สิ่ง​ที่​ได้​ก็​คือ model ที่​อ่อนแอ​และ​ไร้​ความหมาย​เชิง​ธุรกิจ

ลอง​เขียน​ใหม่​ด้วย​ภาษา​ของ domain ที่​โฟกัส​ที่​กระบวนการ​ธุรกิจ:

ถ้า​คุณ​ไม่​ได้​รับคำ​สั่ง​ซื้อ คุณ​ส่ง “undelivered order notification” ได้ ถ้า​เป็นการ​เคลม​ครั้ง​แรก ระบบ​จะ​สร้าง “replacement order” ให้ ถ้า​เคย​เคลม​มา​ก่อน จะ​เปิด “claim case” มอบหมาย​ให้​เจ้าหน้าที่​สอบสวน และ​ทุก​กรณี​จะ​เปิด “lost mail compensation case” ส่ง​ให้​บริษัท​ขนส่ง

คำ​อธิบาย​ใหม่​นี้​เผย​แนวคิด​สำคัญ​ที่​หาย​ไป​ก่อนหน้า — UndeliveredOrderNotification, ReplacementOrder, ClaimCase, LostMailCompensationCase ล้วน​เป็น​คำ​ที่​ควร​เข้า UL และ​น่า​สังเกต​ว่า​มัน​ไม่มี​คำ​ว่า “customer” หรือ “ปุ่ม” หรือ “database” เลย

สอน domain expert ให้​โฟกัส​ที่​ปัญหา ไม่ใช่​กระโดด​ไป​หา​คำ​ตอบ

domain expert ส่วน​ใหญ่​ไม่​คุ้น​กับ​ศัพท์​เทคนิค เมื่อ​พวก​เขา​พยายาม​ช่วย​ด้วย​การกระโดด​ไป​ที่ implementation ให้​ค่อยๆ ชวน​กลับ​มา​โฟกัส​ที่ what และ why ของ​ระบบ ส่วน how นั้น​ปล่อย​ให้​เป็น​หน้าที่​ของ​ทีม​พัฒนา

  • รักษา​ความ​สอดคล้อง​ทาง​ภาษา — ถ้า​ใช้​คำ​ใน code ที่ domain expert ไม่​เคย​พูด ต้อง​ไป​เช็ก อาจ​เป็น​แนวคิด​ใหม่​ที่​ต้อง​เพิ่ม​เข้า UL หรือ​อาจ​เป็น​เพราะ​คุณ​เข้าใจ​ผิด
  • ทำ glossary ของ​คำ​ใน domain ร่วม​กับ domain expert
  • หนึ่ง​แนวคิด หนึ่ง​คำ — อย่า​ให้​มี​สอง​คำ​เรียก​สิ่ง​เดียวกัน
  • เลี่ยง​คำ​กว้าง​เกิน​ไป อย่าง policy, service, manager — ชื่อ​ที่​ยาว​ขึ้น​แต่​สื่อ​ความ​ชัดเจน​ย่อม​ดี​กว่า
  • อย่า​ใช้​ชื่อ design pattern ใน model — decorator หรือ factory มี​ความหมาย​ต่อ business user ไหม? GoF pattern อาจ​ทำให้​สับสน
  • UL ต้อง​ปรากฏ​ทุก​ที่ ตั้งแต่ namespace ถึง class ถึง​ชื่อ method และ​ตั้ง​ชื่อ exception ด้วย​คำ​ของ UL
  • UL จะ​วิวัฒน์ เมื่อ​คุณ​เข้าใจ domain ลึก​ขึ้น — refactor code ให้​สะท้อน​ชื่อ​ที่​เผย​เจตนา​มาก​ขึ้น ถ้า​เจอ​กลุ่ม​ตรรกะ​ซับซ้อน​ก่อ​ตัว ลอง​คุย​กับ domain expert แล้ว​แยก​ออก​เป็น specification หรือ policy class
พิสูจน์ model ด้วย​การ​พูด​ออก​เสียง

ความ​สอดคล้อง​ทาง​ภาษา​คือ​เครื่อง​วัด​ว่า model ใช้ได้​จริง​หรือ​ไม่ ลอง​ฟัง​บทสนทนา​เกี่ยว​กับ model แล้ว​จับ​แนวคิด​ที่ “ไม่​ลงตัว” หรือ​พูด​ออก​มา​แล้ว​สะดุด​ลิ้น — “query ถูก​ส่ง​ไป cache แล้ว match user ด้วย regex เพื่อ​ดู​ว่า​ได้​ส่วนลด​ไหม” business user เข้าใจ​ประโยค​นี้​หรือ​ไม่? ถ้า​ไม่ ก็​แปล​ว่า model ยัง​ไม่​ได้​พูด​ภาษา​ของ domain


domain model ที่​รวย​พฤติกรรมRich Domain Modelmodel domain ที่ “รวย​พฤติกรรม” — object ที่​เก็บ​ทั้ง​ข้อมูล​และ business logic ไว้​ด้วย​กัน เป็น​คู่​ตรง​ข้าม​ของ Anemic Domain Model (ที่​มี​แต่ getter/setter แล้ว​ผลัก logic ไป​ไว้​ที่​อื่น) tactical patterns ของ DDD จะ​คุ้ม​ค่า​ก็​ต่อ​เมื่อ model “รวย” พอ​เช่น​นี้Tactical Design สร้าง​ขึ้น​เพื่อ​แก้​ปัญหา​ยากๆ ดังนั้น​ให้​โฟกัส​ที่​ส่วน​สำคัญ​ต่อ​ธุรกิจ — มอง​ข้าม​ส่วน​ที่​เป็น​แค่​การ​จัดการ​ข้อมูล (CRUD) แล้วไป​จับ “ส่วน​ที่​ยาก” ใน core domain ที่ธุรกิจให้ความสำคัญจริงๆ ซึ่ง​มัก​เป็น​จุด​ที่​สร้าง​รายได้​หรือ​ลด​ต้นทุน

ความ​เข้าใจ​ผิด​ที่​พบ​บ่อย​คือ domain model ต้อง​เหมือน​ชีวิต​จริง — ไม่​จริง อย่า​พยายาม​จำลอง​ชีวิต​จริง แต่​จง model abstraction ที่​มี​ประโยชน์ ภายใน problem domain มอง​หาความ​เหมือน​และ​ความ​แตก​ต่าง พิจารณา​ว่า​ส่วน​ไหน​มี​แนวโน้ม​จะ​เปลี่ยนแปลง​และ​ซับซ้อน แล้ว​ใช้​ข้อมูล​นั้น​สร้าง model — วิธี​นี้​ได้​ผลกว่าการ​ไล่​ล่า “คำ​นาม/คำ​กริยา” จาก​โลก​จริง​มา​แปะ​ลง model มาก

แผนที่​รถไฟ​ใต้ดิน​ลอนดอน​เป็น​ตัวอย่าง​คลาสสิก: มัน​ถูก​ออกแบบ​มา​เพื่อ​แก้​ปัญหา​หนึ่ง — มัน​ไม่​สะท้อน​ระยะ​ทาง​จริง​ระหว่าง​สถานี และ​คำนวณ​ระยะ​ทาง​บน​ดิน​ไม่​ได้ แต่​มัน มี​ประโยชน์​มาก​สำหรับ​การ​เดินทาง​ใต้ดิน เพราะ​มัน​เรียบ​ง่าย​และ​ได้​ผล​ใน context ที่​มัน​ถูก​ออกแบบ​มา

model ไม่มี​ถูก​หรือ​ผิด มี​แต่ ‘มี​ประโยชน์’ หรือ ‘ไม่’

เพราะ domain model ไม่​ได้​มุ่ง​จำลอง​ชีวิต​จริง เรา​จึง​ตัดสิน​มัน​ว่า “ถูก/ผิด” ไม่​ได้ — วัด​ได้​เพียง​ว่า​มัน มี​ประโยชน์​หรือ​ไม่ ต่อ​ปัญหา​ที่​มัน​ถูก​สร้าง​ขึ้น​มา​แก้

  • model เฉพาะ​สิ่ง​ที่​เกี่ยวข้อง — ธุรกิจ​ใหญ่​และ​ซับซ้อน อย่า​พยายาม​ยัด​ทุก​อย่าง​ลง model เดียว ถ้า​ระบบ​ใหญ่ ให้​แบ่ง​เป็น​ส่วน​ย่อย​ที่​จัดการ​ได้
  • อย่า model ความ​สัมพันธ์​จริง — ให้​นิยาม association ใน​แง่​ของ InvariantInvariantกฎ​ทาง​ธุรกิจ​ที่ “ต้อง​เป็น​จริง​เสมอ” ภายใน Aggregate เช่น ยอด​รวม​คำ​สั่ง​ซื้อ​ต้อง​เท่ากับ​ผล​รวม​ของ​รายการ​สินค้า — ต้อง​ถูกต้อง​ภายใน transaction เดียวTactical Design และ​กฎ​ของ​ระบบ​แทน (ใน​ชีวิต​จริง​ลูกค้า​มี​ทั้ง credit history และ​อีเมล แต่​จะ​มี​กฎ​ไหน​บังคับ​ว่า “ต้อง credit ดี​และ​อีเมล​ขึ้น​ต้น​ด้วย A ถึง​ซื้อ​ของ​ได้”?)
  • model มี​ประโยชน์​เพียง​ชั่วคราว — model หนึ่งๆ ใช้ได้​แค่​กับ iteration และ​ชุด use case ช่วง​หนึ่ง​เท่านั้น อย่า​หลง​รัก model ที่​สวยงาม จง​พร้อม “โยน​ทิ้ง​แล้ว​เริ่ม​ใหม่” (throw away) เมื่อ​มัน​ไม่​เกี่ยวข้อง​อีก​ต่อ​ไป
  • จำกัด abstraction — abstraction มี​ต้นทุน (ก่อ​ให้​เกิด dependency และ coupling) จึง​ควร​สร้าง​เฉพาะ​เมื่อ​แนวคิด​นั้น​มี “ความ​แตก​ต่าง (variation)” จริงๆ เท่านั้น และ​พึง​เลือก​ความ​ชัดเจน​ไว้​ก่อน​การ​เลี่ยง code ซ้ำ (DRY)
  • abstract ที่​พฤติกรรม ไม่ใช่ implementation — interface ควร​แทน​แนวคิด​ของ domain เช่น IShippingNoteGenerator (มี variation เป็น domestic/international) แต่ courier gateway เป็น​เรื่อง infrastructure ไม่ใช่​พฤติกรรม domain — เก็บ​มัน​ให้​เป็น concrete นอก model
  • implement ลง code เร็ว​และ​บ่อย — ทดสอบ design กับ domain scenario เพื่อ​เจอ​ข้อ​จำกัด​ทาง​เทคนิค​ที่​อาจ​บังคับ​ให้​แก้ model
  • อย่า​หยุด​ที่​ไอเดีย​ดี​อัน​แรก — หยุด model ต่อ​เมื่อ “หมด​ไอเดีย” ไม่ใช่​ตอน​ได้​ไอเดีย​ดี​อัน​แรก ลอง​แก้​ปัญหา​ด้วย model ที่​ต่าง​ไป​โดย​สิ้นเชิง
แยก​พฤติกรรม​ที่​มี variation ออก​เป็น abstraction
// ✅ abstraction ที่แทน "แนวคิด" ของ domain ที่มี variation จริง
public interface IShippingNoteGenerator {
ShippingNote Generate(Order order);
}
public class DomesticShippingNoteGenerator : IShippingNoteGenerator { /* ... */ }
public class InternationalShippingNoteGenerator : IShippingNoteGenerator { /* เอกสารต่างกัน */ }
// ❌ อย่า abstract courier gateway — มันเป็น infrastructure ไม่ใช่พฤติกรรม domain
// public interface ICourierGateway { ... } // เก็บไว้นอก domain model เป็น concrete

ปัญหา​ง่ายๆ ไม่​ต้องการ​คำ​ตอบ​ซับซ้อน — คุณ​ไม่​จำเป็น​ต้อง​สร้าง UL ให้​ทั้ง app จง​ทุ่ม​แรง​ร่วม​กับ domain expert ไป​ที่ core domain ที่​ซับซ้อน​และ​สำคัญ ส่วน genericGeneric Subdomainปัญหา​ที่​แก้​กัน​มา​แล้ว​ทั่วไป เช่น ระบบ login บัญชี การ​แจ้ง​เตือน — ควร​ใช้​ของ​สำเร็จรูป​หรือ library แทน​การ​เขียน​เองStrategic Design / supporting subdomainSupporting Subdomainส่วน​ที่​จำเป็น​และ​เฉพาะ​กับ​ธุรกิจ​เรา แต่​ไม่ใช่​จุด​ที่​สร้าง​ความ​ได้​เปรียบ ไม่มี​ของ​สำเร็จรูป​ที่​พอดี จึง​ต้อง​ทำ​เอง แต่​ลงทุน​น้อย​กว่า coreStrategic Design ที่​ไม่มี domain logic นั้น​ไม่​ควร​เสียแรง เพราะ​จะ​บั่นทอน​ความ​ร่วมมือ​ของ domain expert จน​เขา​ไม่​อยาก​ช่วย​ใน​ส่วน​ที่​ยากจริงๆ

🚢 ตัวอย่าง — เลือก​ลงแรง​เฉพาะ core

ใน​ระบบ​ขนส่ง การ routing และ tracking สินค้า​คือ core domain ที่​ควร​ลงทุน​สร้าง rich model และ UL อย่าง​เต็ม​ที่ (Route SpecificationRoute SpecificationValue Object ที่​ระบุ “ความ​ต้องการ​ของ​ลูกค้า”: ต้นทาง ปลายทาง และ​กำหนด​เวลา​ถึง — มี method isSatisfiedBy() ตรวจ​ว่า​แผน​เดินทาง​ตรง​ตาม​นี้​หรือ​ไม่Tactical Design, ItineraryItineraryValue Object ที่​เป็น “แผนการ​เดินทาง​จริง” ของ Cargo ประกอบ​ด้วย​ลำดับ​ของ Leg (ช่วง​การ​ขนส่ง​แต่ละ​ช่วง)Tactical Design, Handling EventHandling Eventการ​บันทึก​การ​จัดการ​สินค้า​จริง (LOAD, UNLOAD, RECEIVE, CLAIM) เป็น Aggregate “แยก​ต่างหาก” จาก Cargo เพราะ​มี​ปริมาณ​มาก​และ​ต้อง​ประมวล​ผล​แบบ asyncTactical Design)

แต่​ระบบ login, การ​ส่ง​อีเมล​แจ้ง​เตือน, หรือ​รายงาน CRUD ธรรม​ดาๆ เป็น generic/supporting — ใช้​ของ​สำเร็จรูป​หรือ​เขียน​แบบ​เรียบ​ง่าย​ก็​พอ ไม่​ต้อง​เปลือง knowledge-crunching session ไป​กับ​มัน

ถาม​ตัวเอง​เสมอ​ว่า: “ฉัน​อยู่​ใน core subdomain หรือ​เปล่า? ปัญหา​นี้​ต้อง​ใช้ rich domain ไหม? ธุรกิจ​ให้​ความ​สำคัญ​กับ​ส่วน​นี้​จริง​ไหม? หรือ​เขา​เพียง​อยาก​ให้​มัน​ทำงาน​ได้?” และ​ถ้า​เจอ edge case ที่​ยุ่งยาก​ใน​ส่วน​ที่ ไม่ใช่ core — ให้​พิจารณา​ทำ​เป็น กระบวนการ​แบบ manual เพราะ​มนุษย์​รับมือ edge case ได้​ดี และ​ช่วย​ให้​คุณ​สงวน​แรง​ไว้​ทุ่ม​กับ core domain

การ​สร้าง UL มี​ต้นทุน​สูง

core domain นั้น​เล็ก — จง​โฟกัส​พลัง​ทั้งหมด​ไป​ที่​มัน อย่า​พยายาม​สร้าง​ภาษา​ที่ rich ให้​ทั้ง domain เพราะ supporting/generic subdomain ส่วน​ใหญ่​ไม่​ได้​ประโยชน์​จาก UL การ​เกลี่ย​แรงบางๆ ไป​ทั่ว​ทุก​ที่​มี​แต่​จะ​สูญเปล่า


หัวใจ​ของ​บท​นี้

Model-Driven Design = ผูก Analysis ModelAnalysis Modelmodel เชิง​วิเคราะห์ — ภาพ​การ​ออกแบบ​เชิง​ตรรกะ​และ​โครงสร้าง​ของ​ซอฟต์แวร์​ที่​คน​ไม่ใช่​สาย​เทคนิค​ก็​เข้าใจ​ได้ (เช่น ภาพร่าง​หรือ UML) ใน DDD จะ​ถูก​ผูก​เข้า​กับ code model ผ่าน Ubiquitous LanguageStrategic Design เข้า​กับ Code ModelCode Modelmodel ใน code — การ​แสดงออก​ของ domain model ใน code จริง DDD ถือว่า code model คือ “การ​แสดงออก​หลัก” (primary expression) ของ domain model ไม่ใช่​ไดอะแกรม​หรือ​เอกสารStrategic Design ให้​เป็น model เดียวกัน โดย​มี Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design เป็น​กาว​ยึด — “code คือ model, code คือ​ความ​จริง” domain model คือ abstraction ที่​มี​ประโยชน์ ไม่ใช่​ภาพ​จำลอง​ชีวิต​จริง และ​จะ​คุ้ม​ค่าที่​จะ​ลงแรง​ทำ MDD + UL ก็​ต่อ​เมื่อ​ทำ เฉพาะ​กับ core domain เท่านั้น


🔗 อ้างอิง​เพิ่มเติม​ใน DevIQ

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

  • Domain Model — นิยาม​และ​ตัวอย่าง​ของ domain model ใน​ฐานะ abstraction ที่​มี​ประโยชน์ ไม่ใช่​ภาพ​จำลอง​ชีวิต​จริง ตรง​กับ​ใจความ​หลัก​ของ​บท​นี้
  • Ubiquitous Language — ขยาย​ความ​ว่า​ทำไม UL คือ​กาว​ที่​ผูก analysis model กับ code model เข้า​ด้วย​กัน และ​จะ​สร้าง​มัน​ร่วม​กับ​ทีม​อย่างไร
  • Specification — รายละเอียด​ของ pattern ที่​บท​นี้​แนะนำ​ไว้สั้นๆ สำหรับ​ห่อ​กฎ​ธุรกิจ​ให้​เป็น object ที่​ตรวจสอบ​และ query ได้
  • Anemic Domain Model — ภาพ​ตรง​ข้าม​ของ rich domain model ที่​บท​นี้​ตั้ง​เป้าหมาย​ไว้ ช่วย​ให้​เห็น​ชัด​ว่า model แบบ​ไหน​ที่​ควร​หลีก​เลี่ยง
  • Subdomain — อธิบาย​ความ​ต่าง​ระหว่าง core กับ generic/supporting subdomain ที่​บท​นี้​ใช้​ตัดสิน​ใจ​ว่า​ควร​ทุ่ม​แรง​ทำ MDD + UL ตรง​ไหน

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

ข้อ 1 / 4

Model-Driven Design มีเป้าหมายหลักคืออะไร?