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

ปัญหา​ที่​ทีม​มือใหม่​มัก​เจอ​เมื่อ​เริ่ม​ใช้ DDD

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

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


ลอง​ค้น​คำ​ว่า “DDD” ใน Google คุณ​จะ​เจอ​แต่​เรื่อง building blocks อย่าง EntityEntityอ็อบเจ็กต์ที่​มี “ตัวตน” (identity) ต่อ​เนื่อง​ตาม​เวลา แม้​ค่า​ภายใน​เปลี่ยน ก็​ยัง​เป็น​สิ่ง​เดิม เช่น ลูกค้า, คำ​สั่ง​ซื้อ — แยกแยะ​ด้วย id ไม่ใช่​ด้วย​ค่าTactical Design, Value ObjectValue Objectอ็อบเจ็กต์ที่​สำคัญ​ที่ “ค่า” ของ​มัน ไม่มี​ตัวตน​เฉพาะ สอง​ตัว​ที่​ค่า​เท่า​กัน​ถือว่า​เท่า​กัน ควร​เป็น immutable (เปลี่ยน​ค่า​ไม่​ได้) เช่น เงิน, วัน​ที่, พิกัดTactical Design, AggregateAggregateกลุ่ม​ของ Entity และ Value Object ที่​ถูก​มอง​เป็น​หนึ่ง​หน่วย​เดียว​เพื่อ​รักษา​ความ​ถูกต้อง​ของ​ข้อมูล มี​ขอบเขต​ชัดเจน และ​เป็น​หน่วย​ของ transactionTactical Design, RepositoryRepositoryตัว​ที่​ทำให้​เรา​เข้าถึง Aggregate ราวกับ​เป็น collection ใน​หน่วย​ความ​จำ ซ่อน​รายละเอียด​ฐาน​ข้อมูล มี1 repository ต่อ1 Aggregate RootTactical Design จน​หลาย​คน​เข้าใจ​ผิด​ว่า​นี่​คือ “หัวใจ” ของ DDD แม้แต่ Eric Evans เอง​ยัง​เคย​บอกว่า​เสียดาย​ที่​ไม่​ได้​วาง strategic patterns ไว้​ต้น​เล่ม เพราะ​คน​ส่วน​ใหญ่​อ่าน​ถึง​แค่​ส่วน building blocks แล้ว​ก็​หยุด

ปัญหา​ที่​ใหญ่​กว่า​นั้น​ซ่อน​อยู่​เบื้องหลัง: คน​สาย​เทคนิค​ที่​สนใจ​แต่ pattern และ​การ​เขียน code ใน​ระบบ​ที่​ตรรกะ​ธุรกิจ​ซับซ้อน การ “พิมพ์ code” ไม่​เคย​เป็น​คอ​ขวด code เป็น​เพียง ผลพลอยได้ ของ​การ​ที่​นัก​พัฒนา​กับ domain expertKnowledge Crunchingการ​บด​เคี้ยว​ความ​รู้ — ศิลปะ​การกลั่น​ข้อมูล​ที่​เกี่ยวข้อง​ออก​จาก problem domain ร่วม​กับ domain expert เพื่อ​สร้าง model ที่​มี​ประโยชน์​ต่อ business use caseProcess นั่ง​จำลอง​ปัญหา​ร่วม​กัน — มัน​คือ “ปลายทาง” ของ​การ​ร่วมมือ​และ​การ​ค้น​พบ ไม่ใช่​จุด​เริ่ม

DDD lite — ใช้​แค่ tactical แล้ว​คิด​ว่า​ทำ DDD แล้ว

การ​หยิบ​มา​แต่ tactical pattern โดย​ไม่ knowledge-crunch กับ​ธุรกิจ ไม่​สร้าง Ubiquitous LanguageUbiquitous Languageภาษา​กลาง​ที่​ทุก​คนใน​ทีม (ทั้ง​นัก​พัฒนา​และ​ผู้เชี่ยวชาญ​ธุรกิจ) ใช้​ร่วม​กัน อิง​กับ domain model โดยตรง คำ​เดียวกัน​ต้อง​หมาย​ถึง​สิ่ง​เดียวกัน และ​สะท้อน​ลง​ใน codeStrategic Design ไม่​สนใจ Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design เรียก​กัน​ว่า “DDD lite” ทำ​แบบ​นี้​ไม่​ผิด แต่​อย่า​หลอก​ตัวเอง​ว่า​กำลัง​ทำ DDD เต็ม​รูปแบบ เพราะ​คุณ​กำลัง​พลาด คุณค่า​ส่วน​ใหญ่ ของ​มัน​ไป

