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

ลงมือ​ใช้ DDD จริง — หลักการ แนว​ปฏิบัติ และ pattern

เก้า​บท​ที่​ผ่าน​มา​คุณ​ได้​เห็น “ปรัชญา” ของ DDDDomain-Driven Design (DDD)แนวทาง​พัฒนา​ซอฟต์แวร์​ที่​เน้น​สร้าง domain model ซึ่ง​เข้าใจ​กฎ​และ​กระบวนการ​ของ​ธุรกิจ​อย่าง​ลึกซึ้ง แล้ว​เขียน​ลง​ใน code จริง บัญญัติ​โดย Eric Evans (2003) แบ่ง​เป็น Strategic และ Tactical DesignStrategic Design มา​ครบ​แล้ว บท​นี้​จะ​รวบ​ทุก​อย่าง​เข้า​ด้วย​กัน​เป็น​คำ​ตอบ​ของ​คำถาม​ที่​สำคัญ​ที่สุด — “แล้ว​จะ​เริ่ม​ใช้​กับ project ถัด​ไป​ยังไง?” ส่วน​ที่​เหลือ​ของ​หนังสือ (Part II–IV) จะ​เจาะ coding pattern แต่​บท​นี้​คือ “แผนที่​กระบวนการ” ที่​บอกว่า​ควร​หยิบ practice ไหน​มา​ใช้​เมื่อไร

หัวใจ​ของ​บท​นี้​สรุป​ได้​ใน​ประโยค​เดียว: เริ่ม​จาก​สิ่ง​ที่​ง่าย​ที่สุด​เสมอ ทำ​แบบ​เรียบ​ง่าย​ไป​ก่อน​จนกว่า​จะ​เจอ​ความ​ซับซ้อน​หรือ​ความ​กำกวม​ที่แท้​จริง แล้ว​ค่อย refactor เข้าหา pattern ของ DDD ที​ละ​ขั้น อย่า​เอา​ปืนใหญ่​ยิง​นก (don’t crack a nut with a sledgehammer)


DDD ไม่ใช่​กระสุน​เงิน (silver bullet) และ​อย่า​ขาย​มัน​แบบ​นั้น เช่น​เดียว​กับ​ที่ agile ไม่​ได้​แก้​ทุก​ปัญหา DDD ก็​เช่น​กัน — แต่​มัน​ทรง​พลัง​มาก เมื่อ​ใช้​ถูก​สถานการณ์ สถานการณ์​ที่​เหมาะ​คือ

  • ทีม​ที่​เก่ง มีไฟ และ​อยาก​เรียนรู้
  • problem domain ที่​ไม่​ธรรมดา และ สำคัญ​ต่อ​ธุรกิจ
  • เข้าถึง domain expert ที่​เห็น​ภาพ​เดียว​กับ​วิสัยทัศน์​ของ project ได้
  • ทีม​ทำงาน​แบบ iterative

หาก​ขาด​วัตถุดิบ​เหล่า​นี้ การ​ฝืน​ใช้ DDD จะ​ทำให้​งาน ซับซ้อน​ขึ้น แทนที่​จะ​ง่าย​ลง

ขาย DDD ที่​ตัว​คุณค่า ไม่ใช่​ที่ pattern

เวลา​สื่อสาร DDD กับ​ทีม อย่า​เริ่ม​ที่ pattern language แต่​ให้​เน้น การ align กับ​ธุรกิจ ความ​สำคัญ​ของ strategic context และ​การ​ให้​น้ำหนัก​กับ ภาษา ที่​ใช้​อธิบาย model — strategic DDD ทรง​พลัง​กว่า tactical pattern มาก ทีม​ที่​หมกมุ่น​อยู่​แต่ software pattern จะ​จ่าย​ต้นทุน​ของ DDD ไป​เต็มๆ โดย​ไม่​ได้​รางวัล​ของ​มัน​กลับ​มา​เลย

ส่วน​เวลา​คุย​กับ ฝ่าย​ธุรกิจ อย่า​ไป​พูด​เรื่อง​ปรัชญา​การ​พัฒนา​ตัว​ใหม่ stakeholder ไม่​อยาก​ฟัง​คำ​ว่า agile, SOA หรือ cloud อีก​แล้ว — เพราะ​ทุก​อย่าง​ถูก​โฆษณา​เกิน​จริง​มา​หมด พูด​เพียง​สิ่ง​เดียว​ก็​พอ: “เรา​อยาก​เข้าใจ​ธุรกิจ​ของ​คุณ​ให้​ลึก​ขึ้น เพื่อ​ส่ง​มอบ​คุณค่า​ได้​มาก​ขึ้น” แล้ว​อธิบาย​ว่า​ทำไม​ทีม​พัฒนา​จึง​ต้อง​ใช้​เวลา​กับ​ผู้เชี่ยวชาญ​ธุรกิจ นี่แหละ​คือ​วิธี​ขาย DDD ที่แท้​จริง เพราะ DDD ไม่​ทำงาน​เลย​หาก​ไม่มี commitment จาก domain expert


