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

เมื่อไหร่​ไม่​ควร​ใช้ DDD

สิ่ง​ที่​แยก​ผู้​ใช้ DDD ที่​เก่ง​ออก​จาก​คน​ที่ “ทำ​ตาม​สูตร” คือ​วิจารณญาณ​ว่า “เมื่อไหร่​ไม่​ควร​ใช้” DDD มี​ต้นทุน และ​ไม่ใช่​คำ​ตอบ​สำหรับ​ทุก​ปัญหา

  • domain ซับซ้อน มี​กฎ​ธุรกิจ​ซับซ้อน​และ​เปลี่ยนแปลง​บ่อย (e-commerce การเงิน ERP โล​จิ​สติ​กส์ ประกันภัย)
  • ต้องการ​ความ​ร่วมมือ​ใกล้​ชิด​ระหว่าง​ฝ่าย​ธุรกิจ​กับ​ฝ่าย​เทคนิค
  • ส่วน​นั้น​เป็น Core DomainCore Domainsubdomain ที่​สำคัญ​และ​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน​มาก​ที่สุด เป็น​เหตุผล​ที่​เรา​ต้อง​สร้าง​ซอฟต์แวร์​เอง​แทน​การ​ซื้อ ควร​ทุ่ม​ทีม​เก่ง​ที่สุด​ลง​ตรง​นี้Strategic Design ที่​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน

ถ้า​เป็น app CRUD ง่ายๆ (หน้า admin, รายงาน​ข้อมูล, to-do list, ระบบ​จัดการ​รายชื่อ) การ​ฝืน​ใช้ AggregateAggregateกลุ่ม​ของ Entity และ Value Object ที่​ถูก​มอง​เป็น​หนึ่ง​หน่วย​เดียว​เพื่อ​รักษา​ความ​ถูกต้อง​ของ​ข้อมูล มี​ขอบเขต​ชัดเจน และ​เป็น​หน่วย​ของ transactionTactical Design, Domain EventDomain Eventสิ่ง​ที่ “เกิด​ขึ้น​แล้ว” ใน domain ซึ่ง​ส่วน​อื่น​สนใจ แทน​ด้วย​อ็อบเจ็กต์ที่​เปลี่ยนแปลง​ไม่​ได้ ตั้ง​ชื่อ​เป็น​อดีต เช่น CargoWasRouted ใช้​สื่อสาร​ข้าม AggregateTactical Design, RepositoryRepositoryตัว​ที่​ทำให้​เรา​เข้าถึง Aggregate ราวกับ​เป็น collection ใน​หน่วย​ความ​จำ ซ่อน​รายละเอียด​ฐาน​ข้อมูล มี1 repository ต่อ1 Aggregate RootTactical Design เต็ม​รูปแบบ​จะ​เพิ่ม​ความ​ซับซ้อน​โดย​ไม่​จำเป็น ทำให้​พัฒนา​ช้า​ลง​และ​แก้ feature ง่ายๆ ยาก​ขึ้น — กลาย​เป็น codebase ที่​ซับซ้อน​เกิน​ความ​ต้องการ​จริง​และ​ต้นทุน​บานปลาย

ทาง​สาย​กลาง