DDD ไม่​ได้​บังคับ​ว่า​ต้อง​ใช้ CQRSCQRSCommand Query Responsibility Segregation — แยก model สำหรับ “เขียน/แก้ไข” (command) ออก​จาก model สำหรับ “อ่าน” (query) เหมาะ​กับ domain ซับซ้อน แต่​เพิ่ม​ความ​ซับซ้อน ใช้​อย่าง​ระมัดระวังArchitecture, Event SourcingEvent Sourcingเก็บ​ทุก​การ​เปลี่ยน​สถานะ​เป็น event ที่​เปลี่ยน​ไม่​ได้ แล้ว​สร้าง​สถานะ​ปัจจุบัน​ด้วย​การ​เล่น event ซ้ำ มัก “ต้อง​ใช้​คู่​กับ CQRS” (Greg Young) มี event stream ต่อ1 AggregateArchitecture, messaging หรือ ORM ตัว​ไหน สิ่ง​เดียว​ที่​มัน​ยืนกราน คือ ความ​ซับซ้อน​ของ domain model ต้อง​ถูก​แยก​ออก​จาก​ความ​ซับซ้อน​ทาง​เทคนิค สถาปัตยกรรม​ใด​ที่​รองรับ​การ​แยก​นี้​ได้​ก็​ถือว่า​เข้า​กับ DDD

จุด​สำคัญ​คือ สถาปัตยกรรม​เป็น​เรื่อง​ของ​แต่ละ bounded context ไม่ใช่​ของ​ทั้ง app context ที่​เรียบ​ง่าย​อาจ​ใช้ Layered ArchitectureLayered Architectureการ​แยก code เป็น​ชั้น (UI, Application, Domain, Infrastructure) โดย​รวม code ที่​เกี่ยว​กับ domain ไว้​ชั้น​เดียว​และ​แยก​ออก​จาก​ชั้น​อื่น เป้าหมาย​คือ​การ​แยก​ส่วน (isolation)Architecture บวก Transaction ScriptTransaction Scriptรูปแบบ​ที่​จัด​ตรรกะ​ธุรกิจ​เป็น​ชุด​คำ​สั่ง​ตาม​ขั้นตอน (procedural) แทน​การกระจายลง​ใน​อ็อบเจ็กต์ เหมาะ​กับ​งาน​ง่าย ๆ แต่​จะ​รก​เมื่อ domain ซับซ้อน​ขึ้นArchitecture ก็พอ ส่วน context ที่​ตรรกะ​รวย​และ​เปลี่ยน​บ่อย​จึง​ค่อย​ลงทุน​กับ Rich Domain ModelRich Domain Modelmodel domain ที่ “รวย​พฤติกรรม” — object ที่​เก็บ​ทั้ง​ข้อมูล​และ business logic ไว้​ด้วย​กัน เป็น​คู่​ตรง​ข้าม​ของ Anemic Domain Model (ที่​มี​แต่ getter/setter แล้ว​ผลัก logic ไป​ไว้​ที่​อื่น) tactical patterns ของ DDD จะ​คุ้ม​ค่า​ก็​ต่อ​เมื่อ model “รวย” พอ​เช่น​นี้Tactical Design

🚢 ระบบ​ขนส่ง — คนละ context คนละ​สถาปัตยกรรม

ใน Cargo Shipping นั้น context การ “วางแผน​เส้นทาง” (Route SpecificationRoute SpecificationValue Object ที่​ระบุ “ความ​ต้องการ​ของ​ลูกค้า”: ต้นทาง ปลายทาง และ​กำหนด​เวลา​ถึง — มี method isSatisfiedBy() ตรวจ​ว่า​แผน​เดินทาง​ตรง​ตาม​นี้​หรือ​ไม่Tactical Design, ItineraryItineraryValue Object ที่​เป็น “แผนการ​เดินทาง​จริง” ของ Cargo ประกอบ​ด้วย​ลำดับ​ของ Leg (ช่วง​การ​ขนส่ง​แต่ละ​ช่วง)Tactical Design) มี​กฎ​ซับซ้อน คุ้ม​ที่​จะ​ทำ rich domain model เต็ม​ที่ แต่ context “จัดการ​ข้อมูล​ลูกค้า/ที่​อยู่” แทบ​ไม่มี​ตรรกะ — ใช้ CRUD ธรรมดา​ก็​จบ ไม่​ต้อง​บังคับ​ให้​ทุก​ที่​เป็น Aggregate เหมือน​กัน​หมด