เมื่อ​ธุรกิจ​เข้าใจ​คุณค่า​ของ​เวลา domain expert และ​ทีม​โฟกัส​ที่​การ​แก้​ปัญหา​รอบๆ model ที่​สร้าง​ร่วม​กัน คุณ​ก็​พร้อม​ลงมือ​แล้ว ลำดับ​ขั้น​ด้าน​ล่าง​นี้​คือ​เส้นทาง​จาก “จุด​เริ่ม project” ไป​สู่ “solution”

ก่อน​จะ​จด​ความ​ต้องการ ต้อง align ทีม​กับ​ความ​คาด​หวัง​ของ stakeholder ก่อน เปิด​ประชุม​ด้วย​คำถาม​ปลาย​เปิด​ที่​ดึง “เหตุผล​ที่​เลือก​สร้าง​เอง​แทน​การ​ซื้อ” ออก​มา เช่น

  • เป้าหมาย/แรง​ขับ​ทาง​ธุรกิจ​ของ​ผลิตภัณฑ์​นี้​คือ​อะไร?
  • มัน​จะ​สร้าง​คุณค่า​อะไร​ให้​ธุรกิจ?
  • เรา​จะ​รู้​ได้​ยังไง​ว่า​มัน​สำเร็จ? “ดี” หน้าตา​เป็น​ยังไง?
  • มัน​ต่าง​จาก​ของ​เดิม​ที่​เคย​มี​ยังไง?

จาก​คำ​ตอบ คุณ​จะ​ระบุ ส่วน​ที่​สำคัญ​ที่สุด ของ​ผลิตภัณฑ์​ได้ แล้ว​เขียน​มัน​ออก​มา​เป็น Domain Vision StatementDomain Vision Statementคำแถลง​วิสัยทัศน์​ของ domain — ข้อความ​สั้น ๆ ที่​จับใจความ​ว่า​อะไร​คือ​หัวใจ​ของ​ความ​สำเร็จ​ของ​ซอฟต์แวร์ เป้าหมาย​ธุรกิจ​คือ​อะไร และ​คุณค่า​อยู่​ตรง​ไหน ใช้​สร้าง​ความ​เข้าใจ​ร่วม​กัน​ใน​ทีม​ว่า​อะไร​คือ coreStrategic Design ที่​ดึง​ทั้ง​ทีม​ไป​สู่​เป้าหมาย​เดียวกัน บาง​ครั้ง​คุณ​อาจ​พบ​ว่า​ผลิตภัณฑ์​นี้จริงๆ แล้ว​เป็น​ของ generic ที่​แค่​ทำ​เอง​คุ้ม​กว่า — ถ้า​ใช่ ก็​พูด​ให้​ชัด

วิธี​ดึง stakeholder เข้า​มา​มี​ส่วนร่วม​ใน​การ​เก็บ requirement ที่​ได้​ผล​คือ Behavior-Driven DevelopmentBehavior-Driven Development (BDD)แนว​ปฏิบัติ​เก็บ requirement เป็น ‘พฤติกรรม’ ของ​ระบบ​ใน​ภาษา​ที่​ธุรกิจ​เข้าใจ มอง​ได้​ว่า​เป็น Ubiquitous Language สำหรับ requirement ช่วย​จับ use case/input/output ที่​จะ​กลาย​เป็น application serviceProcess (BDD) — มอง​ว่า​มัน​คือ Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design สำหรับ requirement สิ่ง​ที่​คุณ​กำลัง​จับ​คือ use case, input และ output ซึ่ง​จะ​กลาย​เป็น Application ServiceApplication Serviceบริการ​ที่ “ประสาน​งาน” use case — จัดการ transaction, ความ​ปลอดภัย, การ​บันทึก, แปลง DTO — แต่​ไม่มี​กฎ​ธุรกิจ​อยู่​ใน​ตัว​มัน​เองTactical Design ของ​คุณ​ใน​ภายหลัง

โฟกัส​ที่​ว่า stakeholder อยาก​ได้​อะไร เมื่อไร และ ทำไม — คำถาม “ทำไม” สำคัญ​ที่สุด เพราะ​มัน​ช่วย​ตรวจสอบ​ว่า​สิ่ง​ที่​เขา​ขอ​นั้น​เขา​ต้องการ​จริง​ไหม ใน​ช่วง​นี้ อยู่​ใน Problem SpaceProblem Space“พื้นที่​ปัญหา” — สิ่ง​ที่​ธุรกิจ​ต้องการ​แก้ไข อยู่​ใน​รูป​ของ Domain และ Subdomain (ยัง​ไม่​พูด​ถึง​วิธี​แก้)Strategic Design เท่านั้น อย่า​รีบ​กระโดด​ไป​หา solution

กับดัก: รีบ​กระโดด​ไป​หา​คำ​ตอบ

