บทที่ 25 · Part 5 — Enterprise Fintech Architecture
Evolution and Capstone
วิวัฒน์ architecture จาก module เล็กสู่ enterprise boundaries และส่งมอบ capstone journeys พร้อม ADR และ trigger
Evolution and Capstone
Architecture ไม่ควรถูกเลือกครั้งเดียวตอนสร้าง repository แล้วรักษา tree เดิมตลอด Product, teams, rules และ failure profile เปลี่ยน Codebase ที่เริ่มเรียบง่ายอาจต้องมี domain model, module boundary หรือ deployable แยก แต่การกระโดดไป microservices ก่อนมี evidence ก็สร้าง distributed complexity เร็วกว่าความรู้
จบบทนี้คุณจะ
วาง evolutionary path จาก small module ถึง separate deployables ใช้ change history, ownership, scaling, security และ failure isolation เป็น extraction evidence เขียน ADR พร้อม reevaluation signals และส่งมอบ capstone 2 Fintech journeys ครบ domain/code/data/security/reliability
[!IMPORTANT] วิธีอ่านหลักฐานในบทนี้ คำที่เป็น Definition/Pattern มีแหล่งต้นทางอยู่ใกล้ claim ส่วน decision table, starting structure, checklist และ lab เป็น Heuristic/Trade-off หรือ Course Convention สำหรับฝึกตัดสินใจ ไม่ใช่มาตรฐานสากล เว้นแต่บทจะระบุแหล่งและขอบเขตไว้ชัดเจน
เส้นทางวิวัฒน์ Architecture
ระยะที่ 1: Business Slice ขนาดเล็ก
internal/customer/
service.go
http.go
mysql.go
เหมาะกับ use cases น้อย ทีมเดียวและ dependency เรียบง่าย Guardrails คือ tenant scope, transaction tests และ exit criteria
ระยะที่ 2: Module ที่มี Domain Model
เมื่อ state/rules หนาแน่น เพิ่ม domain values, use-case files, consumed ports และ focused repository โดยไม่เปลี่ยน business name
ระยะที่ 3: Modular Application
เมื่อมีหลาย capabilities จัด outer slices, public contracts, data ownership และ import fitness หลาย modules ยัง deploy ใน process/database infrastructure เดียวได้
ระยะที่ 4: แยกเป็นระบบที่ Deploy ได้อิสระ
พิจารณาเมื่อมี evidence เช่น:
- team ownership/release cadence แยกและ coordination cost วัดได้
- runtime scaling profile ต่างอย่างมีนัยสำคัญ
- security/network/data boundary ต้อง isolate
- failure containment/availability objective ต่าง
- technology/runtime requirement ที่ module boundary รับไม่พอ
ต้องมี contract, observability, data migration, rollback, operational owner และ consistency story พร้อมก่อน extraction
อย่าแยก Service เพราะเห็นโครงสร้าง Folder อย่างเดียว
Package boundary ช่วยซ้อม extraction แต่ไม่พิสูจน์ว่า network boundary คุ้ม Direct function call กลายเป็น latency/partial failure/versioning เมื่อแยก process Shared transaction ต้องเปลี่ยนเป็น workflow/outbox/reconciliation
Monolith First เสนอ strategy หนึ่งพร้อม ยอมรับว่าหลักฐานมีข้อจำกัด จึงใช้เป็น trade-off ไม่ใช่กฎ เริ่มด้วย services ได้หาก boundary, team และ operational platform พร้อมจริง
ADR พร้อมสัญญาณทบทวน
ADR: Keep Invoicing and Receivables as modules in one deployable
Context: separate language/data owners, but one team and shared release cadence today
Decision: module contracts + separate schemas/grants; synchronous in-process command
Accepted costs: shared runtime failure and coordinated deployment
Rejected alternatives: immediate service split; shared table access
Fitness checks: no cross-repository imports; contract-only writes
Reevaluate when: separate teams, independent SLO/scaling, or release coupling exceeds target
Owner / date: Billing Architecture Group / 2026-08-08
Trigger ต้องสังเกตได้ ไม่ใช้ “เมื่อระบบโต” บันทึก decision owner/date และ supersede ADR เก่า แทนการแก้ history เงียบ
Evolution ของ financial controls ต้องรักษาหลักฐาน
Data migration, dual write, ledger correction, authorization policy และ audit retention ต้องมี responsible owners/approved plan การแยก service ไม่ได้อนุญาตให้ลด invariant, idempotency, reconciliation หรือ tenant isolation เพื่อให้ cutover ง่าย
โจทย์สรุป A: Wallet Top-up
Journey:
ต้องส่งมอบ:
- scenario/glossary พร้อม
UNKNOWN - Subdomain/Context classification พร้อม uncertainties
- Checkout/Wallet/Connectivity contracts และ translations
- architecture choice ต่อ module
- Go tree/import rules
- PaymentGateway port + pinned provider translation
- Principal/tenant authorization boundary
- MySQL authoritative/idempotency/concurrency map
- Redis display-only view และ freshness
- crash matrix/outbox/inbox/reconciliation
- test/fitness evidence
Acceptance: replay ทุก crash point ไม่สร้าง provider charge หรือ Wallet credit ซ้ำ และ decision ไม่อ่าน Portal cache
โจทย์สรุป B: จาก Billing สู่ Portal
Journey:
ต้องตัดสิน:
- Metering/Invoicing/Receivables/Receipts boundaries และ language
- Invoice/Credit Note relationship ภายใต้ owner-confirmed policy
- Customer/Seller master vs snapshots
- architecture ต่างกันต่อ module
- collection payment port/idempotency/unknown outcome
- receipt creation failure และ recovery
- Portal read model/freshness/partial view
- authz สำหรับ Issue/Adjust/Collect/View actions
- MySQL ownership, Redis rebuildability และ no cross-context writes
Acceptance: late usage, partial payment, customer legal-name change และ provider timeout มี owner/contract/recovery ที่ชัดโดยไม่ mutate context อื่นโดยตรง
เกณฑ์ทบทวนโจทย์สรุป
ให้ reviewers 5 บทบาทให้คะแนน 0 missing / 1 assumed / 2 evidenced:
| Lens | Evidence |
|---|---|
| Domain | glossary, invariants, policy owners, boundaries |
| Code | patterns per module, public API, import direction |
| Data | authority, transaction, concurrency, freshness, rebuild |
| Security | Principal, tenant/resource/domain policy, audit |
| Reliability | idempotency, ambiguous outcomes, retry, reconciliation |
| Evolution | ADR, metrics/signals, migration/rollback ownership |
คะแนนต่ำไม่จำเป็นต้องแก้ด้วย architecture เพิ่ม บางช่องต้องขอ policy หรือทดลอง production ให้บันทึก unknown แทนสร้างคำตอบ
รายการตรวจสอบสุดท้าย
- เริ่ม architecture จาก scenario/language/invariant
- Subdomain type แยกจาก criticality/compliance
- Bounded Context แยกจาก module/service/database
- แต่ละ module เลือก pattern ตาม forces
- Slice-based outer structure และ roles ภายในมีเหตุผล
- Vendor/protocol/persistence models หยุดที่ adapters
- AuthN, application authz, ownership และ domain policy แยกกัน
- Authoritative decision path ไม่ใช้ display cache
- Cross-boundary money flow มี stable identity และ repair loop
- Tests/fitness พิสูจน์ boundaries ที่สำคัญ
- ADR มี accepted costs และ reevaluation signals
จบคอร์ส
DDD ไม่ได้ตอบว่า folder ควรชื่ออะไร แต่มอบภาษาและ model boundaries ให้เราเลือก architecture อย่างมีเหตุผล Codebase ที่ดีจึงไม่เหมือนกันทุก module มันเริ่มเล็ก โตตาม complexity ปกป้อง external/data/security boundaries และวิวัฒน์ด้วย evidence แทน template
อ่านเพิ่มเติม
- DDD Reference — strategic/tactical pattern vocabulary
- Learning Domain-Driven Design — pattern selection และ evolution
- Building Evolutionary Architectures — incremental change และ fitness functions
- Monolith First และ Microservice Trade-Offs
- Release It! — production failure modes และ stability patterns