ทีม​ที่​ห่วง​แต่ code มัก​ยึด building block patterns ราวกับ​เป็น “คัมภีร์” แทนที่​จะ​เป็น “แนวทาง” โดย​ไม่​เข้าใจ​ว่า​เมื่อไร​ควร​แหก​กฎ​ได้ พวก​เขา​ทุ่ม​แรง​ไป​กับ​การ​ทำให้​ถูกต้อง​ตาม​กฎ​ทุก​ประการ ทั้ง​ที่​แรง​นั้น​ควร​ใช้​ไป​กับ​การ​เข้าใจ​ว่า ทำไม ถึง​ต้อง​เขียน​สิ่ง​นั้น​ตั้งแต่​แรก

DDD คือ​การ​ค้นหา​ว่า ต้อง​เขียน​อะไร ทำไม​ต้อง​เขียน และ​ควร​ลงแรง​แค่​ไหน — “อะไร” และ “ทำไม” สำคัญ​กว่า “อย่างไร” มาก และ​อย่า​ลืม​ว่า tactical patterns คือ​ส่วน​ที่​วิวัฒน์​ไป​ไกล​ที่สุด​นับ​จาก​หนังสือ​ของ Evans ส่วน strategic ยัง​คง​ซื่อตรง​กับ​ต้นฉบับ​เดิม


ปัญหา​ถูก​แก้​ไม่ใช่​แค่​ใน code แต่​ผ่าน​การ​ร่วมมือ การ​สื่อสาร และ​การ​สำรวจ​กับ domain expert

— Scott Millett & Nick Tune

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

Context, context และ context อีก​ที — มัน​คือ​แนวคิด​พื้นฐาน​ของ DDD ปัญหา​ทั้งหมด​ไม่​อาจ​แก้​ด้วย model เดียว เรา​ต้อง​สร้าง​หลาย model เพื่อ​แก้​คนละ​ปัญหา การ​สร้าง model ภายใน​ขอบเขต​ที่​ชัดเจน​คือ​สิ่ง​จำเป็น​ที่​ทำให้ code อยู่​ใน​สภาพ​จัดการ​ได้ และ​ไม่​กลาย​เป็น Big Ball of MudBig Ball of Mudระบบ​ที่​ปนเป​กัน​ยุ่งเหยิง​ไม่มี​ขอบเขต​ชัด ให้​ลาก​เส้น​ล้อม​ไว้​แล้ว​ยอมรับ​สภาพ ไม่​พยายาม​ทำ model ละเอียด​ใน​นั้น และ​ระวัง​ไม่​ให้​ลาม​ไป context อื่นStrategic Design (BBoM) หน้าที่​บอกว่า context เริ่ม​และ​จบ​ตรง​ไหน​เป็น​ของ Context MapContext Mapแผนภาพ​ที่​แสดง Bounded Context ทั้งหมด​และ​ความ​สัมพันธ์​ระหว่าง​กัน ช่วย​ให้​เห็น​ภาพ​รวม​และ​จุด​เชื่อม​ต่อ/แปล​ภาษา​ใน​ระบบ​ใหญ่Strategic Design

ถ้า​ทีม​ไม่​เข้าใจ context อื่น การ​แก้​ของ​พวก​เขา​อาจ “รั่ว” ข้าม​ไป​กระทบ context นั้น เส้น​แบ่ง​ระหว่าง model ที่​พร่า​เลือน​หรือ​ไม่มี​เลย มัก​จบ​ลง​ที่​การ หลอม​รวม model เข้า​ด้วย​กัน ซึ่ง​เร่ง​ให้​เกิด BBoM อย่าง​รวดเร็ว ลอง​คิด​เหมือน​การ​ใช้ Single Responsibility Principle (SRP) ใน​ระดับ​สถาปัตยกรรม — แยก​แนวคิด​ที่​ไม่​เกี่ยวข้อง​กัน​ออก​ไป เพื่อ​ให้​แต่ละ model บริสุทธิ์​และ​โฟกัส

คำ​เดียวกัน ไม่​ได้​แปล​ว่า model เดียวกัน

ระวัง​เมื่อ domain expert ใช้ “คำ​เดิม” แต่​กำลัง​พูด​ใน​คนละ context การ​เห็น​คำ​ซ้ำ​กัน​ทำให้​หลง​คิด​ว่า​นำ model กลับ​มา​ใช้​ซ้ำ​ได้ — ให้​ใช้​หลัก DRY ภายใน bounded context เดียว เท่านั้น ไม่ใช่​ทั้ง​ระบบ อย่า​กลัว​ที่​จะ​ใช้​ชื่อ​และ​แนวคิด​เดียวกัน​ใน​คนละ context

🛒 e-commerce — “Product” ที่​ไม่ใช่​ตัว​เดียวกัน