หลาย​ทีม​รีบ​ลุย requirement เพราะ​อยาก​ไป​เขียน code เร็วๆ ทั้ง​ที่​ยัง​สำรวจ​ปัญหา​ไม่​พอ บ่อย​ครั้ง stakeholder เอง​ก็​ยัง​ไม่​ชัด​ว่า​ต้องการ​อะไร​แน่ การ​อยู่​ใน problem space ให้​นาน​พอ​จะ​ดึง “ความ​ต้องการ​ธุรกิจ​ที่แท้​จริง” ออก​มา และ​มัก​ทำให้​คุณ​เสนอ​กระบวนการ​ธุรกิจ (business process) ที่​ดี​กว่า​ได้ ก่อน​จะ​เสีย​เวลา​สร้าง solution ให้​กับ​ความ​ต้องการ​ที่​ธุรกิจ​ไม่​ได้​มี​อยู่​จริง

เมื่อ story card เริ่ม​เยอะ​จน​ผลิตภัณฑ์​ใหญ่​เกิน​จะ​จัดการ หรือ​เริ่ม​มี​ความ​กำกวม ให้​ลด​ภาระ​ทาง​ความคิด​ด้วย​การ ยก​ระดับ abstraction โดย​แตก​ออก​เป็น SubdomainSubdomainส่วน​ย่อย​ของ Domain ใหญ่ เช่น Domain e-commerce แตก​เป็น subdomain การ​สั่ง​ซื้อ การ​ชำระ​เงิน คลัง​สินค้า ฯลฯ อยู่​ใน “พื้นที่​ปัญหา” (problem space)Strategic Design วิธี​ที่​ดี​คือ​มอง​หา business capability (กิจกรรม​ที่​หนุน​กระบวนการ​ธุรกิจ) แล้ว​สร้าง subdomain จาก​ตรง​นั้น บาง​อัน​จะ​เป็น generic บาง​อัน​เป็น supporting — แต่​อัน​ที่​ทำให้​ผลิตภัณฑ์​อยู่​หรือ​ตาย​คือ Core DomainCore Domainsubdomain ที่​สำคัญ​และ​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน​มาก​ที่สุด เป็น​เหตุผล​ที่​เรา​ต้อง​สร้าง​ซอฟต์แวร์​เอง​แทน​การ​ซื้อ ควร​ทุ่ม​ทีม​เก่ง​ที่สุด​ลง​ตรง​นี้Strategic Design

เมื่อ​แตก problem space แล้ว ให้​ทุ่ม​เวลา​กับ stakeholder ไป​ที่ กระบวนการ​ธุรกิจ (business process) ของ core domain เป็น​หลัก core domain ของ​คุณ​อาจ​เล็ก​ก็ได้ — ไม่​เป็นไร ขอ​แค่​มัน​สนับสนุน​วิสัยทัศน์​โดยตรง ถ้า​ไม่ คุณ​อาจ​ระบุ core domain ผิด หรือ​ต้อง​กลับ​ไป​ทำ​วิสัยทัศน์​ให้​ชัด​ร่วม​กับ stakeholder


ก่อน​สร้าง solution ใดๆ ต้อง​เข้าใจ​สภาพ​แวดล้อม​ที่​คุณ​จะ​ทำงาน​ด้วย​ก่อน — ระบบ​ที่​ขึ้น production อยู่​แล้ว​มี​อะไร​บ้าง คุณ​จะ integrate กับ​มัน​ยังไง วิธี​ที่​ดี​ที่สุด​ใน​การ​จับ​ภูมิทัศน์​นี้​คือ​การ​วาด Context MapContext Mapแผนภาพ​ที่​แสดง Bounded Context ทั้งหมด​และ​ความ​สัมพันธ์​ระหว่าง​กัน ช่วย​ให้​เห็น​ภาพ​รวม​และ​จุด​เชื่อม​ต่อ/แปล​ภาษา​ใน​ระบบ​ใหญ่Strategic Design

ทีม​ต้อง​ระบุ Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design ต่างๆ ที่​จะ​กระทบ​หรือ​ถูก​กระทบ​โดย​ผลิตภัณฑ์​ของ​คุณ แล้ว​ทำ​ตาม​ขั้นตอน

  1. หา​ว่า​มี model/context ใด​บ้าง​ที่​เกี่ยวข้อง วาด​มัน​ออก​มา ตั้ง​ชื่อ และ​ระบุ​ว่า​ใคร​รับผิดชอบ (ถ้า​ไม่รู้​จะ​เริ่ม​ตรง​ไหน ให้​ดู​โครงสร้าง​องค์กร เพราะ​ระบบ​ส่วน​ใหญ่​สร้าง​ตาม​การ​สื่อสาร​ระหว่าง​แผนก)
  2. map จุด​เชื่อม​ต่อ​และ​วิธี integrate
  3. map ข้อมูล​ที่​แลกเปลี่ยน​กัน และ​ใคร​เป็น​เจ้าของ
  4. ติด​ป้าย​ความ​สัมพันธ์ — ทีม​คุณ​เป็น downstreamUpstream / Downstreamความ​สัมพันธ์​ที่​การกระทำ​ของ​ฝ่าย​ต้นน้ำ (upstream) ส่ง​ผล​ต่อ​ฝ่าย​ปลาย​น้ำ (downstream) แต่​ไม่ใช่​ใน​ทาง​กลับ​กัน — ทิศ​ของ​อิทธิพลStrategic Design ที่​ต้อง​พึ่ง​ทีม​อื่น หรือ​เป็น upstream ที่​ต้อง​แจ้ง​การ​เปลี่ยนแปลง​ให้​ทีม​ปลาย​น้ำ?
