Bounded Context
ขอบเขตภายใน domain ที่บรรจุ model ของบริบทนั้นไว้
Bounded Context คือ ขอบเขตเชิงภาษาและเชิง model (linguistic and model boundary) ที่ห่อหุ้ม ubiquitous language หนึ่งชุดไว้ ภายในขอบเขตนั้น คำศัพท์ทุกคำ — ชื่อ entity, value object, aggregate, method, event — มีความหมายเดียว ไม่คลุมเครือ และสอดคล้องกันทั้งใน code เอกสาร diagram และบทสนทนาของทีม
Eric Evans อธิบายไว้ใน “Domain-Driven Design” (2003) ว่าระบบขนาดใหญ่ไม่สามารถมี model เดียวที่ “รวมเป็นหนึ่ง” (unified) ครอบคลุมทั้งองค์กรได้อย่างคุ้มค่า เพราะแต่ละส่วนของธุรกิจมักใช้คำเดียวกันในความหมายต่างกัน Martin Fowler ยกตัวอย่างคำว่า “meter” ในบริษัทไฟฟ้า — ทีมวัดปริมาณการใช้ไฟมองว่า meter คืออุปกรณ์วัด แต่ทีมบัญชีมองว่า meter คือจุดอ้างอิงในการเรียกเก็บเงิน ทั้งสองความหมายถูกต้องในบริบทของตัวเอง แต่จะชนกันถ้าพยายามยัดรวมไว้ใน model เดียว Bounded Context จึงทำหน้าที่แยกความหมายเหล่านี้ออกจากกันอย่างชัดเจน แทนที่จะพยายามหา “ความจริงหนึ่งเดียว” ที่ใช้ได้กับทุกคน
ข้อควรระวัง: bounded context ไม่ใช่ แค่ “module” หรือ “layer” ทางเทคนิค แต่คือขอบเขตที่ถูกกำหนดโดยความหมายและการใช้ภาษาของคนในองค์กร — บ่อยครั้งจึงล้อไปกับโครงสร้างทีมและวัฒนธรรมองค์กร (สัมพันธ์กับ Conway’s Law)
บทบาทใน DDD
หัวข้อที่มีชื่อว่า “บทบาทใน DDD”Bounded Context เป็นแกนกลางของ strategic design ใน DDD (คู่กับ tactical design ที่ว่าด้วย entity/value object/aggregate ภายในบริบทเดียว) บทบาทหลักมีสามด้าน
- ควบคุมความสอดคล้องของภาษา — ทีมงานในบริบทเดียวกันพูดคุยด้วยคำศัพท์เดียวกันโดยไม่ต้องแปลไปมา ลดความเข้าใจผิดระหว่าง developer กับ domain expert
- กำหนดขอบเขตความรับผิดชอบของทีมและ codebase — domain หนึ่ง (domain ที่แตกเป็นหลาย subdomain) อาจมีหลาย bounded context และแต่ละอันมักดูแลโดยทีมต่างกัน เช่นระบบ eCommerce อาจมี Catalog, Customer, Inventory, Order, Marketing, Fraud Detection เป็นบริบทแยกกัน
- เป็นหน่วยของการวางสถาปัตยกรรม — ความสัมพันธ์ระหว่าง bounded context หลายอันถูกอธิบายด้วย Context Mapping ซึ่งระบุ pattern ความสัมพันธ์ เช่น Shared Kernel, Customer-Supplier, Conformist, Anti-Corruption Layer (ACL) และ Open Host Service
แนวปฏิบัติสมัยใหม่ (เช่นแนวทางของ Microsoft Azure Architecture Center สำหรับ microservices) แนะนำว่า ไม่ควรให้ microservice หนึ่งครอบคลุมมากกว่า1 bounded context และในทางกลับกัน microservice ที่เล็กเกินไปมักเป็นเพียง aggregate เดียวภายใน bounded context — กล่าวคือขนาดที่เหมาะสมของ microservice ควรอยู่ระหว่าง “ไม่เล็กกว่า aggregate” และ “ไม่ใหญ่กว่า bounded context” นี่คือเหตุผลที่ bounded context มักถูกใช้เป็นจุดเริ่มต้นในการตัดแบ่ง microservices architecture
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”ระบบ eCommerce หนึ่งระบบอาจมีคำว่า “Product” ปรากฏในหลายบริบท แต่แต่ละบริบทให้ความหมายและ attribute ต่างกัน
- ใน Catalog context — Product คือรายการที่มีชื่อ คำอธิบาย รูปภาพ และหมวดหมู่ สำหรับให้ลูกค้าค้นหาและเปรียบเทียบ
- ใน Inventory context — Product (หรือเรียกว่า SKU) คือหน่วยที่มีจำนวนคงเหลือในคลัง ตำแหน่งจัดเก็บ และสถานะการเติมสินค้า
- ใน Order context — Product ปรากฏเป็น line item ที่ตรึงราคาและชื่อ ณ เวลาที่สั่งซื้อไว้ (snapshot) เพื่อไม่ให้ราคาที่เปลี่ยนภายหลังกระทบใบสั่งซื้อเก่า
ทั้งสามบริบทไม่ได้ใช้ class Product ร่วมกัน แต่ละบริบทมี model ของตัวเอง และเชื่อมต่อกันผ่านการแปลข้อมูล (translation) ที่ชายแดนของบริบท ตัวอย่าง code C# ด้านล่างแสดงว่า Catalog context และ Order context ต่างมีนิยาม Product เป็นของตัวเอง โดยมี translator ทำหน้าที่แปลงข้อมูลข้ามขอบเขต
// ===== Catalog bounded context =====// Product ที่นี่เน้นข้อมูลสำหรับแสดงผลและค้นหาnamespace Catalog.Domain{ public class Product { public Guid ProductId { get; } public string Name { get; } public string Description { get; } public string Category { get; } public decimal CurrentPrice { get; private set; }
public Product(Guid productId, string name, string description, string category, decimal currentPrice) { ProductId = productId; Name = name; Description = description; Category = category; CurrentPrice = currentPrice; }
public void Reprice(decimal newPrice) => CurrentPrice = newPrice; }}
// ===== Order bounded context =====// Product ที่นี่คือ value object ของ line item ตรึงค่า ณ เวลาสั่งซื้อ ไม่อ้างอิงถึง Catalog.Product เลยnamespace Order.Domain{ public sealed class OrderedProduct { public Guid ProductId { get; } public string NameSnapshot { get; } public decimal PriceSnapshot { get; }
public OrderedProduct(Guid productId, string nameSnapshot, decimal priceSnapshot) { ProductId = productId; NameSnapshot = nameSnapshot; PriceSnapshot = priceSnapshot; } }
// translator ที่ชายแดนระหว่างสองบริบท แปลง Catalog.Product เป็น OrderedProduct public static class CatalogToOrderTranslator { public static OrderedProduct Translate(Catalog.Domain.Product catalogProduct) { // จงใจคัดลอกเฉพาะข้อมูลที่ Order context ต้องใช้ ณ เวลานี้เท่านั้น return new OrderedProduct( catalogProduct.ProductId, catalogProduct.Name, catalogProduct.CurrentPrice); } }}แผนภาพต่อไปนี้แสดง domain eCommerce ที่แบ่งออกเป็นหลาย bounded context โดยแต่ละอันมี ubiquitous language ของตัวเอง และเชื่อมต่อกันผ่าน context mapping
graph TB
Domain[eCommerce Domain]
Catalog[Catalog Context]
Inventory[Inventory Context]
Order[Order Context]
Fraud[Fraud Detection Context]
UL1[Ubiquitous Language A]
UL2[Ubiquitous Language B]
UL3[Ubiquitous Language C]
Domain --> Catalog
Domain --> Inventory
Domain --> Order
Domain --> Fraud
Catalog --> UL1
Inventory --> UL2
Order --> UL3
Catalog -.->|context mapping| Order
Order -.->|context mapping| Inventory
Order -.->|context mapping| Fraud
ความสัมพันธ์กับแนวคิดอื่น
หัวข้อที่มีชื่อว่า “ความสัมพันธ์กับแนวคิดอื่น”- Domain และ Subdomain — domain คือพื้นที่ปัญหาทางธุรกิจทั้งหมด ซึ่งวิเคราะห์แตกเป็น subdomain (core/supporting/generic) ส่วน bounded context คือขอบเขตของ solution space — โดยอุดมคติแล้ว bounded context หนึ่งควรสอดคล้องกับ subdomain หนึ่ง แต่ในทางปฏิบัติความสัมพันธ์อาจไม่ตรงกันเป๊ะเสมอไป (หลาย context ต่อ1 subdomain หรือกลับกัน)
- Ubiquitous Language — แต่ละ bounded context มี ubiquitous language เป็นของตัวเอง คำเดียวกันอาจมีความหมายต่างกันคนละบริบท นี่คือสาเหตุหลักที่ต้องมีขอบเขตตั้งแต่แรก
- Context Mapping — เมื่อมีหลาย bounded context ความสัมพันธ์ระหว่างกันต้องถูกอธิบายอย่างชัดเจนด้วย Context Mapping ผ่าน pattern ต่าง ๆ เช่น Shared Kernel, Anti-Corruption Layer, Open Host Service
- Anti-Corruption Layer — เมื่อ bounded context ต้องเชื่อมกับระบบ legacy หรือบริบทที่ model ไม่สอดคล้องกัน มักใช้ ACL เป็นชั้นแปลข้อมูลกัน model ของบริบทตัวเองไม่ให้ถูก “ปนเปื้อน”
- Conway’s Law — ขอบเขตของ bounded context มักสะท้อนโครงสร้างการสื่อสารของทีม/องค์กร ตาม Conway’s Law ทีมที่แยกกันมักผลิตบริบทที่แยกกันตามไปด้วย
- Microservices — ในสถาปัตยกรรม microservices สมัยใหม่ bounded context มักถูกใช้เป็นเกณฑ์กำหนดขอบเขตของ service แต่ละตัว เพื่อไม่ให้ service เดียวต้องรับผิดชอบมากกว่า1 model domain
ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”แหล่งอ้างอิง
หัวข้อที่มีชื่อว่า “แหล่งอ้างอิง”- ที่มา · deviq.com/domain-driven-design/bounded-context
- Bounded Context — Martin Fowler’s bliki
- Identify microservice boundaries — Azure Architecture Center, Microsoft Learn
- Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software (2003) — บทว่าด้วย Bounded Context และ strategic design
- Vaughn Vernon, Implementing Domain-Driven Design (2013) — บทที่ 2 ว่าด้วยการระบุและออกแบบ Bounded Context ร่วมกับ Ubiquitous Language