คำ​ว่า Product ใน context “catalog” หมาย​ถึง​ชื่อ รูป คำ​บรรยาย รีวิว แต่​ใน context “คลัง​สินค้า” มัน​คือ SKU น้ำหนัก ขนาด​กล่อง จำนวน​คง​เหลือ ถ้า​ฝืน​ยัด​ทั้ง​สอง​ให้​เป็น class Product เดียว คุณ​จะ​ได้ god object ที่​เป็น​จุด​เริ่ม​ของ BBoM — 2 model แยก​กัน​ใน Bounded ContextBounded Contextขอบเขต​ที่​ชัดเจน (มัก​เป็น​ระบบ​ย่อย​หรือ​ทีม​หนึ่ง) ที่ model หนึ่ง​ใช้ได้​และ​มี​ความหมาย​แน่นอน ภายใน​ขอบเขต​นี้ Ubiquitous Language สอดคล้อง​กัน 100%Strategic Design ของ​ตัวเอง​ดี​กว่า

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

ถ้า​ไม่มี​ภาษา​กลาง​ร่วม​กัน คุณ​ก็​สร้าง model ร่วม​กัน​ไม่​ได้

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

ออกแบบ​โดย​เอา​เทคนิค​เป็น​ที่​ตั้ง เพราะ​ขาด​การ​ร่วมมือ

หัวข้อ​ที่​มีชื่อ​ว่า “ออกแบบ​โดย​เอา​เทคนิค​เป็น​ที่​ตั้ง เพราะ​ขาด​การ​ร่วมมือ”

ถ้า​ไม่​ร่วมมือ​กัน แนว​คิดสำคัญๆ ของ domain ที่​มัก “ซ่อน​อยู่​โดย​ปริยาย” (implicit) จะ​ถูก​มอง​ข้าม ทีม​จะ​ไป​คว้า​แต่​ผล​ที่​เก็บ​ง่าย (low-hanging fruit) — เช่น “คำ​นาม” ของ domain — แล้ว​สร้าง abstraction รอบๆ ศัพท์​เทคนิค การ​ร่วมมือ​คือ​การ​เอา​คน​หลาย​มุมมอง​มา​ช่วย​กัน​ปั้น model ไม่มี​ใคร​ผูกขาด​ไอเดีย​ดีๆ และ​ไม่มี​ข้อ​เสนอ​ไหน​โง่

Business Analyst แทน domain expert ไม่​ได้​เต็ม​ร้อย

BA ที่​ทำ​หน้าที่​เป็น​ตัวแทน domain expert จะ​ให้ requirement และ​บอก input/output ได้ แต่​จะ ช่วย​ปั้น model ให้​ตอบ use case ไม่​ได้ การ knowledge-crunch กับ​คน​ที่​ไม่ใช่ domain expert ตัว​จริง เสี่ยง​เป็นการ​เสียแรง​เปล่า


ทีม​ต้อง​เข้าใจ​ก่อน​ว่า ทำไม​ถึง​สร้าง​เอง แทนที่​จะ​ซื้อ​ของ​สำเร็จรูป​มา​ใช้ การ​เข้าใจ​วิสัยทัศน์​เชิงกลยุทธ์​และ​เหตุผล​ของ “build over buy” ช่วย​ให้​ทีม​รวม​แรง​ไป​ถูก​ที่ ทรัพยากร​มี​จำกัด ถ้า​ไม่​โฟกัส​ที่ Core DomainCore Domainsubdomain ที่​สำคัญ​และ​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน​มาก​ที่สุด เป็น​เหตุผล​ที่​เรา​ต้อง​สร้าง​ซอฟต์แวร์​เอง​แทน​การ​ซื้อ ควร​ทุ่ม​ทีม​เก่ง​ที่สุด​ลง​ตรง​นี้Strategic Design — ส่วน​ที่​เป็น​หัวใจ​ของ​ความ​สำเร็จ — แล้ว​เกลี่ย​คน​เก่งบางๆ ไป​ทั่ว​ทุก​ส่วน นั่น​คือ anti-pattern

ยอมรับ​ว่า​ไม่ใช่​ทุก​ส่วน​ต้อง​สวยงาม

ก้าว​สำคัญ​ของ​ทีม​คือ​การ ยอมรับ​ว่า​ไม่ใช่​ทุก​ส่วน​ของ​ระบบ​จะ​ถูก​ออกแบบอย่าง​ดี และ​ไม่ใช่​ทุก​ส่วน​จำเป็น​ต้อง​ถูก​ออกแบบอย่าง​ดี ถ้า​ไม่มี​โฟกัส​ที่​ส่วน​สำคัญ คน​เก่งๆ จะ​ถูก​ดึง​ไป​หมกมุ่น​กับ framework JavaScript ตัว​ใหม่​ที่​ชั้น presentation แทนที่​จะ​ปั้น core domain