🚢 Context Map ของ​ระบบ​ขนส่ง = แผนที่​สงคราม

ใน​ระบบ Cargo Shipping ทีม​จอง​และ​วางแผน​เดินทาง (Booking) ต้อง​คุย​กับ context การ​ติดตาม​สินค้า (Tracking) และ​ระบบ​ศุลกากร/ภาษี​ของ​บุคคล​ที่​สาม ลอง​วาด Context Map ติด​ผนัง​ให้​ทุก​คน​เห็น — นี่​คือ “แผนที่​สงคราม” ของ​ทีม

มัน​ต้อง​เรียบ​ง่าย​พอที่​ใคร​ก็​วาด​ได้​เร็ว อย่า​เสีย​เวลา​ทำ UML ให้​สวยงาม ขอ​แค่​เห็น​ภาพ​มุม​สูง​ก่อน แล้ว​ค่อย​ซูม​เข้าไป​ดู​จุด​เชื่อม​ต่อ​เมื่อ​ถึง​เวลา integrate จริง


ก่อน​จะ​ลงทุน​สร้าง domain model เต็ม​รูปแบบ ส่วน​นั้น​ของ​ผลิตภัณฑ์​ควร​เข้า​เกณฑ์​ครบ

  • เป็น​ปัญหา ซับซ้อน (หรือ​มี​ความ​ซับซ้อน​ใน subdomain นั้น)
  • สำคัญ ต่อ​ธุรกิจ​และ​มี​ความ​คาด​หวัง​สูง
  • มี domain expert ให้​เข้าถึง
  • ทีม​มี​ไฟ​และ​ฉลาด​พอ

ถ้า​ส่วน​ไหน “ไม่​ซับซ้อน” มี​แต่​การ​จัดการ​ข้อมูล​ธรรมดา การ​สร้าง domain model จะ​เกิน​จำเป็น (overkill) — ให้​ใช้​วิธี​ที่​ง่าย​กว่า​อย่าง Transaction ScriptTransaction Scriptรูปแบบ​ที่​จัด​ตรรกะ​ธุรกิจ​เป็น​ชุด​คำ​สั่ง​ตาม​ขั้นตอน (procedural) แทน​การกระจายลง​ใน​อ็อบเจ็กต์ เหมาะ​กับ​งาน​ง่าย ๆ แต่​จะ​รก​เมื่อ domain ซับซ้อน​ขึ้นArchitecture หรือ Active Record แทน และ​ถ้า​ส่วน​ไหน​เป็น generic อาจ​มี open source ที่​หยิบ​มา​ใช้ได้​เลย

🛒 เลือก​ศึก​ให้​ถูก

ใน​ร้าน e-commerce การ login, การ​ส่ง​อีเมล​แจ้ง​เตือน หรือ​การ​แสดง​รายการ​สินค้า​เป็น CRUD ตรง​ไป​ตรง​มา — ไม่​ต้อง​ลาก domain expert มา​นั่ง​คุย และ​ไม่​ต้อง​สร้าง rich model ให้​มัน

แต่ กลไก​คำนวณ​ส่วนลด/โปรโมชัน ที่​มี​กฎ​ซ้อน​กัน​ซับซ้อน คือ core domain ตัว​จริง — ตรง​นี้​แหละ​ที่​ควร​ทุ่ม domain expert และ​หลักการ​ของ DDD ลงไป


Domain ExpertDomain Expertผู้​รู้​ลึก​ใน problem domain ที่ ‘ร่วม​สร้าง model’ กับ​ทีม ต่าง​จาก stakeholder ที่​บอกว่า​ระบบ​ต้อง​ทำ​อะไร — ไม่ใช่​ตำแหน่ง แต่​คือ​ใคร​ก็ได้​ใน​ธุรกิจ​ที่​ให้​ความ​เชี่ยวชาญ​ใน​ปัญหา​นั้น​ได้ DDD ไม่​ทำงาน​หาก​ขาด​บุคคล​นี้Process คือ​ผู้​รู้​ลึก​ใน problem domain — ต่าง​จาก stakeholder ที่​บอก “ระบบ​ต้อง​ทำ​อะไร” domain expert คือ​คน​ที่ ร่วม​สร้าง model กับ​ทีม คำ​ว่า domain expert ไม่​ได้​หมาย​ถึง​ตำแหน่ง แต่​หมาย​ถึง​ใคร​ก็ได้​ใน​ธุรกิจ​ที่​ให้​ความ​เชี่ยวชาญ​ใน​ปัญหา​นี้​ได้ เวลา​ของ​เขา​มี​ค่า จง​ใช้​อย่าง​ฉลาด

