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

Subdomains

พื้นที่​ความ​รู้​ย่อย​ที่​นิยาม​ชัดเจน​ภายใน domain ใหญ่

Subdomain คือ พื้นที่​ความ​รู้​หรือ​ความ​รับผิดชอบ​ย่อย​ที่​นิยาม​ไว้​ชัดเจน ภายใน domain ที่​ใหญ่​กว่า เกิด​จาก​การ​แตก domain ทั้ง​ก้อน (เช่น “การ​ค้า​ปลีก​ออนไลน์”) ออก​เป็น​ส่วน​ย่อย​ที่​มี cohesion สูง​และ​มี​ขอบเขต​ชัดเจน​จาก​ส่วน​อื่น เช่น “การ​จัดการ​สินค้า”, “การ​ชำระ​เงิน”, “การ​จัด​ส่ง” แต่ละ subdomain ยัง​แตก​ย่อย​ลง​ไป​อีก​ได้​เรื่อย ๆ ตาม​ความ​ซับซ้อน​ของ​ธุรกิจ

จุด​ที่​มัก​สับสน คือ​ความ​สัมพันธ์​ระหว่าง subdomain กับ Bounded Context — subdomain เป็น​ส่วน​หนึ่ง​ของ problem space (ปัญหา​ทาง​ธุรกิจ​ที่​มี​อยู่​จริง ไม่​ว่า​เรา​จะ​เขียน code หรือ​ไม่) ส่วน bounded context เป็น​ส่วน​หนึ่ง​ของ solution space (ขอบเขต​ของ model ซอฟต์แวร์​ที่​เรา​ออกแบบ​ขึ้น​เพื่อ​ตอบ​ปัญหา​นั้น) ทีม​งาน​ค้น​พบ subdomain ได้​จาก​การ​วิเคราะห์​ธุรกิจ เช่น event storming หรือ domain storytelling ก่อน​ที่​จะ​ตัดสิน​ใจ​ว่า​จะ​สร้าง bounded context ใด​มารองรับ ใน​ทาง​อุดมคติ subdomain หนึ่ง​ควร​ตรง​กับ bounded context หนึ่ง แต่​ใน​ความ​เป็น​จริง​บาง​ครั้ง bounded context เดียว​อาจ​ตอบ​สนอง​หลาย subdomain (มัก​เป็น​สัญญาณ​ของ​ขอบเขต​ที่​ยัง​ไม่​ลงตัว) หรือ subdomain เดียว​อาจ​ถูก​รองรับ​ด้วย​หลาย bounded context ก็ได้

การ​ค้นหา​ขอบเขต​ของ subdomain มัก​อาศัย​สัญญาณ​จาก​ภาษา (คำ​ศัพท์​ทาง​ธุรกิจ​เริ่ม​เปลี่ยน​ความหมาย​หรือ​เริ่ม​ไม่​เกี่ยวข้อง​กัน), จาก​ความ​สัมพันธ์​เชิง​หน้าที่ (function ไหน​ผูก​ติด​กัน​แน่น​เป็นกลุ่ม​เดียวกัน) และ​จาก​โครงสร้าง​องค์กร (แผนก​หรือ​ทีม​ที่​ดูแล​ความ​รับผิดชอบ​นั้น​อยู่​แล้ว) Microsoft Learn แนะนำ​ให้​เริ่ม​จาก​การ​ร่าง​แผนภาพ​ความ​สัมพันธ์​ของ function ทาง​ธุรกิจ​ทั้งหมด​แบบ​หยาบ ๆ ก่อน แล้ว​ค่อย​มอง​หากลุ่ม​ก้อน​ที่​มี cohesion สูง​เพื่อ​ตัด​ออก​มา​เป็น subdomain แต่ละ​อัน

