ลงมือใช้ 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 อย่างไรไม่ให้พัง
หัวข้อที่มีชื่อว่า “ขาย DDD อย่างไรไม่ให้พัง”DDD ไม่ใช่กระสุนเงิน (silver bullet) และอย่าขายมันแบบนั้น เช่นเดียวกับที่ agile ไม่ได้แก้ทุกปัญหา DDD ก็เช่นกัน — แต่มันทรงพลังมาก เมื่อใช้ถูกสถานการณ์ สถานการณ์ที่เหมาะคือ
- ทีมที่เก่ง มีไฟ และอยากเรียนรู้
- problem domain ที่ไม่ธรรมดา และ สำคัญต่อธุรกิจ
- เข้าถึง domain expert ที่เห็นภาพเดียวกับวิสัยทัศน์ของ project ได้
- ทีมทำงานแบบ iterative
หากขาดวัตถุดิบเหล่านี้ การฝืนใช้ DDD จะทำให้งาน ซับซ้อนขึ้น แทนที่จะง่ายลง
เวลาสื่อสาร DDD กับทีม อย่าเริ่มที่ pattern language แต่ให้เน้น การ align กับธุรกิจ ความสำคัญของ strategic context และการให้น้ำหนักกับ ภาษา ที่ใช้อธิบาย model — strategic DDD ทรงพลังกว่า tactical pattern มาก ทีมที่หมกมุ่นอยู่แต่ software pattern จะจ่ายต้นทุนของ DDD ไปเต็มๆ โดยไม่ได้รางวัลของมันกลับมาเลย
ส่วนเวลาคุยกับ ฝ่ายธุรกิจ อย่าไปพูดเรื่องปรัชญาการพัฒนาตัวใหม่ stakeholder ไม่อยากฟังคำว่า agile, SOA หรือ cloud อีกแล้ว — เพราะทุกอย่างถูกโฆษณาเกินจริงมาหมด พูดเพียงสิ่งเดียวก็พอ: “เราอยากเข้าใจธุรกิจของคุณให้ลึกขึ้น เพื่อส่งมอบคุณค่าได้มากขึ้น” แล้วอธิบายว่าทำไมทีมพัฒนาจึงต้องใช้เวลากับผู้เชี่ยวชาญธุรกิจ นี่แหละคือวิธีขาย DDD ที่แท้จริง เพราะ DDD ไม่ทำงานเลยหากไม่มี commitment จาก domain expert
นำหลักการของ DDD ไปใช้ — ทีละขั้น
หัวข้อที่มีชื่อว่า “นำหลักการของ DDD ไปใช้ — ทีละขั้น”เมื่อธุรกิจเข้าใจคุณค่าของเวลา domain expert และทีมโฟกัสที่การแก้ปัญหารอบๆ model ที่สร้างร่วมกัน คุณก็พร้อมลงมือแล้ว ลำดับขั้นด้านล่างนี้คือเส้นทางจาก “จุดเริ่ม project” ไปสู่ “solution”
1. เข้าใจวิสัยทัศน์ก่อนเก็บ requirement
หัวข้อที่มีชื่อว่า “1. เข้าใจวิสัยทัศน์ก่อนเก็บ requirement”ก่อนจะจดความต้องการ ต้อง align ทีมกับความคาดหวังของ stakeholder ก่อน เปิดประชุมด้วยคำถามปลายเปิดที่ดึง “เหตุผลที่เลือกสร้างเองแทนการซื้อ” ออกมา เช่น
- เป้าหมาย/แรงขับทางธุรกิจของผลิตภัณฑ์นี้คืออะไร?
- มันจะสร้างคุณค่าอะไรให้ธุรกิจ?
- เราจะรู้ได้ยังไงว่ามันสำเร็จ? “ดี” หน้าตาเป็นยังไง?
- มันต่างจากของเดิมที่เคยมียังไง?
จากคำตอบ คุณจะระบุ ส่วนที่สำคัญที่สุด ของผลิตภัณฑ์ได้ แล้วเขียนมันออกมาเป็น Domain Vision StatementDomain Vision Statementคำแถลงวิสัยทัศน์ของ domain — ข้อความสั้น ๆ ที่จับใจความว่าอะไรคือหัวใจของความสำเร็จของซอฟต์แวร์ เป้าหมายธุรกิจคืออะไร และคุณค่าอยู่ตรงไหน ใช้สร้างความเข้าใจร่วมกันในทีมว่าอะไรคือ coreStrategic Design ที่ดึงทั้งทีมไปสู่เป้าหมายเดียวกัน บางครั้งคุณอาจพบว่าผลิตภัณฑ์นี้จริงๆ แล้วเป็นของ generic ที่แค่ทำเองคุ้มกว่า — ถ้าใช่ ก็พูดให้ชัด
2. จับกระบวนการธุรกิจที่ต้องการ (BDD)
หัวข้อที่มีชื่อว่า “2. จับกระบวนการธุรกิจที่ต้องการ (BDD)”วิธีดึง 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 ให้กับความต้องการที่ธุรกิจไม่ได้มีอยู่จริง
3. กลั่น problem space
หัวข้อที่มีชื่อว่า “3. กลั่น problem space”เมื่อ story card เริ่มเยอะจนผลิตภัณฑ์ใหญ่เกินจะจัดการ หรือเริ่มมีความกำกวม ให้ลดภาระทางความคิดด้วยการ ยกระดับ abstraction โดยแตกออกเป็น SubdomainSubdomainส่วนย่อยของ Domain ใหญ่ เช่น Domain e-commerce แตกเป็น subdomain การสั่งซื้อ การชำระเงิน คลังสินค้า ฯลฯ อยู่ใน “พื้นที่ปัญหา” (problem space)Strategic Design วิธีที่ดีคือมองหา business capability (กิจกรรมที่หนุนกระบวนการธุรกิจ) แล้วสร้าง subdomain จากตรงนั้น บางอันจะเป็น generic บางอันเป็น supporting — แต่อันที่ทำให้ผลิตภัณฑ์อยู่หรือตายคือ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design
4. โฟกัสที่สิ่งที่สำคัญจริง
หัวข้อที่มีชื่อว่า “4. โฟกัสที่สิ่งที่สำคัญจริง”เมื่อแตก 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 ต่างๆ ที่จะกระทบหรือถูกกระทบโดยผลิตภัณฑ์ของคุณ แล้วทำตามขั้นตอน
- หาว่ามี model/context ใดบ้างที่เกี่ยวข้อง วาดมันออกมา ตั้งชื่อ และระบุว่าใครรับผิดชอบ (ถ้าไม่รู้จะเริ่มตรงไหน ให้ดูโครงสร้างองค์กร เพราะระบบส่วนใหญ่สร้างตามการสื่อสารระหว่างแผนก)
- map จุดเชื่อมต่อและวิธี integrate
- map ข้อมูลที่แลกเปลี่ยนกัน และใครเป็นเจ้าของ
- ติดป้ายความสัมพันธ์ — ทีมคุณเป็น downstreamUpstream / Downstreamความสัมพันธ์ที่การกระทำของฝ่ายต้นน้ำ (upstream) ส่งผลต่อฝ่ายปลายน้ำ (downstream) แต่ไม่ใช่ในทางกลับกัน — ทิศของอิทธิพลStrategic Design ที่ต้องพึ่งทีมอื่น หรือเป็น upstream ที่ต้องแจ้งการเปลี่ยนแปลงให้ทีมปลายน้ำ?
ในระบบ Cargo Shipping ทีมจองและวางแผนเดินทาง (Booking) ต้องคุยกับ context การติดตามสินค้า (Tracking) และระบบศุลกากร/ภาษีของบุคคลที่สาม ลองวาด Context Map ติดผนังให้ทุกคนเห็น — นี่คือ “แผนที่สงคราม” ของทีม
มันต้องเรียบง่ายพอที่ใครก็วาดได้เร็ว อย่าเสียเวลาทำ UML ให้สวยงาม ขอแค่เห็นภาพมุมสูงก่อน แล้วค่อยซูมเข้าไปดูจุดเชื่อมต่อเมื่อถึงเวลา integrate จริง
เกณฑ์ก่อนลงมือ model: ทุกปัญหาไม่ได้เท่ากัน
หัวข้อที่มีชื่อว่า “เกณฑ์ก่อนลงมือ model: ทุกปัญหาไม่ได้เท่ากัน”ก่อนจะลงทุนสร้าง 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 expert และ model รอบ scenario จริง
หัวข้อที่มีชื่อว่า “ทำงานกับ domain expert และ model รอบ scenario จริง”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 ที่ใช้ประโยชน์ได้จริง
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 ธรรมดาจะทำให้เขาเบื่อและหมดความสนใจในตัวคุณอย่างรวดเร็ว
วิวัฒน์ Ubiquitous Language เพื่อขจัดความกำกวม
หัวข้อที่มีชื่อว่า “วิวัฒน์ Ubiquitous Language เพื่อขจัดความกำกวม”ความกำกวม บวกกับความไม่รู้ใน 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
SpecificationSpecificationobject ที่ห่อหุ้ม ‘กฎทางธุรกิจ’ ที่บางส่วนของ domain model ต้องทำให้เป็นจริง ใช้เป็นเกณฑ์ query ได้ด้วย หัวใจคือ method isSatisfiedBy(...) — เป็นเครื่องมือทำ logic ที่ implicit ให้ explicitTactical Design คือ object ที่แทน กฎทางธุรกิจ ที่อย่างน้อยบางส่วนของ domain model ต้องทำให้เป็นจริง มันยังใช้เป็นเกณฑ์ query ได้ด้วย — เช่น “หา object ทั้งหมดที่ผ่านเกณฑ์ของ specification นี้” หัวใจคือ method isSatisfiedBy(...)
ทิ้ง model แรก แล้วทิ้ง model ที่สองด้วย
หัวข้อที่มีชื่อว่า “ทิ้ง model แรก แล้วทิ้ง model ที่สองด้วย”ตอนเริ่ม project คุณรู้น้อยที่สุด แต่กลับเป็นช่วงที่ต้องตัดสินใจเรื่องสำคัญที่สุด model แรกของคุณจะผิดเสมอ — แต่อย่ายึดติด การเรียนรู้ problem domain เกิดขึ้นผ่าน iteration หลายรอบ ปัญหาคือพอทีมได้ model แรกที่ “ใช้ได้” ส่วนใหญ่ก็หยุดสำรวจแล้วรีบไปพิมพ์ code ทันที
สำหรับทุกการออกแบบที่ดี ต้องมีการออกแบบที่แย่อย่างน้อยสามแบบมาก่อน
— Eric Evans
พอได้ model ที่ดีแล้ว ให้ “พักมันไว้” แล้วสำรวจปัญหาจากมุมใหม่ การทดลองและสำรวจคือเชื้อเพลิงของการค้นพบ บางครั้ง model พาคุณเข้ามุมอับ scenario ใหม่ใส่ไม่ได้ — นั่นก็ปกติ อย่าฝืนยัด scenario เข้า model เดิม ให้สร้าง model ใหม่ที่ตอบทั้ง scenario เก่าและใหม่ ผลลัพธ์ที่แท้จริงไม่ใช่ “model สมบูรณ์แบบ” แต่คือ การเรียนรู้และค้นพบ concept ใน domain
อย่ายึดติดกับไอเดีย — มีเพียงการลองผิดลองถูกเท่านั้นที่จะเผย concept ใน domain ออกมา เคล็ดลับเชิงปฏิบัติ: เขียน code ทดลอง (spike) ไว้ใน namespace ของ test ก่อน จนกว่าจะพอใจกับ design แล้วคุณจะ กล้าทิ้ง model ที่ไร้ประโยชน์ได้ง่ายกว่ามาก เพราะยังไม่ได้ commit มันเข้า application namespace
ทำสิ่งที่ implicit ให้ explicit
หัวข้อที่มีชื่อว่า “ทำสิ่งที่ implicit ให้ explicit”เวลาทำงานลึกใน codebase ทีมมักมองข้าม logic บางก้อนว่าเป็นแค่ “รายละเอียดการเขียนโปรแกรม” ทั้งที่มันซ่อนรายละเอียดสำคัญของ domain ไว้ ถ้าไม่ทำให้มัน explicit มันจะไม่ถูกเพิ่มเข้า mental model และการค้นพบครั้งต่อๆ ไปจะยากขึ้น
ลองดูกฎจริงข้อหนึ่ง: เว็บ e-commerce ห้ามลูกค้าต่างประเทศใส่สินค้าชนิดเดียวเกิน 50 ชิ้นในตะกร้า version แรกมักเขียนกฎฝังลงไปใน method ตรงๆ
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 ที่มีตัวตนขึ้นมาจริงๆ
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 ไว้ทีหลัง
มีเพียง 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

สรุปประเด็นสำคัญ (The Salient Points)
หัวข้อที่มีชื่อว่า “สรุปประเด็นสำคัญ (The Salient Points)”- อย่าขาย 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:
- 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 ไปใช้จริงคืออะไร?