นอกจาก​ทีม​แล้ว domain expert เอง​ก็​ต้อง​เข้าใจ core domain ชัดเจน expert ที่​ไม่ share วิสัยทัศน์​หรือ​ไม่รู้​ว่า​ทำไม​ต้อง​เขียน​ซอฟต์แวร์​นี้ จะ​ไม่มี​ประสิทธิภาพ​ใน​วง knowledge-crunching เพราะ​ความ​สับสน​หรือ​ความเฉื่อยชา


การ​เอา​เทคนิค​ที่​ออกแบบ​มา​จัดการ “ปัญหา​ซับซ้อน” ไป​ใช้​กับ domain ที่​แทบ​ไม่มี​ความ​ซับซ้อน​เลย อย่าง​ดี​ก็​เสียแรง​เปล่า อย่าง​แย่​ก็ได้ solution ที่​ซับซ้อน​เกิน​จำเป็น​จน​ดูแล​ยาก​เพราะ​ชั้น abstraction เป็นกอง DDD เหมาะ​กับ app ที่​สำคัญ​เชิงกลยุทธ์​เท่านั้น

นัก​พัฒนา​ที่​ไม่​ได้​สนใจ​การ​ส่ง​มอบ​คุณค่า แต่​สนุก​กับ​เทคนิค​ล้วนๆ มัก​จะ “ประดิษฐ์​ความ​ซับซ้อน​ขึ้น​มา​เอง” เพราะ​เบื่อ​ปัญหา​ธุรกิจ​ที่​ดู​ง่าย — แล้ว​ทิ้ง​ระเบิด​เวลา​ให้​คน​รุ่น​หลัง​ต้อง​มา​ดูแล​ชั้น abstraction ที่​ซ้อน​กัน​เป็นกอง​นั้น

ใช้ DDD กับ domain เล็กๆ ที่​ธุรกิจ​ไม่​ได้​คาด​หวัง​อะไร

หัวข้อ​ที่​มีชื่อ​ว่า “ใช้ DDD กับ domain เล็กๆ ที่​ธุรกิจ​ไม่​ได้​คาด​หวัง​อะไร”

ปัญหา​ง่ายๆ ต้องการ​คำ​ตอบ​ง่ายๆ SubdomainSubdomainส่วน​ย่อย​ของ Domain ใหญ่ เช่น Domain e-commerce แตก​เป็น subdomain การ​สั่ง​ซื้อ การ​ชำระ​เงิน คลัง​สินค้า ฯลฯ อยู่​ใน “พื้นที่​ปัญหา” (problem space)Strategic Design ที่​ไม่​ได้​สร้าง​ความ​ได้​เปรียบ​เชิงกลยุทธ์​จะ​ไม่​ได้​ประโยชน์​จาก​หลักการ DDD ทั้งหมด นี่​ไม่​ได้​แปล​ว่าให้ทำลวกๆ — มัน​ยัง​ต้อง​เร็ว​และ​ดูแล​ได้ แต่​ปัญหา​ที่​ตรรกะ​น้อย​ก็​ควร​ได้​คำ​ตอบ​ที่​ตรง​ไป​ตรง​มา

tactical patterns และ​การ​ลงแรง​สร้าง UL ควร​สงวน​ไว้​ให้ core subdomain เท่านั้น ส่วน generic/supporting subdomain แค่​ทำให้​มัน​ทำงาน​ได้​และ​แยก​ออก​จาก core ก็พอ

🛒 อย่า​ทำ Aggregate ให้​กับ​ฟอร์ม​แก้​ที่​อยู่

ใน core domain อย่าง “ตะกร้า/การ​ชำระ​เงิน” ของ e-commerce การ​ลงทุน​กับ rich model นั้น​คุ้ม แต่​หน้า​จอ “แก้​ที่​อยู่​จัด​ส่ง” ที่​เป็น​ฟอร์ม​กรอก​ข้อมูล​ล้วนๆ — แค่ CRUD ก็จบ การ​ไป​สร้าง Aggregate, Repository, Domain Service ให้​มัน​คือ​การ over-engineer ที่​ไม่​เพิ่ม​คุณค่า​ให้​ธุรกิจ​เลย