ใน​ระบบ​จริง​หนึ่ง​ระบบ มัก​มี​ทั้ง​สอง​แบบ​ปน​กัน เช่น (อ้างอิง​ตัวอย่าง eShopOnContainers ของ Microsoft) microservice การ​สั่ง​ซื้อ​ใช้ DDD เต็ม​รูปแบบ​เพราะ​กฎ​ซับซ้อน ส่วน microservice catalog ที่​เป็น CRUD ล้วน​ใช้ Anemic Domain ModelAnemic Domain Modelanti-pattern ที่อ็อบเจ็กต์มี​แต่ getter/setter ไร้​พฤติกรรม ตรรกะ​ถูก​ดึง​ไป​ไว้​ใน service ทั้งหมด — จ่าย​ค่า domain model แต่​ไม่​ได้​ประโยชน์​ของ​มัน​เลยTactical Design ก็​เพียงพอ — เลือก​ใช้​เครื่องมือ​ตาม​ความ​ซับซ้อน​ของ​แต่ละ​ส่วน


  • ภาษา​ไม่​สอดคล้อง — คำ​เดียวกัน​หมาย​ถึง​คนละ​สิ่ง โดย​ไม่มี Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design มา​กำหนด​ขอบเขต
  • Over-engineering งาน​ง่าย — ยก​ชุด​เครื่องมือ tactical ทั้งหมด​มา​ใส่ CRUD ธรรมดา
  • Value ObjectValue Objectอ็อบเจ็กต์ที่​สำคัญ​ที่ “ค่า” ของ​มัน ไม่มี​ตัวตน​เฉพาะ สอง​ตัว​ที่​ค่า​เท่า​กัน​ถือว่า​เท่า​กัน ควร​เป็น immutable (เปลี่ยน​ค่า​ไม่​ได้) เช่น เงิน, วัน​ที่, พิกัดTactical Design ที่​ผิด​เพี้ยน — ใส่ identity หรือ​ทำให้​แก้​ค่า​ได้ / EntityEntityอ็อบเจ็กต์ที่​มี “ตัวตน” (identity) ต่อ​เนื่อง​ตาม​เวลา แม้​ค่า​ภายใน​เปลี่ยน ก็​ยัง​เป็น​สิ่ง​เดิม เช่น ลูกค้า, คำ​สั่ง​ซื้อ — แยกแยะ​ด้วย id ไม่ใช่​ด้วย​ค่าTactical Design ที่​สร้าง​โดย​ไม่มี identity ชัดเจน
  • Service อ้วน — ดึง​ตรรกะ​ออก​จาก model จน​กลาย​เป็น Anemic Domain ModelAnemic Domain Modelanti-pattern ที่อ็อบเจ็กต์มี​แต่ getter/setter ไร้​พฤติกรรม ตรรกะ​ถูก​ดึง​ไป​ไว้​ใน service ทั้งหมด — จ่าย​ค่า domain model แต่​ไม่​ได้​ประโยชน์​ของ​มัน​เลยTactical Design
  • AggregateAggregateกลุ่ม​ของ Entity และ Value Object ที่​ถูก​มอง​เป็น​หนึ่ง​หน่วย​เดียว​เพื่อ​รักษา​ความ​ถูกต้อง​ของ​ข้อมูล มี​ขอบเขต​ชัดเจน และ​เป็น​หน่วย​ของ transactionTactical Design ใหญ่​เกิน​ไป หรือ​อ้างอิง Aggregate อื่น​โดยตรง → transaction ข้าม​ขอบเขต ปัญหา​ประสิทธิภาพ​และ​ความ​ถูกต้อง
  • กระโดด​ไป tactical ก่อน — ลงมือ​สร้าง Entity/Repository ก่อน​เข้าใจ subdomain และ​ขอบเขต
  • ละเลย Core — ทำ model ส่วน​รอบ​นอก​อย่าง​ประณีต แต่​ปล่อย​ส่วน​หัวใจ​ของ​ธุรกิจ​ไว้
  • Big Ball of MudBig Ball of Mudระบบ​ที่​ปนเป​กัน​ยุ่งเหยิง​ไม่มี​ขอบเขต​ชัด ให้​ลาก​เส้น​ล้อม​ไว้​แล้ว​ยอมรับ​สภาพ ไม่​พยายาม​ทำ model ละเอียด​ใน​นั้น และ​ระวัง​ไม่​ให้​ลาม​ไป context อื่นStrategic Design — Aggregate ปนเป​กัน​หมด ไม่มี​ขอบเขต​ชัด code ผูก​กัน​แน่น
ลำดับ​ที่​ถูกต้อง