เมื่อ​อยู่​ใน Solution SpaceSolution Space“พื้นที่​คำ​ตอบ” — วิธี​ที่​เรา​เลือก​แก้​ปัญหา อยู่​ใน​รูป​ของ Bounded Context และ model 1 subdomain อาจ​มี​ได้​หลาย​คำ​ตอบStrategic Design อย่า​พยายาม model ทั้ง problem domain ใน​คราว​เดียว ให้​ขับ​เคลื่อน​การ model ด้วย​การ เลือก​กระบวนการ​ธุรกิจ (business process) หนึ่ง แล้ว​นิยาม concrete scenario ขึ้น​มา​เป็น​ตัวอย่าง วิธี​นี้​กัน​ไม่​ให้​นัก​พัฒนา​ที่​ไฟ​แรง​เกิน​ไป​สร้าง “model เดียว​ครอบจักรวาล” ที่​ลอก​เลียน​ความ​จริง​ทั้งหมด แทนที่​จะ​เป็น abstraction ที่​ใช้​ประโยชน์​ได้​จริง

🛒 model รอบ scenario ของ​คูปอง

feature: “ใน​ฐานะ​ร้าน ฉัน​อยาก​เสนอ​คูปอง​ส่วนลด เพื่อ​เพิ่ม​ยอด​ใช้​จ่าย​ของ​ลูกค้า”

scenario ที่​เป็น​รูปธรรม: ลูกค้า​มี​คูปอง​ลด 10% ใช้ได้​กับ​ตะกร้า​ที่​ยอด​เริ่มต้น​เกิน $50 — เมื่อ​ใช้​กับ​ตะกร้า​ยอด $60 ส่วนลด​ควร​เป็น $6

ระหว่าง Knowledge CrunchingKnowledge Crunchingการ​บด​เคี้ยว​ความ​รู้ — ศิลปะ​การกลั่น​ข้อมูล​ที่​เกี่ยวข้อง​ออก​จาก problem domain ร่วม​กับ domain expert เพื่อ​สร้าง model ที่​มี​ประโยชน์​ต่อ business use caseProcess ทีม​ฟัง​คำ​ที่ domain expert เลือก​ใช้ แล้ว​จับ concept เหล่า​นั้น​มา​ใส่​ใน model ถ้า​เห็น​ปัญหา​ใน model ให้ challenge กับ expert ทันที

และ​อย่า​เลือก scenario ที่​ง่าย (low-hanging fruit) มา model — ให้​เลือก ส่วน​ที่​ยาก​และ​น่า​สนใจ​ที่สุด​ซึ่ง​อยู่​ลึก​ใน core domain เพราะ​การ​เอา​เวลา​ของ domain expert ไป​คุย​เรื่อง CRUD ธรรมดา​จะ​ทำให้​เขา​เบื่อ​และ​หมด​ความ​สนใจ​ใน​ตัว​คุณ​อย่าง​รวดเร็ว


ความ​กำกวม บวก​กับ​ความ​ไม่รู้​ใน problem domain คือ​ศัตรู​ร้าย​ที่สุด​ของ​นัก​พัฒนา

ทุก​คน​ต้อง​เข้าใจ concept หนึ่งๆ แบบ​เดียวกัน และ​ต้อง​เขียน codebase ด้วย​คำ​เดียวกัน​นั้น เพื่อ​ให้ code modelCode Modelmodel ใน code — การ​แสดงออก​ของ domain model ใน code จริง DDD ถือว่า code model คือ “การ​แสดงออก​หลัก” (primary expression) ของ domain model ไม่ใช่​ไดอะแกรม​หรือ​เอกสารStrategic Design สะท้อน mental model ที่​คุย​กัน เมื่อ​ความ​เข้าใจ​ลึก​ขึ้น UL จะ​วิวัฒน์ และ​เมื่อ​ภาษา​เปลี่ยน code ก็​ต้อง​เปลี่ยน​ตาม — refactor ชื่อ method ให้​เผย​เจตนา​มาก​ขึ้น

ถ้า​เจอ​กลุ่ม​ของ logic ซับซ้อน​เริ่ม​ก่อ​ตัว ให้​คุย​กับ domain expert ว่า code นั้น​ทำ​อะไร แล้ว​ลอง​หา domain concept มา​ตั้ง​ชื่อ​ให้​มัน ถ้า​เจอ ให้​แยก logic กลุ่ม​นั้น​ออก​เป็น Specification หรือ Policy class

Specification คือ​อะไร?

SpecificationSpecificationobject ที่​ห่อ​หุ้ม ‘กฎ​ทาง​ธุรกิจ’ ที่​บาง​ส่วน​ของ domain model ต้อง​ทำให้​เป็น​จริง ใช้​เป็น​เกณฑ์ query ได้​ด้วย หัวใจ​คือ method isSatisfiedBy(...) — เป็น​เครื่องมือ​ทำ logic ที่ implicit ให้ explicitTactical Design คือ object ที่​แทน กฎ​ทาง​ธุรกิจ ที่​อย่าง​น้อย​บาง​ส่วน​ของ domain model ต้อง​ทำให้​เป็น​จริง มัน​ยัง​ใช้​เป็น​เกณฑ์ query ได้​ด้วย — เช่น “หา object ทั้งหมด​ที่​ผ่าน​เกณฑ์​ของ specification นี้” หัวใจ​คือ method isSatisfiedBy(...)