Subdomain เป็น​เครื่องมือ​หลัก​ของ strategic design ใน DDD ใช้​ตอบ​คำถาม​ว่า “ควร​ทุ่ม​ความ​พยายาม​ใน​การ​ออกแบบ​และ​ลงทุน​ทีม​ที่​เก่ง​ที่สุด​ไป​ที่​ส่วน​ไหน​ของ​ระบบ” Eric Evans และ Vaughn Vernon แบ่ง​ประเภท​ของ subdomain ไว้ 3 แบบ:

  • Core subdomain: พื้นที่​หลัก​ที่​สร้าง​ความ​ได้​เปรียบ​ใน​การ​แข่งขัน เป็น​เหตุผล​ที่​องค์กร​มี​อยู่​และ​แตก​ต่าง​จาก​คู่แข่ง ควร​ได้​รับ​ความ​สนใจ​สูงสุด ทีม​ที่​เก่ง​ที่สุด และ​ความ​พยายาม​ใน​การ​ออกแบบ (distillation) มาก​ที่สุด
  • Supporting subdomain: จำเป็นต่อ​ความ​สำเร็จ​ของ​องค์กร แต่​ไม่ใช่​จุด​สร้าง​ความ​แตก​ต่าง มัก​ต้อง​พัฒนา​แบบ custom เพราะ​ไม่มี​โซลูชัน​สำเร็จรูป​ที่​เหมาะสม แต่ core domain จะ​ทำงาน​ไม่​ได้​ถ้า​ขาด​ส่วน​นี้
  • Generic subdomain: จำเป็นต่อ​การ​ดำเนิน​งาน​แต่​ไม่​สร้าง​ความ​ได้​เปรียบ​ใด ๆ อุตสาหกรรม​มัก​แก้​ปัญหา​นี้​ไป​แล้ว จึง​นำ​กลับ​มา​ใช้​ซ้ำ ซื้อ​สำเร็จรูป หรือ outsource ได้ เช่น authentication/authorization, payment processing, messaging, user identity management

การ​จำแนก​ประเภท​นี้​ช่วย​จัด​ลำดับ​ความ​สำคัญ​ของ​ทรัพยากร ทีม​ที่​เก่ง​ที่สุด​ควร​อยู่​กับ core subdomain ส่วน generic subdomain ควร​ใช้​ของ​สำเร็จรูป​แทน​การ​เขียน​เอง​เพื่อ​ประหยัด​ความ​พยายาม​ไป​ลง​กับ​สิ่ง​ที่​สร้าง​มูลค่า​จริง กระบวนการ​ทำงาน​ทั่วไป​คือ วิเคราะห์ domain ธุรกิจ (มัก​เริ่ม​จาก event storming) เพื่อ​ค้นหา​ว่า​มี subdomain อะไร​บ้าง​และ​แต่ละ​อัน​คือ core, supporting หรือ generic จาก​นั้น​จึง​กำหนด bounded context และ context map ตาม​มา​ใน​ขั้น solution space

Vaughn Vernon ใน Implementing Domain-Driven Design เสนอ​แนวคิด “Core Domain Chart” คือ​การ​ให้​ทีม​ประเมิน subdomain แต่ละ​อัน​บน​สอง​แกน ได้แก่ ระดับ​ความ​แตก​ต่าง​ทาง​ธุรกิจ (business differentiation) กับ​ระดับ​ความ​ยุ่งเหยิง​ของ model ที่​มี​อยู่ (model chaos) subdomain ที่​แตก​ต่าง​สูง​แต่ model ยัง​ไม่​ชัดเจน คือ​ผู้​สมัคร core domain ที่​ควร​ได้​รับ​การ​ลงทุน​ออกแบบ​และ distillation มาก​ที่สุด ใน​ขณะ​ที่ subdomain ที่​แตก​ต่าง​ต่ำ​ควร​ถูก​ผลัก​ไป​เป็น supporting หรือ generic แล้ว​ปล่อย​ให้​ทีม​ภายนอก​หรือ​โซลูชัน​สำเร็จรูป​ดูแล​แทน

Microsoft Learn ยก​ตัวอย่าง​บริการ​ส่ง​ของ​ด้วย​โด​รน​ของ​บริษัท​สมมติ Fabrikam ซึ่ง​วิเคราะห์ domain ออก​มา​ได้ subdomain ดังนี้: Shipping และ Drone management เป็น core subdomain เพราะ​เป็น​หัวใจ​ของ​ธุรกิจ, Invoicing เป็น supporting subdomain เพราะ​ต้อง​พัฒนา​เอง​แต่​ไม่ใช่​จุด​ขาย, ส่วน User accounts และ Call center เป็น generic subdomain เพราะ​มี​โซลูชัน​สำเร็จรูป​ให้​ใช้ได้​เลย

graph TD
    Domain[Drone Delivery Domain]
    Domain --> Shipping[Shipping Core]
    Domain --> DroneMgmt[Drone Management Core]
    Domain --> Invoicing[Invoicing Supporting]
    Domain --> UserAccounts[User Accounts Generic]
    Shipping --> ShippingBC[Shipping Bounded Context]
    DroneMgmt --> DroneBC[Drone Management Bounded Context]
    Invoicing --> InvoicingBC[Invoicing Bounded Context]
    UserAccounts --> IdentityBC[Identity Bounded Context]

ตัวอย่าง code C# ด้าน​ล่าง​จำลอง​การ​ทำ “domain map” เป็น​ข้อมูล​ใน code เพื่อ​สื่อสาร​ให้​ทั้ง​ทีม​เห็น​ตรง​กัน​ว่า​แต่ละ bounded context สังกัด subdomain ประเภท​ใด และ​ควร​ได้​รับ​ความ​สนใจ​มาก​น้อย​เพียง​ใด:

// ประเภทของ subdomain ตามการจำแนกของ Evans/Vernon
public enum SubdomainType
{
Core,
Supporting,
Generic
}
// แผนที่ subdomain หนึ่งรายการ พร้อมรายชื่อ bounded context ที่รองรับ subdomain นั้น
public sealed record SubdomainMap(
string Name,
SubdomainType Type,
IReadOnlyList<string> BoundedContexts);
// ผลจากการวิเคราะห์ domain ของ Fabrikam ก่อนตัดสินใจเรื่องสถาปัตยกรรมใด ๆ
public static class FabrikamDomainMap
{
public static readonly IReadOnlyList<SubdomainMap> Subdomains = new[]
{
new SubdomainMap("Shipping", SubdomainType.Core,
new[] { "Ordering", "Delivery" }),
new SubdomainMap("DroneManagement", SubdomainType.Core,
new[] { "FleetControl" }),
new SubdomainMap("Invoicing", SubdomainType.Supporting,
new[] { "Billing" }),
new SubdomainMap("UserAccounts", SubdomainType.Generic,
new[] { "Identity" }),
};
// ใช้จัดลำดับว่าทีมเก่ง ๆ ควรถูกจัดสรรไปที่ subdomain ไหนก่อน
public static IEnumerable<SubdomainMap> ByInvestmentPriority() =>
Subdomains.OrderBy(s => s.Type); // Core มาก่อน Supporting มาก่อน Generic
}

code นี้​ไม่ใช่ pattern ทาง​เทคนิค​ที่​ต้อง implement ตรง ๆ แต่​เป็น​ตัวอย่าง​ว่าการ​ตัดสิน​ใจ​เชิงกลยุทธ์ (strategic design) สามารถ​ทำให้​ชัดเจน​และ​ตรวจสอบ​ได้​ใน​ระดับ code เช่น การ​เขียน test ที่​ยืนยัน​ว่า generic subdomain อย่าง UserAccounts ไม่​ได้​ถูก​พัฒนา​เอง​ทั้งหมด​โดย​ทีม core

  • Subdomain vs. Bounded Context: subdomain อยู่​ใน problem space ส่วน bounded context อยู่​ใน solution space ทีม​มัก​ค้น​พบ subdomain ก่อน​แล้ว​จึง​ออกแบบ bounded context ตาม แต่​ทั้ง​สอง​ไม่​จำเป็น​ต้อง​ตรง​กัน​แบบ 1 ต่อ 1 เสมอ​ไป
  • Subdomain vs. Domain: Domain คือ​ภาพ​รวม​ทั้งหมด​ของ​ปัญหา​ธุรกิจ ส่วน subdomain คือ​ส่วน​ย่อย​ที่​แตก​ออก​มา​เพื่อ​ให้​จัดการ​ความ​ซับซ้อน​ได้​ง่าย​ขึ้น
  • Core subdomain กับ Distillation: Evans ใช้​กระบวนการ distillation เพื่อ​กลั่นกรอง​แยก core domain ออก​จาก generic subdomain และ cohesive mechanism ให้​ทีม​โฟกัส​พลังงาน​ไป​ที่​ส่วน​ที่​สร้าง​มูลค่า​จริง
  • Generic subdomain กับ Anti-Corruption Layer: เมื่อ generic subdomain ถูก outsource หรือ​ซื้อ​สำเร็จรูป มัก​ต้อง​มี Anti-Corruption Layer กัน​ไม่​ให้ model ภายนอก​รั่วไหล​เข้า​มา​ปน​กับ core domain
  • Subdomain กับ Context Mapping: หลัง​ระบุ subdomain และ​แปลง​เป็น bounded context แล้ว ทีม​ยัง​ต้อง​ทำ Context Mapping เพื่อ​บันทึก​ความ​สัมพันธ์​และ​รูปแบบ​การ​รวม​กัน (integration) ระหว่าง bounded context เหล่า​นั้น
  • Subdomain กับ Ubiquitous Language: แต่ละ subdomain (และ bounded context ที่​รองรับ​มัน) มัก​มี​ภาษา​กลาง​ของ​ตัวเอง​ที่​แตก​ต่าง​กัน เช่น คำ​ว่า “account” ใน subdomain การเงิน​อาจ​หมาย​ถึง​บัญชี​เงิน ใน​ขณะ​ที่ subdomain บัญชี​ผู้​ใช้​อาจ​หมาย​ถึง​ตัวตน​ของ​ผู้​ใช้​ระบบ การ​แยก subdomain ให้​ชัด​จึง​ช่วย​ลด​ความ​กำกวม​ของ​ภาษา​ไป​ใน​ตัว