ไม่ใช่​ทุก​ส่วน​ของ​ระบบ​ที่​ต้อง​ออกแบบอย่าง​ดี การ​พยายาม​ขัด​ทั้ง codebase ให้​เพ​อร์เฟกต์คือ​การ​เสียแรง สำหรับ​ส่วน​ที่​แทบ​ไม่มี​ตรรกะ — แค่​ฟอร์ม​บน​ข้อมูล — เลือก CRUD / Active Record / Transaction ScriptTransaction Scriptรูปแบบ​ที่​จัด​ตรรกะ​ธุรกิจ​เป็น​ชุด​คำ​สั่ง​ตาม​ขั้นตอน (procedural) แทน​การกระจายลง​ใน​อ็อบเจ็กต์ เหมาะ​กับ​งาน​ง่าย ๆ แต่​จะ​รก​เมื่อ domain ซับซ้อน​ขึ้นArchitecture เพื่อ​ลด​เวลา​ที่​ใช้ แล้ว​เก็บ​เวลา​นั้น​ไว้​ทุ่ม​ให้ core domain คุณ ไม่​ได้ เป็น​โปรแกรมเมอร์​ที่​แย่​เพราะ​ไม่มี domain model

ถาม​ตัวเอง​เสมอ: ความ​ซับซ้อน​ที่​เพิ่ม​มา​นี้​คุ้ม​ไหม?

หัวข้อ​ที่​มีชื่อ​ว่า “ถาม​ตัวเอง​เสมอ: ความ​ซับซ้อน​ที่​เพิ่ม​มา​นี้​คุ้ม​ไหม?”

เวลา junior เพิ่ง​รู้จัก design pattern พวก​เขา​มัก​อยาก​เอา​ไป​ใช้​กับ​ทุก​บรรทัด พฤติกรรม​เดียวกัน​เกิด​กับ​คน​เพิ่ง​รู้จัก DDD — เอา tactical pattern ไป​แปะ​ทุก project โดย​ไม่​ดู​ว่า​คุ้ม​ไหม

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


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

พยายาม​สำเร็จ​โดย​ไม่มี​ทีม​ที่​มี​แรง​จูงใจ​และ​โฟกัส

หัวข้อ​ที่​มีชื่อ​ว่า “พยายาม​สำเร็จ​โดย​ไม่มี​ทีม​ที่​มี​แรง​จูงใจ​และ​โฟกัส”

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

  • หลักการ​ออกแบบ​ที่​แน่น​พอ​จะ refactor ได้​อย่าง​มั่นใจ
  • สายตา​ใน​การ​ออกแบบ​ที่​คม (sharp design sense)
  • ทีม​ที่​โฟกัส มี​แรง​จูงใจ และ​มี​ประสบการณ์
DDD ไม่ใช่​กระสุน​เงิน (silver bullet)

เหมือน​กับ​การ​เปลี่ยน​จาก waterfall มา​เป็น agile/XP ไม่​ได้​แก้​ทุก​ปัญหา การ​หัน​มา​ทำ DDD ก็​ไม่​ได้​ผลิต​ซอฟต์แวร์​ที่​ดี​ขึ้น​มา​เอง​โดย​อัตโนมัติ ปัจจัย​ร่วม​ของ​ทุก project ที่​สำเร็จ​คือ ทีม​คน​เก่ง​ที่​หลงใหล​ใน​งาน​และ​ใส่ใจ​ว่า​มัน​จะ​สำเร็จ

การ​เป็น​เจ้าของ​และ​การ​ลงทุน​ของ​ฝ่าย​ธุรกิจ โดย​เฉพาะ​จาก domain expert คือ​กุญแจ​ของ​การ​ร่วมมือ​ที่​ได้​ผล ถ้า expert ไม่​ได้​อิน​กับ project หรือ​ไม่​เข้าใจ​วิสัยทัศน์ ทีม​ก็​ยาก​จะ​ค้น​พบ model ที่​มี​ประโยชน์ ที่​น่า​สนใจ​คือ เมื่อ​ร่วมมือ​กับ expert จริงๆ บาง​ครั้ง​ทางออก​ที่​ดี​ที่สุด​คือ การ​ออกแบบ​กระบวนการ​ธุรกิจ (business process) เสีย​ใหม่​เพื่อ​ขจัด​ปัญหา​ที่​ต้นตอ จน​ไม่​ต้อง​เขียน​ซอฟต์แวร์​เลย​ด้วย​ซ้ำ

DDD คือ​การ brainstorm คือ​การ​เรียนรู้​ร่วม​กัน คือ​การ​ไม่​หยุด​ที่​ไอเดีย​แรก​แต่​ทดลอง​ต่อ​จน​เจอ​ของ​ที่​ดี​กว่า ทั้งหมด​นี้​ใช้​เวลา กระบวนการ​ที่​ไม่​รองรับ​การวน​ซ้ำ​ก็​รองรับ DDD ไม่​ได้