ตอน​เริ่ม project คุณ​รู้​น้อย​ที่สุด แต่​กลับ​เป็น​ช่วง​ที่​ต้อง​ตัดสิน​ใจ​เรื่อง​สำคัญ​ที่สุด model แรก​ของ​คุณ​จะ​ผิด​เสมอ — แต่​อย่า​ยึด​ติด การ​เรียนรู้ problem domain เกิด​ขึ้น​ผ่าน iteration หลาย​รอบ ปัญหา​คือ​พอ​ทีม​ได้ model แรก​ที่ “ใช้ได้” ส่วน​ใหญ่​ก็​หยุด​สำรวจ​แล้ว​รีบ​ไป​พิมพ์ code ทันที

สำหรับ​ทุก​การ​ออกแบบ​ที่​ดี ต้อง​มี​การ​ออกแบบ​ที่​แย่​อย่าง​น้อย​สาม​แบบ​มา​ก่อน

— Eric Evans

พอได้ model ที่​ดีแล้ว ให้ “พัก​มัน​ไว้” แล้ว​สำรวจ​ปัญหา​จาก​มุม​ใหม่ การ​ทดลอง​และ​สำรวจ​คือ​เชื้อเพลิง​ของ​การ​ค้น​พบ บาง​ครั้ง model พา​คุณ​เข้า​มุม​อับ scenario ใหม่​ใส่​ไม่​ได้ — นั่น​ก็​ปกติ อย่า​ฝืน​ยัด scenario เข้า model เดิม ให้​สร้าง model ใหม่​ที่​ตอบ​ทั้ง scenario เก่า​และ​ใหม่ ผลลัพธ์​ที่แท้​จริง​ไม่ใช่ “model สมบูรณ์​แบบ” แต่​คือ การ​เรียนรู้​และ​ค้น​พบ concept ใน domain

LEARN TO UNLEARN — เรียน​เพื่อ​ที่​จะ​ลืม

อย่า​ยึด​ติด​กับ​ไอเดีย — มี​เพียง​การ​ลอง​ผิด​ลอง​ถูก​เท่านั้น​ที่​จะ​เผย concept ใน domain ออก​มา เคล็ด​ลับ​เชิง​ปฏิบัติ: เขียน code ทดลอง (spike) ไว้​ใน namespace ของ test ก่อน จนกว่า​จะ​พอใจ​กับ design แล้ว​คุณ​จะ กล้า​ทิ้ง model ที่​ไร้​ประโยชน์​ได้​ง่าย​กว่า​มาก เพราะ​ยัง​ไม่​ได้ commit มัน​เข้า application namespace


เวลา​ทำงาน​ลึก​ใน codebase ทีม​มัก​มอง​ข้าม logic บาง​ก้อน​ว่า​เป็น​แค่ “รายละเอียด​การ​เขียน​โปรแกรม” ทั้ง​ที่​มัน​ซ่อน​รายละเอียด​สำคัญ​ของ domain ไว้ ถ้า​ไม่​ทำให้​มัน explicit มัน​จะ​ไม่​ถูก​เพิ่ม​เข้า mental model และ​การ​ค้น​พบ​ครั้ง​ต่อๆ ไป​จะ​ยาก​ขึ้น

ลอง​ดู​กฎ​จริง​ข้อ​หนึ่ง: เว็บ e-commerce ห้าม​ลูกค้า​ต่าง​ประเทศ​ใส่​สินค้า​ชนิด​เดียว​เกิน 50 ชิ้น​ใน​ตะกร้า version แรก​มัก​เขียน​กฎ​ฝัง​ลง​ไป​ใน method ตรงๆ

Basket.add — implicit (ก่อน)
public void add(Product product)
{
if (basket_contains_an_item_for(product))
{
var item_quantity = get_item_for(product).quantity().add(new Quantity(1));
// กฎลึกลับ: ทำไมต้อง 50? อีกหกเดือนไม่มีใครจำได้
if (item_quantity.contains_more_than(new Quantity(50)))
throw new ApplicationException("You can only purchase 50 of a single product.");
else
get_item_for(product).increase_item_quantity_by(new Quantity(1));
}
else
_items.Add(BasketItemFactory.create_item_for(product, this));
}

อีก​หก​เดือน​ถัด​มา ไม่มี​ใคร​เข้าใจ​ว่า​กฎ​นี้​มี​อยู่​ทำไม จริงๆ แล้ว ซัพพลายเออร์​เป็น​ผู้​บังคับ​กฎ​นี้​เพื่อ​กัน​ไม่​ให้​เว็บ​กลาย​เป็น​ผู้​ค้า​ส่ง เมื่อ​รู้​เหตุผล​นี้ ให้​ห่อ logic ลงใน class ที่​ตั้ง​ชื่อ​ให้​สะท้อน​ความ​เข้าใจ​นั้น — นี่​คือ Specification ที่​มี​ตัวตน​ขึ้น​มาจริงๆ

