Strategic Design ด้วย Bounded Context และ Ubiquitous Language
ของสองชิ้นที่เรียกว่า Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design กับ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design นั้นคืออะไรกันแน่? พูดสั้นที่สุด DDD คือการสร้าง model ของ Ubiquitous Language ไว้ภายใน Bounded Context ที่ขีดขอบเขตไว้อย่างชัดเจน — ซึ่งคำอธิบายแบบนี้ก็คงยังไม่ค่อยช่วยให้เห็นภาพเท่าไร เรามาแกะมันออกทีละชั้นกัน
graph TD
subgraph BC["Bounded Context"]
A["แนวคิด A"] --> B["แนวคิด B"]
A --> C["แนวคิด C"]
end
UL["Ubiquitous Language — ภาษากลางที่ใช้ทั้งพูดและเขียนลงใน code"]
BC -.- UL
อย่างแรก Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design คือ ขอบเขตเชิงความหมายตามบริบท (semantic contextual boundary) หมายความว่า ภายในขอบเขตนี้ แต่ละคอมโพเนนต์ของซอฟต์แวร์ model มีความหมายเฉพาะเจาะจงและทำสิ่งเฉพาะเจาะจง คอมโพเนนต์ที่อยู่ข้างในล้วนผูกกับบริบทและมีแรงจูงใจเชิงความหมายกำกับอยู่ แค่นี้ก็เข้าใจได้
ตอนเพิ่งเริ่มลงมือสร้าง model Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ยังค่อนข้างเป็นนามธรรม มองได้ว่าเป็นส่วนหนึ่งของ พื้นที่ปัญหา (Problem Space)Problem Space“พื้นที่ปัญหา” — สิ่งที่ธุรกิจต้องการแก้ไข อยู่ในรูปของ Domain และ Subdomain (ยังไม่พูดถึงวิธีแก้)Strategic Design แต่เมื่อ model เริ่มมีความหมายลึกและคมชัดขึ้น Bounded Context จะแปรเปลี่ยนไปสู่ พื้นที่คำตอบ (Solution Space)Solution Space“พื้นที่คำตอบ” — วิธีที่เราเลือกแก้ปัญหา อยู่ในรูปของ Bounded Context และ model 1 subdomain อาจมีได้หลายคำตอบStrategic Design อย่างรวดเร็ว โดยมีซอฟต์แวร์ model ปรากฏออกมาเป็น source code ของ project จำไว้ว่า Bounded Context คือที่ที่ model ถูก implement จริง และเราจะมี software artifact แยกต่างหากสำหรับแต่ละ Bounded Context
พื้นที่ปัญหาและพื้นที่คำตอบคืออะไร (What Is a Problem Space and a Solution Space?)
หัวข้อที่มีชื่อว่า “พื้นที่ปัญหาและพื้นที่คำตอบคืออะไร (What Is a Problem Space and a Solution Space?)”พื้นที่ปัญหา (Problem Space)Problem Space“พื้นที่ปัญหา” — สิ่งที่ธุรกิจต้องการแก้ไข อยู่ในรูปของ Domain และ Subdomain (ยังไม่พูดถึงวิธีแก้)Strategic Design คือที่ที่เราทำการวิเคราะห์และออกแบบเชิงกลยุทธ์ระดับสูง ภายใต้ข้อจำกัดของ project หนึ่งๆ ตรงนี้ใช้แค่ไดอะแกรมก็พอ ระหว่างที่ถกเรื่องตัวขับเคลื่อนระดับ project พร้อมจดเป้าหมายและความเสี่ยงสำคัญไว้ Context MapContext Mapแผนภาพที่แสดง Bounded Context ทั้งหมดและความสัมพันธ์ระหว่างกัน ช่วยให้เห็นภาพรวมและจุดเชื่อมต่อ/แปลภาษาในระบบใหญ่Strategic Design ทำงานได้ดีมากในพื้นที่ปัญหา และ Bounded Context ก็นำมาใช้ในการถกพื้นที่ปัญหาได้เมื่อจำเป็น แม้ว่าโดยธรรมชาติมันจะผูกแน่นกับพื้นที่คำตอบมากกว่า
พื้นที่คำตอบ (Solution Space)Solution Space“พื้นที่คำตอบ” — วิธีที่เราเลือกแก้ปัญหา อยู่ในรูปของ Bounded Context และ model 1 subdomain อาจมีได้หลายคำตอบStrategic Design คือที่ที่เรา implement ทางออกที่การถกในพื้นที่ปัญหาได้ระบุไว้ว่าเป็น Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design ของเรา เมื่อ Bounded Context ถูกพัฒนาขึ้นในฐานะ ความริเริ่มเชิงกลยุทธ์ที่สำคัญ ขององค์กร เราเรียกมันว่า Core Domain เราพัฒนาทางออกใน Bounded Context นั้นเป็น code ทั้ง main source และ test source และยังต้องผลิต code ในพื้นที่คำตอบที่รองรับการเชื่อมต่อ (integration) กับ Bounded Context อื่นด้วย
ซอฟต์แวร์ model ที่อยู่ภายในขอบเขตนั้นสะท้อนภาษาที่ทีมในแต่ละ Bounded Context พัฒนาขึ้นและพูดกันทุกคน ภาษานี้เรียกว่า Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design เพราะมันทั้งถูกพูดในหมู่สมาชิกทีมและถูก implement ในซอฟต์แวร์ model ดังนั้น Ubiquitous Language จึงต้อง เคร่งครัด แม่นยำ รัดกุม และกระชับ ในไดอะแกรม กล่อง (box) ภายใน Bounded Context แทนแนวคิดของ model ซึ่งอาจถูก implement เป็น class
เมื่อเทียบกับซอฟต์แวร์ทั้งหมดที่องค์กรใช้ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design คือ model ที่ติดอันดับสำคัญที่สุด เพราะมันคือหนทางสู่ความยิ่งใหญ่ Core Domain ถูกพัฒนาขึ้นเพื่อ สร้างความแตกต่างให้องค์กรเหนือคู่แข่งทั้งหมด อย่างน้อยที่สุดมันต้องตอบโจทย์สายธุรกิจหลักสายหนึ่ง องค์กรเก่งทุกเรื่องไม่ได้และไม่ควรพยายามด้วยซ้ำ จึงต้องเลือกอย่างชาญฉลาดว่าอะไรควรเป็นส่วนหนึ่งของ Core Domain และอะไรไม่ควร นี่คือคุณค่าหลักที่ DDD เสนอ — เราต้องลงทุนให้เหมาะสมด้วยการทุ่มทรัพยากรที่ดีที่สุดลงใน Core Domain
Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design คือ ขอบเขตของภาษา — ภายในขอบเขตนี้ทุกคำใน model มีความหมายเดียวที่แน่นอน ออกนอกเส้นนี้ คำเดียวกันมีสิทธิ์หมายถึงคนละสิ่ง และนั่นคือเรื่องปกติ Bounded Context ที่เป็นความริเริ่มเชิงกลยุทธ์สำคัญที่สุดเรียกว่า Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design — เป็นที่ที่ต้องทุ่มทีมเก่งที่สุดลงไป
Bounded Context, ทีม และ Source Code Repository (Bounded Contexts, Teams, and Source Code Repositories)
หัวข้อที่มีชื่อว่า “Bounded Context, ทีม และ Source Code Repository (Bounded Contexts, Teams, and Source Code Repositories)”เมื่อมีใครในทีมใช้สำนวนจาก Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ทุกคนในทีมเข้าใจตรงกันว่าหมายถึงอะไร อย่างแม่นยำและมีข้อจำกัดชัดเจน สำนวนนั้น “แพร่อยู่ทั่ว (ubiquitous)” ภายในทีม เช่นเดียวกับภาษาทั้งหมดที่ทีมใช้นิยามซอฟต์แวร์ model ที่กำลังพัฒนา
ลองนึกถึงภาษาในซอฟต์แวร์ model เหมือนนานาประเทศที่ประกอบกันเป็นทวีปยุโรป ภายในเยอรมนี ฝรั่งเศส และอิตาลี ภาษาราชการของแต่ละประเทศชัดเจนและแน่นอน แต่เมื่อข้ามพรมแดน ภาษาราชการก็เปลี่ยนไป เอเชียก็เช่นกัน — ญี่ปุ่นพูดญี่ปุ่น ส่วนภาษาที่พูดในจีนและเกาหลีก็แตกต่างกันชัดเจนตามเส้นพรมแดน Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ก็มองได้แบบเดียวกัน คือเป็น ขอบเขตของภาษา ในกรณีของ DDD ภาษาเหล่านี้คือภาษาที่ทีมเจ้าของซอฟต์แวร์ model พูดกัน และรูปแบบลายลักษณ์อักษรที่สำคัญของภาษานั้นก็คือ source code ของ model
ในภาษามนุษย์ คำศัพท์วิวัฒน์ตามกาลเวลา และข้ามพรมแดนคำเดิมๆ ก็แฝงนัยที่ต่างออกไป ลองนึกถึงคำสเปนที่ใช้ในสเปนกับคำเดียวกันที่ใช้ในโคลอมเบีย ที่แม้แต่การออกเสียงก็เปลี่ยน มันมีทั้งสเปนแบบสเปนและสเปนแบบโคลอมเบีย ภาษาในซอฟต์แวร์ model ก็เช่นกัน เป็นไปได้ว่าคนจากทีมอื่นจะให้ความหมายกับศัพท์เดียวกันต่างออกไป เพราะความรู้ทางธุรกิจของเขาอยู่ในบริบทอื่น เขากำลังพัฒนา Bounded Context คนละอันต่างหาก คอมโพเนนต์ใดๆ ที่อยู่นอกบริบทเราไม่คาดหวังว่าจะยึดนิยามเดียวกัน อันที่จริงมันคงต่างกัน — จะเล็กน้อยหรือมหาศาลก็ตาม จากคอมโพเนนต์ที่ทีมเราสร้าง และนั่นไม่เป็นไรเลย
ควรมี หนึ่งทีมต่อหนึ่ง Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design และควรมี source code repository แยกต่างหาก สำหรับแต่ละ Bounded Context ทีมหนึ่งอาจทำงานหลาย Bounded Context ได้ แต่ หลายทีมไม่ควรมาทำ Bounded Context เดียวกัน ให้แยก source code และ database schema ของแต่ละ Bounded Context ออกจากกันให้สะอาด เหมือนที่เราแยก Ubiquitous Language และเก็บ acceptance test กับ unit test ไว้คู่กับ main source code
การที่หนึ่งทีมทำ1 Bounded Context ตัดโอกาสเกิด “เซอร์ไพรส์ไม่พึงประสงค์” ที่มาจากการที่ทีมอื่นเข้ามาแก้ source code ของเราโดยสิ้นเชิง ทีมเราเป็นเจ้าของ code และ database และนิยาม interface อย่างเป็นทางการที่คนอื่นต้องใช้ผ่านมันเข้ามา — นี่คือประโยชน์ข้อหนึ่งของการใช้ DDD
เพื่อให้เห็นเหตุผลใหญ่ข้อหนึ่งของการใช้ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ลองพิจารณาปัญหาที่พบบ่อยในการออกแบบซอฟต์แวร์ ทีมจำนวนมากไม่รู้ว่าควรหยุดยัดแนวคิดลงใน domain model เมื่อไร model อาจเริ่มจากเล็กและจัดการได้… แต่แล้วทีมก็เพิ่มแนวคิดเข้าไปอีก อีก และอีก ไม่นานก็เกิดปัญหาใหญ่ — ไม่เพียงแนวคิดเยอะเกินไป แต่ภาษาของ model ก็เริ่มเบลอ เพราะเมื่อพินิจดูแล้ว จริงๆ มันมี หลายภาษาปนกันใน model ใหญ่ก้อนเดียวที่สับสนและไร้ขอบเขต
graph TD P["Product"] --> B["BacklogItem"] P --> R["Release"] P --> S["Sprint"] B --> T["Task"] R --> SB["ScheduledBacklogItem"] S --> CB["CommittedBacklogItem"] T --> E["EstimationLogEntry"]
เพราะข้อบกพร่องนี้ ทีมมักเปลี่ยนผลิตภัณฑ์ซอฟต์แวร์ใหม่เอี่ยมให้กลายเป็นสิ่งที่เรียกว่า Big Ball of MudBig Ball of Mudระบบที่ปนเปกันยุ่งเหยิงไม่มีขอบเขตชัด ให้ลากเส้นล้อมไว้แล้วยอมรับสภาพ ไม่พยายามทำ model ละเอียดในนั้น และระวังไม่ให้ลามไป context อื่นStrategic Design — ก้อนโคลนใหญ่ที่ไม่มีอะไรน่าภูมิใจ มันเป็น monolith และแย่กว่านั้นด้วย คือเป็นระบบที่มีหลาย model พันกันยุ่งโดยไม่มีขอบเขตชัดเจน อาจต้องใช้หลายทีมมาช่วยกันทำซึ่งยิ่งเป็นปัญหา แนวคิดที่ไม่เกี่ยวกันกระจายไปทั่วหลาย module เชื่อมโยงด้วย element ที่ขัดแย้งกันเอง ถ้า project นี้มี test มันก็คงรันนานมากจน test ถูกข้ามในช่วงที่สำคัญที่สุด นี่คือผลผลิตของการพยายามทำมากเกินไป โดยคนมากเกินไป ในที่ที่ผิด ความพยายามจะพูด Ubiquitous Language ก็ได้แต่ภาษาถิ่นที่แตกร้าวและนิยามไม่ชัด จนถูกทิ้งไปในที่สุด ภาษาแบบนี้ไม่ได้ถูกคิดมาอย่างดีแม้แต่เท่ากับภาษาเอสเปรันโต (ภาษาประดิษฐ์ที่ออกแบบมาอย่างตั้งใจ — แต่ยังถูกคิดมาดีกว่าภาษาของ Big Ball of Mud เสียอีก) มันเป็นแค่ความยุ่งเหยิง เหมือน Big Ball of Mud
Domain Expert และตัวขับเคลื่อนทางธุรกิจ (Domain Experts and Business Drivers)
หัวข้อที่มีชื่อว่า “Domain Expert และตัวขับเคลื่อนทางธุรกิจ (Domain Experts and Business Drivers)”บ่อยครั้งมีคำใบ้ที่ชัดเจน หรืออย่างน้อยก็แผ่วๆ จากผู้มีส่วนได้ส่วนเสียทางธุรกิจ ที่จะช่วยทีมเทคนิคตัดสินใจสร้าง model ได้ดีขึ้น Big Ball of MudBig Ball of Mudระบบที่ปนเปกันยุ่งเหยิงไม่มีขอบเขตชัด ให้ลากเส้นล้อมไว้แล้วยอมรับสภาพ ไม่พยายามทำ model ละเอียดในนั้น และระวังไม่ให้ลามไป context อื่นStrategic Design จึงมักเป็นผลของความพยายามอันไร้สติยั้งของทีมนักพัฒนาที่ไม่ฟัง ผู้เชี่ยวชาญธุรกิจ (Domain Expert)Domain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design
การแบ่งแผนกหรือกลุ่มงานของธุรกิจมักเป็นตัวบ่งชี้ที่ดีว่าขอบเขตของ model ควรอยู่ตรงไหน เรามักพบ Domain Expert อย่างน้อยหนึ่งคนต่อ1 business function แม้สมัยนี้จะมีแนวโน้มจัดคนตาม project มากขึ้นและจัดตาม functional group ตามลำดับชั้นการบริหารน้อยลง แต่แม้ใน model ธุรกิจแบบใหม่ๆ เราก็ยังพบว่า project ถูกจัดตามตัวขับเคลื่อนทางธุรกิจและภายใต้พื้นที่ของความเชี่ยวชาญอยู่ดี
จะรู้ได้ว่าจำเป็นต้องแบ่งแยกแบบนี้ ก็เมื่อพิจารณาว่าแต่ละ business function มักมีนิยามต่างกันสำหรับ คำเดียวกัน ลองดูแนวคิดชื่อ “Policy” (กรมธรรม์) และดูว่าความหมายต่างกันอย่างไรข้าม business function ของธุรกิจประกันภัย เห็นได้ชัดว่า Policy ในงาน Underwriting (การพิจารณารับประกัน) ต่างจาก Policy ในงาน Claims (การเคลม) และ Policy ในงาน Inspections (การตรวจสอบ) อย่างมาก Policy ในแต่ละพื้นที่ธุรกิจมีอยู่ด้วยเหตุผลที่ต่างกัน เป็นข้อเท็จจริงที่หนีไม่พ้น และไม่มีกายกรรมทางความคิดใดเปลี่ยนมันได้
- Policy ใน Underwriting: ในพื้นที่ความเชี่ยวชาญด้านการพิจารณารับประกัน Policy ถูกสร้างขึ้นจากการประเมินความเสี่ยงของสิ่งที่เอาประกัน เช่น ในประกันทรัพย์สิน ผู้พิจารณารับประกันจะประเมินความเสี่ยงที่ผูกกับทรัพย์สินนั้น เพื่อคำนวณเบี้ยประกันที่จะคุ้มครองทรัพย์สิน
- Policy ใน Inspections: ในงานประกันทรัพย์สิน องค์กรประกันมักมีพื้นที่ความเชี่ยวชาญด้านการตรวจสอบ ที่รับผิดชอบตรวจทรัพย์สินที่จะเอาประกัน ฝ่าย underwriting พึ่งพาข้อมูลจากการตรวจสอบอยู่บ้าง — เพื่อยืนยันว่าทรัพย์สินอยู่ในสภาพตามที่ผู้เอาประกันอ้าง รายละเอียดการตรวจ (ภาพถ่ายและบันทึก) จะผูกกับ Policy ในพื้นที่ inspections และข้อมูลนี้ underwriting สามารถอ้างถึงเพื่อต่อรองค่าเบี้ยขั้นสุดท้ายได้
- Policy ใน Claims: Policy ในพื้นที่การเคลม จะติดตามคำขอชดใช้เงินของผู้เอาประกันตามเงื่อนไขของ Policy ที่สร้างไว้ในฝั่ง underwriting Policy ฝั่งเคลมจะอ้างถึง Policy ฝั่ง underwriting อยู่บ้าง แต่จะโฟกัสที่ความเสียหายต่อทรัพย์สินที่เอาประกัน และการพิจารณาของเจ้าหน้าที่เคลมว่าควรจ่ายเงินหรือไม่ เท่าไร
ถ้าพยายามยุบ Policy ทั้งสามแบบให้เป็น Policy เดียวสำหรับทั้งสามกลุ่มธุรกิจ จะเจอปัญหาแน่นอน และยิ่งเป็นปัญหาหนักขึ้นไปอีก ถ้าในอนาคต Policy ที่หนักอึ้งอยู่แล้วต้องรองรับแนวคิดทางธุรกิจที่สี่และที่ห้าเข้ามาด้วย — ไม่มีใครได้ประโยชน์
graph LR
subgraph UW["Underwriting Context"]
P1["Policy"]
end
subgraph CL["Claims Context"]
P2["Policy"]
end
subgraph IN["Inspections Context"]
P3["Policy"]
end
ในทางกลับกัน DDD เน้น โอบรับความต่างเหล่านี้ ด้วยการแยกชนิดที่แตกต่างกันออกไปคนละ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ยอมรับเสียว่ามันเป็นคนละภาษา แล้วทำงานไปตามนั้น มีสามความหมายของ Policy หรือ? ถ้าใช่ ก็มี3 Bounded Context แต่ละอันมี Policy ของตัวเองที่มีคุณสมบัติเฉพาะ ไม่จำเป็นต้องตั้งชื่อให้ยุ่งยากเป็น UnderwritingPolicy, ClaimsPolicy, หรือ InspectionsPolicy เพราะชื่อของ Bounded Context จัดการ scoping นั้นให้แล้ว ชื่อจึงเป็นเพียง Policy เหมือนกันในทั้ง3 Bounded Context
ในอุตสาหกรรมสายการบิน คำว่า “flight” มีได้หลายความหมาย — flight ที่นิยามว่าเป็นการบินขึ้นและลงครั้งเดียวจากสนามบินหนึ่งไปอีกที่หนึ่ง, flight อีกแบบที่นิยามในแง่ของการซ่อมบำรุงอากาศยาน, และ flight อีกแบบที่นิยามในแง่ของการออกตั๋วผู้โดยสารแบบบินตรงหรือแวะพัก เพราะแต่ละความหมายเข้าใจได้ชัดก็ต่อเมื่ออยู่ในบริบทของมัน แต่ละอันจึงควรถูก model ในคนละ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design การยัดทั้งสามไว้ใน Bounded Context เดียวมีแต่จะนำไปสู่ความสับสนพันกันยุ่ง
กรณีศึกษา (Case Study)
หัวข้อที่มีชื่อว่า “กรณีศึกษา (Case Study)”เพื่อให้เหตุผลของการใช้ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design เป็นรูปธรรมขึ้น มาดูตัวอย่าง domain model จริงกัน ในกรณีนี้เรากำลังทำ application บริหาร project แบบ agile ที่อิง Scrum แนวคิดศูนย์กลางหรือแนวคิดหลักคือ Product ซึ่งแทนซอฟต์แวร์ที่จะสร้างและจะถูกขัดเกลาตลอดหลายปีของการพัฒนา Product มี Backlog Item, Release, และ Sprint แต่ละ Backlog Item มี Task หลายตัว และแต่ละ Task มีกลุ่มของ Estimation Log Entry ได้ Release มี Scheduled Backlog Item ส่วน Sprint มี Committed Backlog Item จนถึงตรงนี้ทุกอย่างยังดี เราระบุแนวคิดหลักของ domain model ได้ และภาษายังโฟกัสและไม่แตก
แล้วทีมก็เริ่มเติม: “อ้อใช่ เราต้องมี user ด้วย และอยากเปิดให้เกิดการพูดคุยร่วมกัน (collaborative discussion) ภายในทีมผลิตภัณฑ์ มาแทนแต่ละองค์กรที่สมัครใช้งานเป็น Tenant ภายใต้ Tenant เราจะให้ลงทะเบียน User กี่คนก็ได้ และ User จะมี Permission แล้วก็เพิ่มแนวคิด Discussion เป็นหนึ่งในเครื่องมือทำงานร่วมที่เราจะรองรับ”
ทีมเติมต่อ: “เออ ยังมีเครื่องมือทำงานร่วมอื่นอีก Discussion อยู่ภายใน Forum และ Discussion มี Post แล้วเราก็อยากรองรับ Shared Calendar ด้วย” จากนั้น: “อย่าลืมว่า Tenant ต้องชำระเงิน เราจะขาย package support เป็นระดับๆ จึงต้องมีทางติดตาม support incident ทั้ง Support และ Payment ควรบริหารภายใต้ Account” และยังโผล่มาอีก: “ทุก Product แบบ Scrum มี Team เฉพาะที่ทำงานให้ ประกอบด้วย ProductOwner หนึ่งคนและ TeamMember หลายคน แต่จะจัดการเรื่อง Human Resource Utilization ยังไงดี? เอ… ถ้าเรา model Schedule ของ TeamMember พร้อมกับ utilization และ availability ของพวกเขาล่ะ?” และ: “Shared Calendar ไม่ควรจำกัดแค่ CalendarEntry ธรรมดา เราควรระบุชนิดเฉพาะของ CalendarEntry ได้ เช่น Reminder, Milestone, การประชุม Planning และ Retrospective, และ Target Date”
เดี๋ยวก่อน! เห็นกับดักที่ทีมกำลังตกลงไปไหม? ดูสิว่าพวกเขาเตลิดออกห่างจากแนวคิดหลักดั้งเดิม — Product, Backlog Item, Release, Sprint — ไปไกลแค่ไหน ภาษาไม่ได้เป็นเรื่องของ Scrum ล้วนๆ อีกต่อไป มันแตกร้าวและสับสน อย่าหลงเชื่อว่าจำนวนแนวคิดที่ตั้งชื่อไว้ยังดูจำกัด เพราะทุก element ที่ตั้งชื่อ เราอาจต้องมีอีกสองสามแนวคิดมารองรับมัน ทีมกำลังเดินหน้าสู่การส่งมอบ Big Ball of MudBig Ball of Mudระบบที่ปนเปกันยุ่งเหยิงไม่มีขอบเขตชัด ให้ลากเส้นล้อมไว้แล้วยอมรับสภาพ ไม่พยายามทำ model ละเอียดในนั้น และระวังไม่ให้ลามไป context อื่นStrategic Design ทั้งที่ project เพิ่งจะเริ่มต้นด้วยซ้ำ
graph TD Acc["Account"] --> SP["SupportPlan"] Acc --> Pay["Payment"] SP --> Inc["Incident"] Ten["Tenant"] --> Usr["User"] Usr --> Perm["Permission"] Prod["Product"] --> BI["BacklogItem"] Prod --> Rel["Release"] Prod --> Spr["Sprint"] BI --> Tsk["Task"] Tsk --> Vol["Volunteer"] Tsk --> ELE["EstimationLogEntry"] Rel --> SBI["ScheduledBacklogItem"] Spr --> CBI["CommittedBacklogItem"] Tm["Team"] --> PO["ProductOwner"] Tm --> TM["TeamMember"] RM["ResourceManager"] --> TCR["TimeConsumingResource"] TCR --> Sch["Schedule"] TCR --> Av["Availability"] Fo["Forum"] --> Dis["Discussion"] Dis --> Po["Post"] Cal["Calendar"] --> CE["CalendarEntry"]
Fundamental Strategic Design ที่จำเป็น (Fundamental Strategic Design Needed)
หัวข้อที่มีชื่อว่า “Fundamental Strategic Design ที่จำเป็น (Fundamental Strategic Design Needed)”DDD มีเครื่องมืออะไรช่วยเราเลี่ยงหลุมพรางพวกนี้? อย่างน้อยต้องมีเครื่องมือเชิงกลยุทธ์พื้นฐานสองชิ้น ชิ้นหนึ่งคือ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design อีกชิ้นคือ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design การใช้ Bounded Context บังคับให้เราตอบคำถามว่า “อะไรคือ core?” Bounded Context ควรอุ้มแนวคิดที่เป็นแกนของความริเริ่มเชิงกลยุทธ์ไว้ใกล้ชิด และผลักทุกอย่างที่เหลือออกไป แนวคิดที่ยังคงอยู่คือส่วนหนึ่งของ Ubiquitous Language ของทีม นี่คือวิธีที่ DDD ทำงานเพื่อเลี่ยงการออกแบบ application แบบ monolithic
เพราะ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ไม่ใช่ monolith จึงได้ประโยชน์อื่นตามมาเมื่อใช้มัน หนึ่งในนั้นคือ test จะโฟกัสที่ model เดียว จำนวนจึงน้อยลงและรันเร็วขึ้น แม้นี่จะไม่ใช่แรงจูงใจหลักในการใช้ Bounded Context แต่ก็ให้ผลตอบแทนในทางอื่นแน่นอน
แท้จริงแล้วบางแนวคิดจะ “อยู่ในบริบท (in context)” และถูกรวมไว้ในภาษาของทีมอย่างชัดเจน ส่วนแนวคิดอื่นจะ “อยู่นอกบริบท (out of context)” แนวคิดที่รอดผ่านการกรองแบบ “เอาเฉพาะ core” อันเข้มงวดนี้ คือส่วนหนึ่งของ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ของทีมที่เป็นเจ้าของ Bounded Context ขอบเขตนั้นเองที่เน้นย้ำความเคร่งครัดภายใน
แล้วจะรู้ได้อย่างไรว่าอะไรคือ core? ตรงนี้แหละที่ต้องดึงคนสองกลุ่มสำคัญมารวมเป็นทีมเดียวที่ร่วมมือและเป็นอันหนึ่งอันเดียว — ผู้เชี่ยวชาญธุรกิจ (Domain Expert)Domain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design กับนักพัฒนาซอฟต์แวร์
Domain Expert โดยธรรมชาติจะโฟกัสที่เรื่องธุรกิจมากกว่า ความคิดของพวกเขาหมุนรอบวิสัยทัศน์ว่าธุรกิจทำงานอย่างไร ใน domain ของ Scrum เราคาดได้ว่า Domain Expert จะเป็น Scrum Master ที่เข้าใจอย่างถ่องแท้ว่า Scrum ถูกนำไปปฏิบัติใน project อย่างไร
หลายคนสงสัยว่า Scrum product owner ต่างจาก Domain ExpertDomain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design ของ DDD อย่างไร บางกรณีอาจเป็นคนคนเดียวกันที่สวมได้ทั้งสองบทบาท แต่ไม่น่าแปลกใจที่ product owner มักโฟกัสที่การบริหารและจัดลำดับความสำคัญของ product backlog และดูแลความต่อเนื่องเชิงแนวคิดและเทคนิคของ project มากกว่า นั่นไม่ได้แปลว่า product owner จะเป็นผู้เชี่ยวชาญในความสามารถหลักของธุรกิจที่เรากำลังทำอยู่โดยอัตโนมัติ ให้แน่ใจว่ามี Domain Expert ตัวจริงอยู่ในทีม อย่าเอา product owner มาแทนโดยที่ขาด know-how ที่จำเป็น
ในธุรกิจของเราก็มี Domain Expert เช่นกัน มันไม่ใช่ตำแหน่งงาน แต่อธิบายถึงคนที่โฟกัสที่ธุรกิจเป็นหลัก mental model ของพวกเขานี่แหละที่เราใช้เป็นจุดเริ่มต้นในการก่อร่างรากฐานของ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ของทีม
ในทางกลับกัน นักพัฒนาโฟกัสที่การพัฒนาซอฟต์แวร์ และอาจถูกกลืนกินด้วยภาษาโปรแกรมและเทคโนโลยี (Java, C#, Scala, JavaScript, PHP, …) แต่นักพัฒนาใน project DDD ต้อง ต้านแรงดึงที่จะหมกมุ่นกับเทคนิคจนรับโฟกัสทางธุรกิจของความริเริ่มเชิงกลยุทธ์หลักไม่ได้ ตรงข้าม นักพัฒนาควรปฏิเสธความรวบรัดที่ไม่จำเป็น และพร้อมโอบรับ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ที่ทีมค่อยๆ พัฒนาขึ้นภายใน Bounded Context ของตน
เราใช้ DDD เพราะ ความซับซ้อนของ model ธุรกิจสูง เราไม่เคยอยากทำให้ domain model ซับซ้อนเกินกว่าที่ควรจะเป็น แต่เราใช้ DDD ก็เพราะ model ธุรกิจซับซ้อนกว่าแง่มุมทางเทคนิคของ project — และนั่นคือเหตุผลที่นักพัฒนาต้องลงไปขุด model ธุรกิจร่วมกับ Domain ExpertDomain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design!
ทั้งนักพัฒนาและ Domain Expert ควรปฏิเสธแนวโน้มที่จะให้ เอกสารปกครองเหนือบทสนทนา Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ที่ดีที่สุดเกิดจาก วงป้อนกลับแบบร่วมมือ (collaborative feedback loop) ที่ดึง mental model รวมของทีมออกมา บทสนทนาที่เปิดกว้าง การสำรวจ และการท้าทายฐานความรู้ปัจจุบัน นำไปสู่ความเข้าใจที่ลึกขึ้นเกี่ยวกับ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design
ท้าทายและรวมให้เป็นหนึ่ง (Challenge and Unify)
หัวข้อที่มีชื่อว่า “ท้าทายและรวมให้เป็นหนึ่ง (Challenge and Unify)”กลับมาที่คำถาม “อะไรคือ core?” โดยใช้ model ที่ก่อนหน้านี้บานปลายควบคุมไม่ได้ มาลอง ท้าทายและรวมให้เป็นหนึ่ง กัน
การท้าทายที่ง่ายมากข้อหนึ่งคือถามว่า แนวคิดแต่ละตัวใน model ใหญ่ยึดตาม Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ของ Scrum หรือไม่ ตัวอย่างเช่น Tenant, User, และ Permission ไม่เกี่ยวอะไรกับ Scrum เลย แนวคิดเหล่านี้ควรถูกแยกออก (factored out) จากซอฟต์แวร์ model Scrum ของเรา
Tenant, User, และ Permission ควรถูกแทนด้วย Team, ProductOwner, และ TeamMember จริงอยู่ที่ ProductOwner และ TeamMember แท้จริงก็คือ User ใน Tenancy หนึ่ง แต่ด้วย ProductOwner และ TeamMember เรายึดตาม Ubiquitous Language ของ Scrum — มันเป็นคำที่เราใช้กันเป็นธรรมชาติเวลาคุยถึงผลิตภัณฑ์ Scrum และงานที่ทีมทำกับมัน
SupportPlan และ Payment เป็นส่วนหนึ่งของการบริหาร project แบบ Scrum จริงหรือ? คำตอบชัดเจนว่า “ไม่” จริงที่ทั้งสองจะถูกบริหารภายใต้ Account ของ Tenant แต่มันไม่ใช่ภาษา Scrum หลักของเรา มันอยู่นอกบริบทและถูกถอดออกจาก model เช่นเดียวกับเรื่อง Human Resource Utilization (ResourceManager, TimeConsumingResource, Schedule, Availability) — อาจมีประโยชน์กับใครสักคน แต่ไม่ได้ถูกใช้โดยตรงโดย TeamMember ที่อาสา (Volunteer) มาทำ Task ของ BacklogItem มันอยู่นอกบริบท
หลังจากเพิ่ม Team, ProductOwner, และ TeamMember ผู้สร้าง model ก็พบว่าขาดแนวคิดหลักที่ให้ TeamMember ลงมือทำ Task ใน Scrum สิ่งนี้เรียกว่า Volunteer (การอาสารับงาน) ดังนั้นแนวคิด Volunteer จึงอยู่ในบริบทและถูกรวมไว้ในภาษาของ model หลัก
แม้ว่า Milestone, Retrospective, และอื่นๆ ที่อิงปฏิทินจะอยู่ในบริบท แต่ทีมเลือกเก็บความพยายาม model ส่วนนั้นไว้ทำใน sprint ถัดๆ ไป — มันอยู่ในบริบท แต่ตอนนี้ อยู่นอก scope สุดท้ายผู้สร้าง model อยากแน่ใจว่าได้คำนึงถึงข้อเท็จจริงที่ว่า threaded Discussion จะเป็นส่วนหนึ่งของ model หลัก จึง model Discussion ไว้ นั่นแปลว่า Discussion เป็นส่วนหนึ่งของ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ของทีม และจึงอยู่ภายใน Bounded Context
การท้าทายเชิงภาษาเหล่านี้ทำให้ได้ model ของ Ubiquitous Language ที่สะอาดและชัดเจนขึ้นมาก แต่ model Scrum จะตอบสนองความต้องการ Discussion ที่จำเป็นอย่างไร? มันต้องอาศัยคอมโพเนนต์เสริมจำนวนมากจึงจะทำงานได้ จึงดูไม่เหมาะที่จะ model ไว้ใน Scrum Bounded Context ของเรา อันที่จริงชุด Collaboration ทั้งชุดอยู่นอกบริบท Discussion จะถูกรองรับด้วยการเชื่อมต่อกับ Bounded Context อีกอันหนึ่ง — Collaboration Context
graph LR
subgraph APM["Agile Project Management Context (Core Domain)"]
Prod["Product"] --> BI["BacklogItem"]
Prod --> Rel["Release"]
Prod --> Spr["Sprint"]
BI --> Tsk["Task"]
Tsk --> Vol["Volunteer"]
Tsk --> ELE["EstimationLogEntry"]
Rel --> SBI["ScheduledBacklogItem"]
Spr --> CBI["CommittedBacklogItem"]
Tm["Team"] --> PO["ProductOwner"]
Tm --> TM["TeamMember"]
Dis1["Discussion (ใช้งาน)"]
end
subgraph COL["Collaboration Context"]
Fo["Forum"] --> Dis2["Discussion (ต้นทาง)"]
Dis2 --> Po["Post"]
Cal["Calendar"] --> CE["CalendarEntry"]
end
APM -.- COL
หลังจากเดินผ่านกระบวนการนี้ เราเหลือ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design จริงๆ ที่เล็กลงมาก แน่นอนว่า Core Domain จะเติบโตต่อไป เรารู้อยู่แล้วว่า Planning, Retrospective, Milestone และ model ที่อิงปฏิทินที่เกี่ยวข้องต้องถูกพัฒนาในเวลาอันควร แต่ model จะเติบโตก็ต่อเมื่อ แนวคิดใหม่ยึดตาม Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ของ Scrum เท่านั้น
ส่วนแนวคิดอื่นๆ ที่ถูกถอดออกจาก Core Domain ล่ะ? เป็นไปได้สูงว่าหลายตัว ถ้าไม่ใช่ทั้งหมด จะถูกประกอบขึ้นเป็น Bounded Context ของตัวเอง แต่ละอันยึดตาม Ubiquitous Language ของมันเอง และภายหลังเราจะได้เห็นวิธีเชื่อมต่อกับพวกมันด้วย Context MappingContext Mappingกิจกรรมการระบุ Bounded Context และนิยามความสัมพันธ์ระหว่างกัน (เช่น Partnership, Shared Kernel, ACL) เพื่อจัดการการเชื่อมต่อระหว่างทีม/ระบบStrategic Design
พัฒนา Ubiquitous Language (Developing a Ubiquitous Language)
หัวข้อที่มีชื่อว่า “พัฒนา Ubiquitous Language (Developing a Ubiquitous Language)”แล้วจะลงมือพัฒนา Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ภายในทีมจริงๆ อย่างไร? Ubiquitous Language เกิดจากชุดคำนามที่รู้จักกันดีหรือเปล่า? คำนามสำคัญก็จริง แต่บ่อยครั้งนักพัฒนาให้น้ำหนักกับคำนามใน domain model มากเกินไป จนลืมว่าภาษาพูดประกอบด้วยอะไรมากกว่าคำนามเยอะ ที่ผ่านมาเราโฟกัสคำนามใน Bounded Context ตัวอย่างเป็นหลัก ก็เพราะเราสนใจอีกแง่มุมหนึ่งของ DDD คือการบีบ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design ให้เหลือเฉพาะ element ที่จำเป็น
อย่าจำกัด Core Domain ไว้แค่คำนาม แต่ให้พิจารณาแสดง Core Domain เป็น ชุดของ scenario ที่เป็นรูปธรรม เกี่ยวกับสิ่งที่ domain model ควรทำ คำว่า “scenario” ในที่นี้ไม่ได้หมายถึง use case หรือ user story แต่หมายถึง scenario ในแง่ว่า domain model ควรทำงานอย่างไร — คอมโพเนนต์ต่างๆ ทำอะไร สิ่งนี้ทำได้สมบูรณ์ที่สุดด้วยการร่วมมือกันเป็นทีมของทั้ง Domain Expert และนักพัฒนาเท่านั้น
ลองทำ EventStormingEventStormingเวิร์กช็อปแบบร่วมมือ (Alberto Brandolini, 2013) ใช้กระดาษโน้ตสีติดบนผนัง: ส้ม=event, น้ำเงิน=command, เหลือง=aggregate ฯลฯ เพื่อค้นพบ model และขอบเขตของ contextProcess สักสองสามรอบขณะทำงานกับ scenario ของคุณ มันช่วยให้เข้าใจอย่างรวดเร็วว่าควรทำ scenario ไหนก่อนและจัดลำดับอย่างไร และในทางกลับกัน การพัฒนา scenario ที่เป็นรูปธรรมก็ให้ไอเดียที่ดีขึ้นว่าควรเดิน EventStormingEventStormingเวิร์กช็อปแบบร่วมมือ (Alberto Brandolini, 2013) ใช้กระดาษโน้ตสีติดบนผนัง: ส้ม=event, น้ำเงิน=command, เหลือง=aggregate ฯลฯ เพื่อค้นพบ model และขอบเขตของ contextProcess ไปทางไหน ทั้งสองเป็นเครื่องมือที่ทำงานเข้าขากันได้ดี (Vernon อธิบาย EventStorming ของ Alberto Brandolini ไว้ในบท “เครื่องมือเร่งและบริหารการนำไปใช้”)
นี่คือตัวอย่าง scenario ที่เข้ากับ Ubiquitous Language ของ Scrum:
เปิดให้ backlog item แต่ละตัวสามารถ commit เข้า sprint ได้ โดย backlog item จะ commit ได้ก็ต่อเมื่อมันถูก schedule สำหรับ release แล้ว ถ้ามันถูก commit ไว้กับ sprint อื่นอยู่ ต้องยกเลิก commit นั้นก่อน เมื่อ commit เสร็จ ให้แจ้งฝ่ายที่เกี่ยวข้อง
— scenario เริ่มต้น (Vaughn Vernon, Domain-Driven Design Distilled)
สังเกตว่านี่ไม่ใช่ scenario เรื่องที่ “มนุษย์” ใช้ Scrum ใน project อย่างไร เราไม่ได้พูดถึงขั้นตอนของคน แต่ scenario นี้อธิบายว่า คอมโพเนนต์ของซอฟต์แวร์ model ถูกใช้รองรับการบริหาร project แบบ Scrum อย่างไร scenario นี้ยังไม่สมบูรณ์แบบ และข้อดีของ DDD คือเราคอยมองหาทางปรับปรุง model อยู่ตลอด เราได้ยินคำนาม แต่ scenario ไม่ได้จำกัดเราไว้แค่คำนาม เราได้ยินคำกริยา คำวิเศษณ์ และไวยากรณ์อื่นๆ ด้วย เราได้ยินว่ามีข้อจำกัด (constraint) — เงื่อนไขที่ต้องเป็นจริงก่อน scenario จะจบลงได้สำเร็จ ประโยชน์สำคัญและทรงพลังที่สุดคือ เราสามารถ มีบทสนทนาเรื่องการทำงานของ domain model ได้จริงๆ นั่นคือ design ของมัน
เราวาดภาพและไดอะแกรมได้ ทั้งหมดนี้ทำเพื่อสื่อสารกันในทีมให้ดี แต่ขอเตือนสักนิด ระวังเรื่องเวลาที่ใช้คอยอัปเดต scenario เป็นลายลักษณ์อักษร ภาพวาด และไดอะแกรม ให้ทันสมัยในระยะยาว — สิ่งเหล่านั้น ไม่ใช่ domain model มันเป็นเพียงเครื่องมือช่วยพัฒนา domain model ในที่สุด code คือ model และ model คือ code พิธีรีตองมีไว้สำหรับโอกาสพิเศษ เช่นงานแต่งงาน ไม่ใช่สำหรับ domain model นี่ไม่ได้แปลว่าให้เลิกทำ scenario ให้สดใหม่ แต่ให้ทำเท่าที่มันยังช่วยมากกว่าจะเป็นภาระ
ใส่ “ใคร” ลงใน model
หัวข้อที่มีชื่อว่า “ใส่ “ใคร” ลงใน model”จะปรับปรุง Ubiquitous Language ในตัวอย่างก่อนหน้าอย่างไรดี? อะไรขาดไป? ไม่นานเราคงอยากเข้าใจว่า “ใคร” เป็นคน commit backlog item เข้า sprint ลองเติม “ใคร” เข้าไป:
product owner เป็นผู้ commit backlog item แต่ละตัวเข้า sprint…
หลายกรณีเราควรตั้งชื่อ persona แต่ละตัวที่เกี่ยวข้องใน scenario และให้คุณสมบัติที่จำแนกได้แก่แนวคิดอื่นๆ เช่น backlog item และ sprint แต่ในกรณีนี้ยังไม่มีเหตุผลหนักแน่นพอที่จะตั้งชื่อ product owner หรือบรรยาย backlog item และ sprint เพิ่ม เพราะทุก product owner, backlog item, และ sprint จะทำงานเหมือนกันไม่ว่าจะมี persona ที่เป็นรูปธรรมหรือไม่ ในกรณีที่การตั้งชื่อช่วยได้ ก็ให้ใช้:
product owner ชื่อ Isabel commit backlog item “View User Profile” เข้า sprint “Deliver User Profiles”…
หยุดคิดสักครู่ ไม่ใช่ว่า product owner เป็นคนเดียวที่รับผิดชอบตัดสินใจว่า backlog item จะถูก commit เข้า sprint ทีม Scrum คงไม่ชอบใจนัก เพราะพวกเขาจะถูกผูกมัดให้ส่งมอบงานในกรอบเวลาที่ตัวเองไม่ได้มีส่วนกำหนด ถึงอย่างนั้น สำหรับซอฟต์แวร์ model อาจเป็นการปฏิบัติที่สุดที่ให้คนคนเดียวรับผิดชอบลงมือ action นี้ เราจึงระบุว่าเป็นบทบาท product owner ที่ทำ แต่ธรรมชาติของทีม Scrum ก็บังคับให้เกิดคำถามว่า “มีอะไรที่สมาชิกทีมที่เหลือต้องทำก่อน เพื่อให้ product owner ทำการ commit ได้หรือไม่?”
เห็นไหมว่าเกิดอะไรขึ้น? ด้วยการ ท้าทาย model ด้วยคำถาม “ใคร” เราถูกนำไปสู่โอกาสที่จะเข้าใจ model ลึกขึ้น บางทีเราควรกำหนดให้มี ฉันทามติของทีมระดับหนึ่ง ว่า backlog item ถูก commit ได้ ก่อนจะอนุญาตให้ product owner ลงมือ commit จริง นำไปสู่ scenario ที่ขัดเกลาแล้ว:
product owner commit backlog item เข้า sprint โดย backlog item จะ commit ได้ก็ต่อเมื่อมันถูก schedule สำหรับ release แล้ว และมีสมาชิกทีมจำนวนหนึ่งเป็น quorum ที่อนุมัติการ commit แล้ว…
เอาล่ะ ตอนนี้เราได้ Ubiquitous Language ที่ขัดเกลาขึ้น เพราะเราระบุแนวคิด model ใหม่ชื่อ quorum ออกมาได้ เราตัดสินว่าต้องมี quorum ของสมาชิกทีมที่เห็นพ้องว่าควร commit backlog item และต้องมีวิธีให้พวกเขา approve การ commit นั่นนำแนวคิด model ใหม่และไอเดียที่ว่า user interface จะต้องอำนวยการโต้ตอบเหล่านี้ของทีมเข้ามา เห็นนวัตกรรมที่ค่อยๆ คลี่ออกไหม?
ยังมี “ใคร” อีกตัวที่หายไปจาก model ตัวไหน? scenario เปิดของเราจบด้วย “เมื่อ commit เสร็จ ให้แจ้งฝ่ายที่เกี่ยวข้อง” ใครหรืออะไรคือฝ่ายที่เกี่ยวข้อง? คำถามนี้นำไปสู่ความเข้าใจที่ลึกขึ้น ใครต้องรู้เมื่อ backlog item ถูก commit เข้า sprint? อันที่จริง element model ที่สำคัญคือ sprint เอง — sprint ต้องติดตามยอด commit รวมและความพยายามที่ต้องใช้ส่งมอบทุก task ของ sprint ประเด็นสำคัญตอนนี้คือ sprint ต้องถูกแจ้งเมื่อมี backlog item ถูก commit เข้ามา:
ถ้ามันถูก commit ไว้กับ sprint อื่นอยู่ ต้องยกเลิก commit นั้นก่อน เมื่อ commit เสร็จ ให้แจ้งทั้ง sprint ที่ถูกยกเลิก commit ออกไป และ sprint ที่ถูก commit เข้ามาใหม่
ตอนนี้เรามี domain scenario ที่ดีพอควร ประโยคปิดท้ายยังนำเราไปสู่ความเข้าใจว่า backlog item กับ sprint อาจไม่จำเป็นต้องรับรู้การ commit ในเวลาเดียวกัน ต้องไปถามฝั่งธุรกิจให้แน่ใจ แต่ฟังดูเป็นจุดที่เหมาะจะนำ ความถูกต้องที่ตามมาทีหลัง (Eventual Consistency)Eventual Consistencyความถูกต้องที่ “ตามมาทีหลัง” ไม่ใช่ทันที ใช้กับการอัปเดตข้าม Aggregate ผ่าน Domain Event แทนการบังคับให้ตรงกันในทันทีภายใน transaction เดียวTactical Design เข้ามา — และจะได้เห็นว่ามันสำคัญและทำได้อย่างไรในบทเรื่อง Aggregate
scenario ที่ขัดเกลาฉบับเต็มจึงเป็นแบบนี้:
product owner commit backlog item เข้า sprint โดย backlog item จะ commit ได้ก็ต่อเมื่อมันถูก schedule สำหรับ release แล้ว และมีสมาชิกทีมจำนวนหนึ่งเป็น quorum ที่อนุมัติการ commit แล้ว ถ้ามันถูก commit ไว้กับ sprint อื่นอยู่ ต้องยกเลิก commit นั้นก่อน เมื่อ commit เสร็จ ให้แจ้งทั้ง sprint ที่ถูกยกเลิก commit ออกไป และ sprint ที่ถูก commit เข้ามาใหม่
ในทางปฏิบัติซอฟต์แวร์ model จะทำงานอย่างไร? ลองจินตนาการ user interface ที่สร้างสรรค์รองรับ model นี้ ขณะทีม Scrum กำลังร่วม session วางแผน sprint สมาชิกใช้สมาร์ตโฟนหรืออุปกรณ์มือถือเพิ่มการอนุมัติของตนให้แก่ backlog item แต่ละตัวขณะถกและตกลงกันว่าจะทำใน sprint หน้า ฉันทามติของ quorum ที่อนุมัติ backlog item แต่ละตัว ให้อำนาจ product owner ในการ commit backlog item ที่อนุมัติแล้วทั้งหมดเข้า sprint
นำ Scenario ไปใช้งานจริง (Putting Scenarios to Work)
หัวข้อที่มีชื่อว่า “นำ Scenario ไปใช้งานจริง (Putting Scenarios to Work)”หลายคนอาจสงสัยว่าจะเปลี่ยนจาก scenario ที่เป็นลายลักษณ์อักษรไปเป็น artifact บางอย่างที่ใช้ตรวจสอบ domain model เทียบกับ specification ของทีมได้อย่างไร มีเทคนิคชื่อ Specification by Example (หรือที่เรียกว่า Behavior-Driven Development / BDD) ที่ใช้ได้ สิ่งที่เราพยายามทำคือพัฒนาและขัดเกลา Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design ร่วมกัน สร้าง model ที่มีความเข้าใจร่วม และพิจารณาว่า model ยึดตาม specification หรือไม่ ด้วยการสร้าง acceptance test นี่คือวิธีเขียน scenario ก่อนหน้านี้ใหม่ในรูปของ executable specification:
Scenario: The product owner commits a backlog item to a sprint Given a backlog item that is scheduled for release And the product owner of the backlog item And a sprint for commitment And a quorum of team approval for commitment When the product owner commits the backlog item to the sprint Then the backlog item is committed to the sprint And the backlog item committed event is createdเมื่อเขียน scenario ในรูปนี้ เราสร้าง backing code และใช้เครื่องมือ execute specification นี้ได้ แม้ไม่มีเครื่องมือ เราก็อาจพบว่ารูปแบบ given/when/then นี้ทำงานได้ดีกว่ารูปแบบ scenario แบบเดิม
เราไม่จำเป็นต้องใช้รูปแบบ executable specification นี้เพื่อตรวจสอบ domain model เทียบกับ scenario ก็ได้ ใช้ unit testing framework ทำสิ่งเดียวกันได้ โดยสร้าง acceptance test (ไม่ใช่ unit test) ที่ตรวจสอบ domain model:
/* * product owner commit backlog item เข้า sprint * backlog item จะ commit ได้ก็ต่อเมื่อถูก schedule สำหรับ release แล้ว * และมี quorum ของสมาชิกทีมอนุมัติการ commit แล้ว * เมื่อ commit เสร็จ ให้แจ้ง sprint ที่ถูก commit เข้ามา */@Testpublic void shouldCommitBacklogItemToSprint() { // Given var backlogItem = backlogItemScheduledForRelease(); var productOwner = productOwnerOf(backlogItem); var sprint = sprintForCommitment(); var quorum = quorumOfTeamApproval(backlogItem, sprint);
// When backlogItem.commitTo(sprint, productOwner, quorum);
// Then assertTrue(backlogItem.isCommitted()); var backlogItemCommitted = backlogItem.events().ofType(BacklogItemCommitted.class).singleOrDefault(); assertNotNull(backlogItemCommitted);}วิธีอิง unit test เพื่อทำ acceptance testing นี้บรรลุเป้าหมายเดียวกับ executable specification ข้อได้เปรียบคือเขียน scenario validation ได้รวดเร็วกว่า แลกกับความอ่านง่ายที่ลดลงบ้าง แต่ Domain ExpertDomain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design ส่วนใหญ่ก็ตาม code นี้ได้โดยมีนักพัฒนาช่วยเล็กน้อย เมื่อใช้วิธีนี้ ควรเก็บ scenario รูปเอกสารไว้คู่กับ validation code ในรูปคอมเมนต์ ดังในตัวอย่าง
ไม่ว่าจะเลือกวิธีไหน ทั้งสองมักใช้ในแบบ red-green (fail-pass) คือ specification จะ fail ก่อนเมื่อรันครั้งแรก เพราะยังไม่มี implement แนวคิด domain model ให้ตรวจสอบ แล้วเราค่อยๆ ขัดเกลา domain model ผ่านชุดผลลัพธ์ red จนรองรับ specification ครบและ validation ผ่าน (เห็น green ทั้งหมด) acceptance test เหล่านี้จะผูกกับ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design โดยตรงและเก็บไว้ใน source code repository ของมัน
แล้วในระยะยาวล่ะ? (What about the Long Haul?)
หัวข้อที่มีชื่อว่า “แล้วในระยะยาวล่ะ? (What about the Long Haul?)”หลายคนอาจสงสัยว่าควรดูแล Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design อย่างไรเมื่อนวัตกรรมหยุดลงและเข้าสู่การ maintenance อันที่จริงการเรียนรู้ที่ดีที่สุดบางส่วน หรือการได้มาซึ่งความรู้ เกิดขึ้นตลอดช่วงเวลายาวนาน แม้ในช่วงที่บางคนเรียกว่า “maintenance” ก็ตาม เป็นความผิดพลาดที่ทีมจะมองว่านวัตกรรมจบลงเมื่อ maintenance เริ่มต้น
บางทีสิ่งที่แย่ที่สุดคือการแปะป้าย “maintenance phase” ลงบน Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design กระบวนการเรียนรู้ต่อเนื่องไม่ใช่ “เฟส” เลย Ubiquitous Language ที่พัฒนาขึ้นในช่วงต้นต้องเติบโตต่อเนื่องเมื่อปีผ่านไป จริงอยู่ที่มันอาจค่อยๆ มีนัยสำคัญน้อยลงในที่สุด แต่คงอีกนาน ทั้งหมดนี้เป็นส่วนหนึ่งของพันธะที่องค์กรมีต่อความริเริ่มหลัก ถ้าให้พันธะระยะยาวนี้ไม่ได้ — model ที่เรากำลังทำอยู่วันนี้เป็นตัวสร้างความแตกต่างเชิงกลยุทธ์ เป็น Core Domain จริงหรือ?
สถาปัตยกรรม (Architecture)
หัวข้อที่มีชื่อว่า “สถาปัตยกรรม (Architecture)”อีกคำถามที่หลายคนอาจสงสัย — ภายใน Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design มีอะไรอยู่บ้าง? เมื่อดูจากไดอะแกรมสถาปัตยกรรม Ports and Adapters (Hexagonal)Hexagonal Architectureสถาปัตยกรรม “Ports and Adapters” โดย Alistair Cockburn — วาง domain ไว้ตรงกลาง นิยาม port (interface) ให้ adapter ภายนอกมาเสียบ ทุก dependency ชี้เข้าหา domainArchitecture จะเห็นว่า Bounded Context ประกอบด้วยมากกว่าแค่ domain model
graph LR IN["Input Adapter<br/>(UI controller, REST endpoint, message listener)"] --> AS["Application Service<br/>(orchestrate use case, จัดการ transaction)"] AS --> DM["Domain Model<br/>(Entity, Business Logic, Domain Event)"] DM --> OUT["Output Adapter<br/>(persistence, message sender)"]
ชั้น (layer) เหล่านี้พบได้ทั่วไปใน Bounded Context — Input AdapterAdapterตัวที่ “ทำให้” port เป็นจริง เช่น PostgresCargoRepository หรือ REST controller อยู่ชั้นนอกและพึ่งพา domain ทำให้สลับเทคโนโลยีได้โดยไม่แตะ domainArchitecture เช่น UI controller, REST endpoint, และ message listener; Application ServiceApplication Serviceบริการที่ “ประสานงาน” use case — จัดการ transaction, ความปลอดภัย, การบันทึก, แปลง DTO — แต่ไม่มีกฎธุรกิจอยู่ในตัวมันเองTactical Design ที่ประสาน use case และจัดการ transaction; domain model ที่เราโฟกัสกันมา; และ Output AdapterAdapterตัวที่ “ทำให้” port เป็นจริง เช่น PostgresCargoRepository หรือ REST controller อยู่ชั้นนอกและพึ่งพา domain ทำให้สลับเทคโนโลยีได้โดยไม่แตะ domainArchitecture เช่นการจัดการ persistence และตัวส่ง message มีอะไรให้พูดถึงอีกมากเกี่ยวกับชั้นต่างๆ ในสถาปัตยกรรมนี้ ซึ่งละเอียดเกินกว่าจะกล่าวในหนังสือฉบับกลั่นนี้
แม้เทคโนโลยีจะกระจายอยู่ทั่วสถาปัตยกรรม แต่ domain model ควรปลอดจากเทคโนโลยี เหตุผลหนึ่งคือ — นั่นจึงเป็นเหตุผลที่ transaction ถูกจัดการโดย Application ServiceApplication Serviceบริการที่ “ประสานงาน” use case — จัดการ transaction, ความปลอดภัย, การบันทึก, แปลง DTO — แต่ไม่มีกฎธุรกิจอยู่ในตัวมันเองTactical Design ไม่ใช่โดย domain model
Ports and AdaptersHexagonal Architectureสถาปัตยกรรม “Ports and Adapters” โดย Alistair Cockburn — วาง domain ไว้ตรงกลาง นิยาม port (interface) ให้ adapter ภายนอกมาเสียบ ทุก dependency ชี้เข้าหา domainArchitecture ใช้เป็นสถาปัตยกรรมรากฐานได้ แต่ไม่ใช่ทางเลือกเดียวที่ใช้คู่กับ DDD ได้ เราใช้ DDD ร่วมกับสถาปัตยกรรมหรือ architecture pattern เหล่านี้ (และอื่นๆ) ได้ โดยผสมผสานตามต้องการ:
- Event-Driven Architecture และ Event SourcingEvent Sourcingเก็บทุกการเปลี่ยนสถานะเป็น event ที่เปลี่ยนไม่ได้ แล้วสร้างสถานะปัจจุบันด้วยการเล่น event ซ้ำ มัก “ต้องใช้คู่กับ CQRS” (Greg Young) มี event stream ต่อ1 AggregateArchitecture (จะกล่าวในบทเรื่อง Domain Event)
- CQRSCQRSCommand Query Responsibility Segregation — แยก model สำหรับ “เขียน/แก้ไข” (command) ออกจาก model สำหรับ “อ่าน” (query) เหมาะกับ domain ซับซ้อน แต่เพิ่มความซับซ้อน ใช้อย่างระมัดระวังArchitecture — Command Query Responsibility Segregation
- Reactive และ Actor Model — ดูแนวคิด Actor model ที่ใช้คู่กับ DDD
- REST — Representational State Transfer
- SOA — Service-Oriented Architecture
- Microservices — ตามหนังสือ Building Microservices microservice แทบจะเทียบเท่ากับ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ของ DDD
- Cloud Computing — รองรับในลักษณะเดียวกับ microservices
บางคนมอง microservice ว่าเล็กกว่า Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ของ DDD มาก โดยนิยามนั้น microservice 1 model เพียงแนวคิดเดียวและจัดการข้อมูลชนิดแคบๆ เช่น microservice หนึ่งเป็น Product อีกอันเป็น BacklogItem ถ้านี่คือ granularity ที่คุณมองว่าเป็น microservice ที่คุ้มค่า ก็ให้เข้าใจว่าทั้ง microservice Product และ BacklogItem ยังคงอยู่ใน Bounded Context เชิงตรรกะที่ใหญ่กว่าเดียวกัน คอมโพเนนต์ microservice เล็กๆ สองตัวนี้เพียงมี deployment unit ต่างกัน (ซึ่งอาจส่งผลต่อวิธีที่มันโต้ตอบกัน — ดูเรื่อง Context MappingContext Mappingกิจกรรมการระบุ Bounded Context และนิยามความสัมพันธ์ระหว่างกัน (เช่น Partnership, Shared Kernel, ACL) เพื่อจัดการการเชื่อมต่อระหว่างทีม/ระบบStrategic Design) แต่ในเชิงภาษา มันยังอยู่ในขอบเขตเชิงบริบทและความหมายแบบ Scrum เดียวกัน
สรุป (Summary)
หัวข้อที่มีชื่อว่า “สรุป (Summary)”ในบทนี้เราได้เรียนรู้: หลุมพรางสำคัญบางอย่างของการยัดมากเกินไปใน model เดียวจนกลายเป็น Big Ball of MudBig Ball of Mudระบบที่ปนเปกันยุ่งเหยิงไม่มีขอบเขตชัด ให้ลากเส้นล้อมไว้แล้วยอมรับสภาพ ไม่พยายามทำ model ละเอียดในนั้น และระวังไม่ให้ลามไป context อื่นStrategic Design; การประยุกต์ใช้ strategic design ของ DDD; การใช้ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design และ Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design; วิธีท้าทายสมมติฐานของตัวเองและรวม model ให้เป็นหนึ่ง; วิธีพัฒนา Ubiquitous Language; คอมโพเนนต์เชิงสถาปัตยกรรมที่พบภายใน Bounded Context; และที่สำคัญ — DDD ไม่ได้ยากเกินกว่าจะลงมือใช้เองได้!
หัวใจของทั้งบทคือ Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design เป็นขอบเขตของภาษา ภายในนั้น Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design สอดคล้องกัน 100% และถูกกลั่นร่วมกันระหว่างนักพัฒนากับ Domain ExpertDomain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design ผ่านบทสนทนา การท้าทาย และ scenario ที่เป็นรูปธรรม สิ่งที่รอดผ่านการกรอง “เอาเฉพาะ core” คือ Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design ที่เราต้องทุ่มลงทุนมากที่สุด
- Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design = ขอบเขตเชิงความหมาย ภายในนั้นทุกคำมีความหมายเดียวแน่นอน คำเดียวกัน (เช่น Policy, flight) มีได้หลายความหมายข้าม context
- Ubiquitous LanguageUbiquitous Languageภาษากลางที่ทุกคนในทีม (ทั้งนักพัฒนาและผู้เชี่ยวชาญธุรกิจ) ใช้ร่วมกัน อิงกับ domain model โดยตรง คำเดียวกันต้องหมายถึงสิ่งเดียวกัน และสะท้อนลงใน codeStrategic Design คือภาษากลางที่ทั้งพูดและฝังใน code — พัฒนาร่วมกับ Domain ExpertDomain Expertผู้เชี่ยวชาญธุรกิจที่รู้กฎ กระบวนการ และความต้องการของ domain อย่างลึกซึ้ง เป็นแหล่งความรู้สำคัญที่ทีมพัฒนาต้องร่วมงานด้วยอย่างใกล้ชิดใน DDDStrategic Design ผ่านวงป้อนกลับ ไม่ใช่ผ่านเอกสารที่ปกครองเหนือบทสนทนา
- หนึ่งทีม / 1 Bounded Context / 1 repository — ยัดมากเกินไปโดยไม่มีขอบเขตจะได้ Big Ball of MudBig Ball of Mudระบบที่ปนเปกันยุ่งเหยิงไม่มีขอบเขตชัด ให้ลากเส้นล้อมไว้แล้วยอมรับสภาพ ไม่พยายามทำ model ละเอียดในนั้น และระวังไม่ให้ลามไป context อื่นStrategic Design
- ท้าทายและรวมให้เป็นหนึ่ง ด้วยคำถาม “อะไรคือ core?” และ “ใคร?” เพื่อกลั่น Core DomainCore Domainsubdomain ที่สำคัญและสร้างความได้เปรียบในการแข่งขันมากที่สุด เป็นเหตุผลที่เราต้องสร้างซอฟต์แวร์เองแทนการซื้อ ควรทุ่มทีมเก่งที่สุดลงตรงนี้Strategic Design ที่เล็กแต่คม
- Bounded ContextBounded Contextขอบเขตที่ชัดเจน (มักเป็นระบบย่อยหรือทีมหนึ่ง) ที่ model หนึ่งใช้ได้และมีความหมายแน่นอน ภายในขอบเขตนี้ Ubiquitous Language สอดคล้องกัน 100%Strategic Design ไม่ผูกกับสถาปัตยกรรมเดียว — ใช้คู่ Ports and AdaptersHexagonal Architectureสถาปัตยกรรม “Ports and Adapters” โดย Alistair Cockburn — วาง domain ไว้ตรงกลาง นิยาม port (interface) ให้ adapter ภายนอกมาเสียบ ทุก dependency ชี้เข้าหา domainArchitecture, REST, Event-Driven, CQRSCQRSCommand Query Responsibility Segregation — แยก model สำหรับ “เขียน/แก้ไข” (command) ออกจาก model สำหรับ “อ่าน” (query) เหมาะกับ domain ซับซ้อน แต่เพิ่มความซับซ้อน ใช้อย่างระมัดระวังArchitecture, microservices ได้ แต่ domain model ต้องปลอดเทคโนโลยี
เจาะลึกแนวคิดในบทนี้ต่อได้ที่คลังอ้างอิง DevIQ:
- Bounded Context — นิยามและตัวอย่างของ “ขอบเขตของภาษา” ที่เป็นแกนหลักของบทนี้
- Ubiquitous Language — ภาษากลางที่ทีมและ Domain Expert พัฒนาร่วมกันภายใน Bounded Context
- Domain และ Core Domain — ขยายความว่า Core Domain ต่างจาก subdomain อื่นอย่างไร และทำไมต้องกลั่นให้เล็กและคม
- Context Mapping — วิธีเชื่อมความสัมพันธ์ระหว่าง Bounded Context หลายอันที่บทนี้กล่าวถึงไว้
- Event Storming — เทคนิคเร่งค้นพบ scenario และขอบเขตของ Bounded Context ที่บทนี้แนะนำให้ลองใช้คู่กัน
เช็กความเข้าใจ — บทที่ 2
ข้อ 1 / 4คำว่า "Policy" ในงาน Underwriting, Claims, และ Inspections ควรถูกจัดการอย่างไรตามแนวทาง DDD?