model ที่​ดี​จะ​ไม่​เกิด​ใน​ครั้ง​แรก model และ​ภาษา “ใช้ได้​เฉพาะ​ช่วง​เวลา​หนึ่ง” เท่านั้น ทีม​ที่​ไม่​เข้าใจ​ข้อ​นี้​จะ​เห็น​ของดี​ที่​ตัวเอง​สร้าง​ค่อยๆ กลาย​เป็น BBoM model ต้องการ​ความ​รัก ต้อง​ถูก​ขัดเกลา​และ refactor เมื่อ​เข้าใจ domain ลึก​ขึ้น​และ​มี use case ใหม่​มา​ท้าทาย

ต้อง​มี unit test เป็น​ตาข่าย​นิรภัย

จะ​ทดลอง​และ​วิวัฒน์ model ได้ ต้อง​มี unit test คอย​รองรับ ไม่​จำเป็น​ต้อง​ทำ TDD อย่าง​เคร่งครัด แต่​ต้อง​มั่นใจ​ว่า code ยัง​ถูกต้อง​หลัง​การ refactor หลายๆ รอบ

ทุก solution ต้อง​มี​ปัญหา​ที่​เหมาะ​กับ​มัน DDD เป็น​เครื่องมือ​ที่​ดี​ใน​กล่อง​เครื่องมือ แต่​ถ้า​ธุรกิจ​ไม่​ซับซ้อน​หรือ​ไม่​ค่อย​เปลี่ยน ก็​อย่า​รีบ​คว้า “ค้อน DDD” มา​ทุบ​ทุก​อย่าง — มี​เครื่องมือ​อื่น​ที่​เหมาะ​กว่า

flowchart TD
  A[bounded context นี้] --> B{ตรรกะธุรกิจ<br/>ซับซ้อน + เปลี่ยนบ่อย?}
  B -- ใช่ และเป็น core --> C[Model-Driven Design<br/>Rich Domain Model + UL]
  B -- ไม่ --> D[CRUD / Active Record /<br/>Transaction Script]

ยอม​แลก​ความ pragmatic เพื่อ​ความ​บริสุทธิ์​ที่​ไม่​จำเป็น

หัวข้อ​ที่​มีชื่อ​ว่า “ยอม​แลก​ความ pragmatic เพื่อ​ความ​บริสุทธิ์​ที่​ไม่​จำเป็น”

อย่า​ไล่​ตาม​ความ​สมบูรณ์​แบบ​ใน​ที่​ที่​ไม่​ต้องการ​มัน สำหรับ generic/supporting subdomain ให้​ทำให้​มัน​เรียบ​ง่าย เขียน​ให้​มัน​ทำงาน​ได้​แล้ว​เดิน​หน้า​ไป core domain ต่างหาก​คือ​ที่​ที่​คุณ​จะ​ตามหาความ​สมบูรณ์​แบบ​ได้ — ball of mud ก้อน​เล็กๆ ที่​ถูก​แยก​ออก​จาก context อื่น​อย่าง​ชัดเจน บางที​ก็​เป็น​ทาง​เลือก​ที่​ดี​กว่า เพราะ​เป็น code สำหรับ​โยน​ทิ้ง (throw-away code) ที่​เขียน​ได้​เร็ว เก็บ​ให้​พ้น​ทาง และ​ถ้า​ต้อง​เปลี่ยน​ก็​เขียน​ทับ​ใหม่​ได้​ทันที

เมื่อ​คุณ​สร้าง​ระบบ​ตาม​หลัก DDD จะ​ไม่มี​ใบ​ประกาศ​จาก Eric Evans ส่ง​มา​ทาง​ไปรษณีย์​ชม​ว่า​คุณ​ทำ​สำเร็จ การ​ทำ​ตาม pattern language หรือ methodology อย่าง​หลับ​หู​หลับตา​โดย​ไม่​คำนึง​ถึง context เฉพาะ​ของ​ตัวเอง คือ​ความ​เขลา

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

อย่า​พยายาม​สร้าง repository pattern ที่​เพ​อร์เฟกต์ และ​อย่า​ไป​ขอ​คำ​ยืนยัน​จาก​เพื่อน​ที่​ไม่​ได้​อยู่​ใน project เพราะ​ถ้า​ไม่มี context ครบ คำ​แนะนำ​นั้น​ต้อง​รับ​ไว้​แบบ​มี​ข้อ​สงสัย

ทีม​ที่​หมกมุ่น​กับ​การ​แปะ design pattern โดย​ไม่​ดู​ความ​จำเป็น​จริง มักได้​สถาปัตยกรรม​ที่​ซับซ้อน​เกิน​จน​พลาด​เป้าหมาย​ของ​ผลิตภัณฑ์ ใน​ส่วน​สำคัญ​ที่​เปลี่ยน​บ่อย การ​มี supple design (design ที่​ยืดหยุ่น) ช่วย​ให้ model ปรับ​ตัว​ได้​โดย​ไม่​กระเพื่อม​ไป​ทั้ง​ระบบ แต่​การ​เค้น design ให้​สง่างาม​ใน​ที่​ที่​ไม่มี​คุณค่า​ทาง​ธุรกิจ คือ​การ​ลงแรง​ที่​สูญเปล่า