OverSeasSellingPolicy — explicit (หลัง)
public class OverSeasSellingPolicy
{
public static Quantity quantity_threshold = new Quantity(50);
public bool is_satisfied_by(Quantity item_quantity, Country country)
{
return !item_quantity.contains_more_than(quantity_threshold);
}
}
// ใน Basket.add — เจตนาชัดเจนขึ้นทันที
if (_over_seas_selling_policy.is_satisfied_by(item_quantity))
get_item_for(product).increase_item_quantity_by(new Quantity(1));
else
throw new OverSeasSellingPolicyException(/* ... */);
ตั้ง​ชื่อ​ให้​ทุก​สิ่ง

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


เป็น​นัก​แก้​ปัญหา​ก่อน เป็น​นัก​เทคโนโลยี​ทีหลัง

หัวข้อ​ที่​มีชื่อ​ว่า “เป็น​นัก​แก้​ปัญหา​ก่อน เป็น​นัก​เทคโนโลยี​ทีหลัง”

นัก​พัฒนา​คือ นัก​แก้​ปัญหา ที่​ใช้​เทคโนโลยี​เป็น​เครื่องมือ ไม่ใช่​กลับ​กัน เทคโนโลยี​ไม่ใช่​คำ​ตอบ​ของ​ปัญหา​ธุรกิจ มัน​เป็น​แค่ implementation detail การ brainstorm model บน​กระดาษ​หรือ whiteboard ก่อน​ลงมือ​ใน IDE จะ​ช่วย​ให้​คุณ​โฟกัส​ที่ conceptual model ที่​ปลอด​จาก​ความ​รก​ของ infrastructure

Code คือ ผลผลิต ของ DDD ไม่ใช่​กระบวนการ — คุณ​แก้​ปัญหา​ได้​โดย​ไม่​ต้อง​มี technical solution ด้วย​ซ้ำ

และ​อย่า​พยายาม​แก้​ทุก​ปัญหา บาง edge case ซับซ้อน​แต่​มี​คุณค่า​ทาง​ธุรกิจ​น้อย — ปล่อย​ให้​มนุษย์​จัดการ “เป็น​ราย​กรณี​ยกเว้น” (manage by exception) มักได้​ผล​ดี​กว่า​และ​ถูก​กว่า​การ​ลงทุน automate ทุก​อย่าง


DDD ไม่มี​ใบ​ประกาศนียบัตร​เหมือน​การ​เป็น scrum master รางวัล​ของ​คุณ​คือ ผลิตภัณฑ์​ที่​เข้าใจ​ง่าย ดูแล​รักษา​ง่าย ตรง​กับ​ความ​คาด​หวัง​ของ stakeholder และ​สนุก​ที่​จะ​ทำงาน​ด้วย สัญญาณ​ที่​บอกว่า​มา​ถูก​ทาง:

  • สมาชิก​ใน​ทีม เข้าใจ​ธุรกิจ​ดี​ขึ้น คุย​กับ stakeholder ได้​คล่อง และ​เสนอ​วิธี​แก้​ปัญหา​ที่​ธุรกิจ​ไม่รู้​ด้วย​ซ้ำ​ว่า​มี
  • ทีม​เลิก​ทุ่ม​แรง​สร้าง​สถาปัตยกรรม​ขั้น​เทพ​ให้​ทุก​ส่วน​เท่า​กัน​หมด แต่​รู้จัก แลก​ความ​สมบูรณ์​แบบ​ที่​ไม่​จำเป็น มา​เป็น​ซอฟต์แวร์​ที่​แยก​ส่วน​ชัดเจน​และ​ใช้งาน​ได้​จริง
  • ใช้​เวลา​กับ what, why, when มาก​ขึ้น แล้ว​ค่อย​ปล่อย how ไว้​ทีหลัง
Good Is Good Enough

มี​เพียง core domain เท่านั้น​ที่​ต้อง​ประณีต​สง่างาม เพราะ​ทั้ง​ความ​ซับซ้อน​และ​ความ​สำคัญ​ของ​มัน ส่วน​อื่น​ไม่​ได้​แปล​ว่า​ให้​เขียน​แบบ​ขอ​ไป​ที แต่​ให้ แยก​ออก​มา ล้อม​ด้วย​ขอบเขต​ที่​ชัดเจน และ​เปิดเผย​พฤติกรรม​เท่า​ที่​จำเป็น เพื่อ​หนุน core domain — อย่า​ขัด​เงา (gold-plate) ส่วน​ที่​มี​คุณค่า​น้อย

รูป​ที่ 10-1 รวบ​กระบวนการ​ทั้งหมด​ของ​บท​นี้​ไว้: stakeholder กับ​ทีม​ร่วม​กัน share vision และ capture behavior ใน problem space แตก problem space ออก​เป็น generic/supporting/core ใช้ solution ง่าย​กับ​ปัญหา​ง่าย แล้ว collaborate กับ domain expert บน​ปัญหา​ที่​ซับซ้อน อธิบาย model ด้วย UL ทดลอง​หลาย​แบบ และ decompose ลง​เป็น Bounded Context ใน solution space

