Domain
องค์ความรู้ กิจกรรม และประเด็นทั้งหมดของธุรกิจหนึ่ง ๆ
ใน Domain-Driven Design (DDD) domain คือ “subject area ที่ผู้ใช้นำโปรแกรมไปประยุกต์ใช้” ตามคำของ Eric Evans ผู้บัญญัติศัพท์นี้ไว้ในหนังสือ Domain-Driven Design: Tackling Complexity in the Heart of Software (2003) กล่าวอีกแบบ domain คือองค์ความรู้ กิจกรรม กฎเกณฑ์ และประเด็นทั้งหมดที่เกี่ยวข้องกับปัญหาทางธุรกิจที่ซอฟต์แวร์ถูกสร้างขึ้นมาเพื่อรับใช้ ไม่ใช่ตัวซอฟต์แวร์เอง แต่เป็น “โลกจริง” ที่ซอฟต์แวร์พยายามจำลอง
domain มักซับซ้อนเกินกว่าจะจำลองเป็นหน่วยเดียวได้อย่างมีความหมาย ตัวอย่างเช่น domain รวมของระบบ eCommerce อาจเรียกได้ว่าเป็น “การค้าปลีกออนไลน์” (online retail) ซึ่งครอบคลุมทั้งการจัดการสินค้า การชำระเงิน การจัดส่ง การดูแลลูกค้า ฯลฯ — แต่ละส่วนมีภาษาและกฎของตัวเอง
ลักษณะสำคัญของ domain ได้แก่
- Entities — สิ่งหลักที่มีอยู่ในโลกของธุรกิจ เช่น ลูกค้า สินค้า คำสั่งซื้อ
- Rules — กฎที่กำกับพฤติกรรมและความถูกต้องของข้อมูลในธุรกิจนั้น
- Processes — กระบวนการทางธุรกิจ เช่น การประมวลผลคำสั่งซื้อ การอนุมัติสินเชื่อ
- Domain boundaries — ขอบเขตที่แยก domain หนึ่งออกจากอีก domain หนึ่ง
เพราะ domain มักใหญ่และซับซ้อน DDD จึงแนะนำให้แตกออกเป็น subdomain ย่อย ๆ ที่จัดการได้ง่ายกว่า และจัดลำดับความสำคัญด้วยแนวคิด Core Domain — พื้นที่หลักที่สร้างความแตกต่างเหนือคู่แข่งและควรได้รับความใส่ใจในการออกแบบมากที่สุด ส่วน Supporting subdomain และ Generic subdomain มีความสำคัญรองลงมา (ดู Subdomains)
บทบาทใน DDD
หัวข้อที่มีชื่อว่า “บทบาทใน DDD”domain คือจุดเริ่มต้นของ DDD ทั้งหมด — ก่อนจะเขียน code สักบรรทัด ทีมต้องทำความเข้าใจ domain ผ่านการพูดคุยกับ domain expert เทคนิคอย่าง Event Storming หรือ Domain Storytelling ช่วยให้ทีมสำรวจ domain แบบมีโครงสร้างโดยไม่ต้องรีบตัดสินใจเรื่องเทคโนโลยี
เมื่อเข้าใจ domain แล้ว งานออกแบบใน DDD แบ่งเป็นสองระดับ:
- Strategic Design (Strategic Design) — มองภาพใหญ่ ว่า domain ควรถูกแบ่งเป็น subdomain อะไรบ้าง และแต่ละ subdomain ควรสอดคล้องกับ Bounded Context ใด พร้อมทำ Context Mapping เพื่อบันทึกความสัมพันธ์ระหว่าง context เหล่านั้น
- Tactical Design (Tactical Design) — ลงรายละเอียดภายในแต่ละ Bounded Context ด้วย pattern เช่น Entity, Value Object, Aggregate เพื่อสร้าง Domain Model ที่สะท้อนกฎของ domain จริง
ทีมและ domain expert ร่วมกันสร้าง Ubiquitous Language — ภาษากลางที่ใช้เรียกแนวคิดใน domain อย่างสอดคล้องกันทั้งในบทสนทนา เอกสาร และ code เพราะคำเดียวกันอาจมีความหมายต่างกันใน domain หรือ Bounded Context ต่างกัน (เช่นคำว่า “Account” ในบริบทบัญชีผู้ใช้ กับ “Account” ในบริบทบัญชีการเงิน)
Vaughn Vernon ใน Implementing Domain-Driven Design เน้นย้ำว่าการลงทุนเวลาทำความเข้าใจ domain ให้ลึกคือสิ่งที่แยก DDD ออกจากการออกแบบซอฟต์แวร์ทั่วไป เพราะ model ที่ดีต้องผ่านการทำซ้ำ (iterate) ร่วมกับ domain expert ไม่ใช่เดาเอาจาก requirement document เพียงอย่างเดียว
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”สมมติบริษัท Fabrikam ทำธุรกิจส่งพัสดุด้วยโดรน domain รวมของบริษัทคือ “การจัดส่งด้วยโดรน” ซึ่งเมื่อวิเคราะห์แล้วแตกเป็นหลาย subdomain: Shipping และ Drone Management เป็น Core subdomain เพราะเป็นจุดที่สร้างความได้เปรียบ ส่วน Invoicing เป็น Supporting subdomain และ User Accounts กับ Call Center เป็น Generic subdomain ที่อาจใช้ระบบสำเร็จรูปแทนได้
graph TD
Domain[Domain: Drone Delivery]
Core1[Core: Shipping]
Core2[Core: Drone Management]
Supporting[Supporting: Invoicing]
Generic1[Generic: User Accounts]
Generic2[Generic: Call Center]
BC1[Bounded Context: Shipping]
BC2[Bounded Context: Accounts]
UL[Ubiquitous Language]
Domain --> Core1
Domain --> Core2
Domain --> Supporting
Domain --> Generic1
Domain --> Generic2
Core1 --> BC1
Generic1 --> BC2
BC1 --> UL
BC2 --> UL
code ด้านล่างแสดงว่าการแบ่ง domain และ subdomain ไม่ใช่แค่แนวคิดบนกระดาน แต่สะท้อนลงมาถึงโครงสร้าง namespace และตำแหน่งที่กฎของ domain (“domain logic”) อยู่ใน code จริง
// Core subdomain: การจัดส่งคือหัวใจของธุรกิจ ต้องจำลองอย่างละเอียดและดูแลใกล้ชิดที่สุดnamespace Fabrikam.Shipping.Domain{ public class DeliveryOrder { public Guid Id { get; } public DroneAssignment Assignment { get; private set; }
public DeliveryOrder(Guid id) { Id = id; }
// กฎของ domain (domain rule) ถูกเก็บไว้ในตัว Entity เอง // ไม่ใช่กระจัดกระจายอยู่ใน service หรือ controller ภายนอก public void AssignDrone(Drone drone) { if (!drone.IsAvailable) { throw new InvalidOperationException("โดรนลำนี้ไม่ว่างสำหรับงานจัดส่ง"); }
Assignment = new DroneAssignment(drone.Id, DateTime.UtcNow); } }
public record DroneAssignment(Guid DroneId, DateTime AssignedAtUtc);
public class Drone { public Guid Id { get; } public bool IsAvailable { get; private set; } = true;
public Drone(Guid id) => Id = id; }}
// Generic subdomain: การจัดการบัญชีผู้ใช้ไม่ใช่จุดต่างของธุรกิจ// จึงเรียบง่ายกว่ามาก และอาจแทนที่ด้วยบริการสำเร็จรูป (เช่น identity provider) ได้namespace Fabrikam.Accounts.Domain{ public class UserAccount { public Guid Id { get; } public string Email { get; private set; }
public UserAccount(Guid id, string email) { Id = id; Email = email; } }}สังเกตว่า Fabrikam.Shipping.Domain มี invariant และ business rule ที่ซับซ้อน สมกับเป็น Core subdomain ในขณะที่ Fabrikam.Accounts.Domain เป็นเพียง data holder ง่าย ๆ เพราะเป็น Generic subdomain — นี่คือวิธีที่การเข้าใจ domain อย่างถูกต้องนำไปสู่การตัดสินใจลงทุนความพยายามในการออกแบบอย่างเหมาะสม
ความสัมพันธ์กับแนวคิดอื่น
หัวข้อที่มีชื่อว่า “ความสัมพันธ์กับแนวคิดอื่น”- Domain vs. Subdomain — domain และ subdomain เป็นคำสัมพัทธ์ (relative term) เดียวกัน ต่างกันแค่ระดับ: เมื่อเรียกบางสิ่งว่า subdomain หมายความว่ามันเป็นส่วนย่อยของ domain ที่ใหญ่กว่าซึ่งเรากำลังพูดถึงอยู่ ดู Subdomains
- Domain vs. Bounded Context — domain/subdomain อยู่ใน “problem space” (พื้นที่ปัญหาทางธุรกิจ) ส่วน Bounded Context อยู่ใน “solution space” (พื้นที่คำตอบที่ทีมออกแบบ) โดยอุดมคติแล้วแต่ละ subdomain ควรถูกจับคู่กับ Bounded Context หนึ่งเดียว แต่ในทางปฏิบัติความสัมพันธ์อาจไม่ตรงกันเป๊ะ ดู Bounded Context
- Domain vs. Domain Model — domain คือความรู้และความเป็นจริงทางธุรกิจ ส่วน Domain Model คือตัวแทนเชิงซอฟต์แวร์ของความรู้นั้นที่ทีมสร้างขึ้นและวิวัฒน์ไปพร้อมกับความเข้าใจที่ลึกขึ้น
- Domain vs. Ubiquitous Language — Ubiquitous Language คือภาษาที่ทีมและ domain expert ใช้ร่วมกันเพื่ออธิบาย domain นั้นให้ตรงกันทั้งในคำพูดและ code
- Core Domain vs. Shared Kernel — เมื่อหลาย Bounded Context ต้องใช้แนวคิดร่วมกันจาก domain เดียวกัน อาจเลือกทำ Shared Kernel เพื่อ share model บางส่วนอย่างระมัดระวัง
ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”แหล่งอ้างอิง
หัวข้อที่มีชื่อว่า “แหล่งอ้างอิง”- ที่มา · deviq.com/domain-driven-design/domain
- Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003.
- Vernon, Vaughn. Implementing Domain-Driven Design. Addison-Wesley, 2013.
- Domain-Driven Design — Martin Fowler’s Bliki
- Use Domain Analysis to Model Microservices — Azure Architecture Center, Microsoft Learn
- Domain-Driven Design Reference — domainlanguage.com (Eric Evans)