🚢 อยู่​กับ code สัก​พัก​ก่อน​ตัดสิน​ใจ pattern

ใน​ตอน​ทำ core domain ของ​ระบบ​ขนส่ง ทีม​ควร “รอ” ก่อน​ผูกมัด​กับ pattern ใด pattern หนึ่ง การ​ชะลอ​การ refactor แล้ว​อยู่​กับ code เพื่อ​ดู​ว่า​ตรง​ไหน​เสียดสี​หรือ​เปลี่ยน​บ่อย​ที่สุด จะ​เผย​ความ​จริง​ของ domain ออก​มา และ​นำ​ไป​สู่​การ​เลือก design ที่​มี​ข้อมูล​รองรับ​มากกว่า

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

อย่า​ให้ design pattern และ​หลักการ​มา​ขวาง​การ​ส่ง​มอบ​คุณค่า DDD คือ​การ​มอบ​คุณค่า ไม่ใช่​การ​ผลิต code สง่างาม — pattern เป็น​เพียง​รายละเอียด​การ implement เป้าหมาย​จริง​คือ​เข้าใจ domain ให้​ลึก​พอ​จะ​แก้​ปัญหา​ใน​นั้น​ได้


  • tactical patterns ช่วย​สร้าง domain model ที่​ดี​ได้ แต่​เป็น​ส่วน​ที่​ถูก​ให้​น้ำหนัก​เกิน​จริง — คุณค่า​ของ DDD ไม่​ได้​อยู่​ตรง​นี้
  • DDD เป็น​มากกว่า​การ​เขียน code: การ​ร่วมมือ​กับ domain expert เพื่อ knowledge-crunch และ​มี​ความ​เข้าใจ​ร่วม​ที่​แสดงออก​ผ่าน Ubiquitous Language คือ​เสา​หลัก
  • Context คือ​ทุก​สิ่ง — การ​แบ่ง context และ​แยก​ส่วน​ช่วย​รักษา​ความ​ถูกต้อง​ของ code ลด​ภาระ​ทาง​ความคิด (cognitive load) และ​ทำให้​แต่ละ model คม​ชัด​และ​โฟกัส
  • คุณ​ต้อง​มี​ทีม​เก่ง​ที่​ทุ่มเท​และ​เต็มใจ​เรียนรู้ domain และ​ต้อง​เข้าถึง domain expert ได้
  • ใช้ CRUD กับ bounded context ที่​ความ​ซับซ้อน​ต่ำ​ได้​เลย — ไม่มี domain model ไม่​ได้​แปล​ว่า​คุณ​เป็น​โปรแกรมเมอร์​ที่​แย่
  • Bounded Context และ Ubiquitous Language คือ​รากฐาน​ของ DDD และ DDD คือ​กระบวนการ​ของ​การ​เรียนรู้ ขัดเกลา ทดลอง และ​สำรวจ เพื่อ​ค้น​พบ model ที่​มี​ประโยชน์​ร่วม​กัน

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

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

  • Tactical Design — ทำความ​เข้าใจ​ว่า tactical patterns คือ​อะไร​และ​ควร​อยู่​ตรง​ไหน​ใน​ภาพ​รวม ก่อน​จะ​ให้​น้ำหนัก​กับ​มัน​มาก​เกิน​ไป​แบบ​ที่​บท​นี้​เตือน
  • Strategic Design — ส่วน​ที่​หนังสือ​ย้ำ​ว่า​สำคัญ​กว่า tactical แต่​ทีม​มือใหม่​มัก​มอง​ข้าม
  • Bounded Context — แก่น​ของ​ปัญหา “Big Ball of Mud” ที่​เกิด​จาก​การ​มอง​ข้าม​ขอบเขต context ตาม​ที่​บท​นี้​อธิบาย
  • Ubiquitous Language — ภาษา​กลาง​ที่​ขาด​ไม่​ได้​สำหรับ​การ​ร่วมมือ​กับ domain expert ซึ่ง​เป็น​คุณค่า​แท้จริง​ของ DDD ตาม​ที่​บท​นี้​เน้น​ย้ำ

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

ข้อ 1 / 4

ตามหนังสือ ทำไมการให้น้ำหนักกับ tactical patterns มากเกินไปจึงเป็นปัญหา?