บทที่ 24 · Part 5 — From Model to Running System
Application Boundaries and Transactions
รักษา domain decisions ภายใน model และให้ application layer ประสาน use case, transaction, authorization และ ports
Application Boundaries and Transactions
Domain Model ที่ดีอาจถูกทำลายได้ถ้า HTTP handler ตัดสิน policy, repository ส่ง ORM entity ให้ caller แก้ และ transaction commit ก่อน outbox Application boundary ทำให้ use case มีจุดประสาน actor, authorization, model, persistence และ external ports โดยไม่แย่ง business decision จาก domain
จบบทนี้คุณจะ
แยก driving adapter, Application Service และ domain model วาง authorization กับ transaction ที่เหมาะสม ออกแบบ command/result ที่ใช้ Ubiquitous Language และรักษา Domain Model จาก HTTP, JWT, SQL กับ vendor concerns โดยไม่ต้องเลือก architecture template ทั้งระบบ
Application Service เป็น Use-case Boundary
ตัวอย่าง ConfirmTransfer:
func (s Service) ConfirmTransfer(ctx context.Context, cmd ConfirmTransfer) error {
if err := s.authorizer.CanConfirm(ctx, cmd.Principal, cmd.IntentID); err != nil {
return err
}
return s.tx.Within(ctx, func(ctx context.Context) error {
intent, err := s.intents.ByID(ctx, cmd.IntentID)
if err != nil {
return err
}
if err := intent.Confirm(cmd.TermsVersion); err != nil {
return err
}
return s.intents.Save(ctx, intent)
})
}
Application Service orchestrates แต่ intent.Confirm ปกป้อง invariant
Driving Adapter แปล Transport
HTTP/CLI/message adapter:
- parse/shape validation
- authenticate และสร้าง Principal
- translate DTO เป็น application command
- call use case
- map errors/result เป็น protocol
Domain ไม่ parse JWT/header/status code และไม่รู้ framework
Authorization หลายชั้น
แยก:
| Layer | Decision |
|---|---|
| Edge/adapter | identity/token authenticity |
| Application | actor ใช้ use case/tenant/resource ได้ไหม |
| Domain | action ถูก policy/invariant ณ state นี้ไหม |
| Data | tenant/filter/grant ป้องกัน bypass |
| Audit | evidence ใครตัดสิน/ทำอะไร |
Domain rule maker cannot approve own request อาจอยู่ model/policy แต่ Principal mapping อยู่ adapter
Authorization Policy ต้องมี Owner
role, relationship, amount-based approval และ segregation rule ต้องมาจาก accountable Security/Risk/ Business owner พร้อม source/date Protocol authentication ไม่ตัดสิน domain policy แทน
Transaction Boundary
Local transaction ครอบ changes ที่ต้อง atomic ตาม Aggregate/use case แต่ห้ามเปิด database transaction ค้างระหว่าง network call
Pattern:
Transaction A: record intent/outbox
External call: provider with stable identity/idempotency
Transaction B: record observed outcome
Repair loop: reconcile unknown/crash
Business transaction ยาวกว่าหนึ่ง ACID transaction ต้องมี states/identity/recovery
Ports ตาม Purpose
Application-owned contracts เช่น:
type PaymentExecutor interface {
Execute(ctx context.Context, request ExecutionRequest) (ExecutionOutcome, error)
}
Outcome แยก declined, rejected, indeterminate, accepted ไม่คืน vendor DTO/HTTP error ตรง ๆ Port ใช้เมื่อปกป้อง meaningful boundary ไม่สร้าง interface ทุก function เพื่อ mocking
Command และ Result
Command สื่อ intent มี business identity และ caller context ไม่ใช่ HTTP payload copy:
ConfirmTransfer{IntentID, Principal, TermsVersion, RequestID}
Result สื่อ outcome ที่ caller ใช้ได้ แยก domain rejection จาก technical failure/unknown
แบบฝึกปฏิบัติ: Confirm Transfer Boundary
วาดและเขียน skeleton:
HTTP DTO -> Principal/Command -> Application Service -> Aggregate -> Repository
|
-> Outbox/Port after correct boundary
ระบุ validation/authorization/domain decision/transaction/error owner และทดสอบ duplicate command, version conflict, unauthorized principal, outbox failure
รายการตรวจสอบ
- Adapter แปล protocol และสร้าง Principal
- Application Service orchestrates ไม่ถือ hidden domain rule
- Domain model ไม่รู้ HTTP/JWT/SQL/vendor
- Transaction ครอบ atomic local changes
- Network call ไม่อยู่ใน long DB transaction
- Port/result ใช้ application language
- Authorization/domain policy/data isolation แยกชั้น
สรุปบทนี้
Application boundary เชื่อม model กับโลกจริงโดยรักษา responsibility: adapter จัด protocol, application ประสาน use case/transaction, domain ตัดสิน business behavior และ ports แปล external capabilities นี่เป็น consequence ของ model boundary ไม่ใช่เป้าหมาย DDD เอง
อ่านเพิ่มเติม
- DDD Reference — Layered Architecture และ Application Layer
- Hexagonal Architecture — boundary/ports ต้นทาง
- Go Transactions — official transaction guidance