รูปที่ 10-1: กระบวนการของ DDD — problem space (บน) ที่ stakeholder และทีมร่วมกัน share vision จับพฤติกรรม และแตกปัญหาออกเป็น core/supporting/generic แล้วไหลลงสู่ solution space (ล่าง) ที่ collaborate กับ domain expert ทดลองหลาย model validate ด้วย UL และ decompose ลงเป็น Bounded Context


  • อย่า​ขาย DDD เป็นกระสุน​เงิน (silver bullet) ให้​เน้น​การ align กับ​ธุรกิจ​และ​การ​เรียนรู้ domain
  • ใช้​หลักการ​ของ DDD เฉพาะ​เมื่อ​จำเป็น ไม่ใช่​เครื่องมือ​สำหรับ​ทุก​ปัญหา
  • แตก problem space แล้ว​โฟกัส​ที่ Core DomainCore Domainsubdomain ที่​สำคัญ​และ​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน​มาก​ที่สุด เป็น​เหตุผล​ที่​เรา​ต้อง​สร้าง​ซอฟต์แวร์​เอง​แทน​การ​ซื้อ ควร​ทุ่ม​ทีม​เก่ง​ที่สุด​ลง​ตรง​นี้Strategic Design — บทสนทนา​ที่​น่า​สนใจ​ทั้งหมด​เกิด​ขึ้น​ตรง​นี้
  • จับ​ภูมิทัศน์​ด้วย Context MapContext Mapแผนภาพ​ที่​แสดง Bounded Context ทั้งหมด​และ​ความ​สัมพันธ์​ระหว่าง​กัน ช่วย​ให้​เห็น​ภาพ​รวม​และ​จุด​เชื่อม​ต่อ/แปล​ภาษา​ใน​ระบบ​ใหญ่Strategic Design ก่อน model: ใคร​เป็น​เจ้าของ context ไหน แลก​ข้อมูล​อะไร​กัน​บ้าง
  • build model รอบ feature scenario เริ่ม​จาก​อัน​ที่​เสี่ยง/ซับซ้อน​ที่สุด อย่า​เอา​เวลา expert ไป​กับ CRUD
  • ใน​ระบบ legacy ให้​ป้องกัน​ตัว​ด้วย Anticorruption LayerAnticorruption Layer (ACL)ชั้น​กั้น​ที่​ทีม​ปลาย​น้ำ​สร้าง​ขึ้น​เพื่อ​แปลง model ของ​ระบบ​อื่น​ให้​เป็น​ภาษา​ของ model ตัวเอง ป้องกัน​ไม่​ให้ model ภายนอก​มา “ปน​เปื้อน” model เราStrategic Design อย่า​ไว้ใจ​ระบบ​อื่น​ง่ายๆ และ​อย่า​พยายาม​ล้าง​ทุก​อย่าง​ใหม่​หมด
  • integrate, refine และ challenge model ตลอด​เวลา — มี model ที่​ใช้ได้​อย่าง​น้อย​สาม​แบบ
  • อย่า​สมมติ​อะไร เริ่ม​ง่ายๆ เลื่อน​การ​ตัดสิน​ใจ design ใหญ่ๆ ออก​ไป แล้ว refactor เข้าหา strategic pattern เมื่อ​จำเป็น
  • modeling เป็น​กิจกรรม​ของ​ทีม​ที่​เกิด เมื่อไร​ก็ได้ ที่​ติดขัด ไม่ใช่​ขั้นตอน​ตายตัว​ใน timeline
  • model และ​ภาษา วิวัฒน์​ไป​ด้วย​กัน — model ที่​พูด​ถึง​เป็น​คำ​พูด​ไม่​ได้ ย่อม​มี​ประโยชน์​จำกัด​และ evolve ได้​ยาก

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

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

  • Strategic Design — บท​นี้​ย้ำ​ว่า​ควร​ขาย DDD และ​ลงทุน​ความคิด​ที่​ระดับ strategic (align กับ​ธุรกิจ, ภาษา, core domain) ก่อน​เสมอ ไม่ใช่​กระโดด​ไป tactical pattern
  • Subdomain — ขั้นตอน “กลั่น problem space” ใน​บท​นี้​คือ​การ​แตก​ผลิตภัณฑ์​ออก​เป็น subdomain (core/supporting/generic) เพื่อ​โฟกัส​ความ​พยายาม​ให้​ถูก​จุด
  • Context Mapping — ขั้นตอน “เข้าใจ​ภูมิทัศน์​จริง​ก่อน​ลงมือ​สร้าง” ใช้ Context Map แบบ​เดียว​กับ​ที่​อธิบาย​ไว้​ใน​หน้า​นี้ เพื่อ​ระบุ Bounded Context และ​ความ​สัมพันธ์​ระหว่าง​ทีม
  • Specification — ตัวอย่าง OverSeasSellingPolicy ใน​บท​นี้​คือ​การ​ห่อ​กฎ​ธุรกิจ​ที่ implicit ให้​เป็น Specification/Policy object ที่​มี isSatisfiedBy(...) ตรง​ตาม pattern นี้

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

ข้อ 1 / 4

ตามบทนี้ หัวใจของการนำ DDD ไปใช้จริงคืออะไร?