เริ่ม​จาก Strategic ก่อน​เสมอ: เข้าใจ DomainDomainขอบเขต​ของ​ปัญหา​หรือ​ธุรกิจ​ที่​ซอฟต์แวร์​ของ​เรา​เข้าไป​แก้ไข เช่น การ​ขนส่ง​สินค้า การ​ธนาคาร e-commerce — คือ “โลก​ของ​ผู้​ใช้” ที่​โปรแกรม​ต้อง​เข้าใจStrategic Design → แบ่ง SubdomainSubdomainส่วน​ย่อย​ของ Domain ใหญ่ เช่น Domain e-commerce แตก​เป็น subdomain การ​สั่ง​ซื้อ การ​ชำระ​เงิน คลัง​สินค้า ฯลฯ อยู่​ใน “พื้นที่​ปัญหา” (problem space)Strategic Design → หา Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design → วาด Context MapContext Mapแผนภาพ​ที่​แสดง Bounded Context ทั้งหมด​และ​ความ​สัมพันธ์​ระหว่าง​กัน ช่วย​ให้​เห็น​ภาพ​รวม​และ​จุด​เชื่อม​ต่อ/แปล​ภาษา​ใน​ระบบ​ใหญ่Strategic Design แล้ว จึง ลงมือ tactical การกระโดด​ไป​เขียน EntityEntityอ็อบเจ็กต์ที่​มี “ตัวตน” (identity) ต่อ​เนื่อง​ตาม​เวลา แม้​ค่า​ภายใน​เปลี่ยน ก็​ยัง​เป็น​สิ่ง​เดิม เช่น ลูกค้า, คำ​สั่ง​ซื้อ — แยกแยะ​ด้วย id ไม่ใช่​ด้วย​ค่าTactical Design/RepositoryRepositoryตัว​ที่​ทำให้​เรา​เข้าถึง Aggregate ราวกับ​เป็น collection ใน​หน่วย​ความ​จำ ซ่อน​รายละเอียด​ฐาน​ข้อมูล มี1 repository ต่อ1 Aggregate RootTactical Design ทันที​เป็น​สาเหตุ​ของ​ปัญหา​เชิง​โครงสร้าง​ที่​แก้​ยาก​ภายหลัง


คุณ​ได้​เดิน​ครบ​ทั้ง 5 ขั้น: เข้าใจ “ทำไม” (Stage 0) → สร้าง Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design (Stage 1) → ออกแบบ​เชิงกลยุทธ์​ด้วย Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design และ Context MappingContext Mappingกิจกรรมการ​ระบุ Bounded Context และ​นิยาม​ความ​สัมพันธ์​ระหว่าง​กัน (เช่น Partnership, Shared Kernel, ACL) เพื่อ​จัดการ​การ​เชื่อม​ต่อ​ระหว่าง​ทีม/ระบบStrategic Design (Stage 2) → ลงมือ​สร้าง building blocks (Stage 3) → จัด​สถาปัตยกรรม​และ​รูปแบบ​ขั้น​สูง (Stage 4) → และ​ฝึก​วิจารณญาณ​ว่า​เมื่อไหร่​ควร/ไม่​ควร​ใช้ (Stage 5)

หัวใจ​ที่​ควร​จำ

DDD ไม่ใช่​ชุด​กฎ​ตายตัว แต่​คือ​วิธี​คิด​ที่​เริ่ม​จาก “ภาษา​และ​ขอบเขต” ก่อน “code” — building blocks เป็น​เพียง​เครื่องมือ ส่วน​คุณค่า​จริง​อยู่​ที่​การ​เข้าใจ​ธุรกิจ​อย่าง​ลึกซึ้ง​และ​จำลอง​มัน​ออก​มา​ให้​ตรง

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

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

  • Anemic Domain Model — model ที่​เก็บ​แต่​ข้อมูล​ไม่มี​พฤติกรรม เหมาะ​กับ subdomain แบบ CRUD ตาม​ที่​บท​นี้​แนะนำ แต่​กลาย​เป็น anti-pattern ถ้า​เผลอ​ใช้​กับ core domain ที่​มี​กฎ​ซับซ้อน
  • Aggregate — ทบทวน​ขอบเขต​ของ Aggregate ที่​ถูกต้อง เพื่อ​หลีก​เลี่ยง anti-pattern “Aggregate ใหญ่​เกิน​ไป” ที่​บท​นี้​เตือน​ไว้
  • Value Object — ทบทวน​คุณสมบัติ​ที่แท้​จริง​ของ Value Object เพื่อ​ไม่​ให้​ตกหลุม anti-pattern “Value Object ที่​ผิด​เพี้ยน”
  • Big Ball of Mud — anti-pattern สถาปัตยกรรม​ที่​บท​นี้​ยก​เป็น​ตัวอย่าง​ผลลัพธ์​ของ​การ​ไม่มี​ขอบเขต​ชัดเจน

ทดสอบรวบยอด — Stage 5

ข้อ 1 / 4

งานใดที่ “ไม่ควร” ใช้ DDD เต็มรูปแบบ?