บทที่ 5 · Part 1 — Architecture Starts with the Domain

Enterprise Fintech Landscape

สร้างแผนที่สมมติฐานของ Wallet, Checkout, Billing, Payment Integration และ Web Portal อย่างมีหลักฐาน

Enterprise Fintech Landscape

ในบริษัทเดียวกันคำว่า Product, Domain, Service และ Repository มักถูกใช้แทนกัน Wallet เป็นชื่อในหน้า website, เป็นทีม, เป็น Git repository และเป็น runtime service พร้อมกัน เมื่อวาด architecture diagram ทุกกล่องจึงดูเหมือนเป็น boundary ที่พิสูจน์แล้ว ทั้งที่บางกล่องเป็นเพียงโครงสร้างองค์กรหรือช่องทางผู้ใช้

จบบทนี้คุณจะ

แยก Product, Subdomain, Bounded Context, module, service และ datastore สร้าง landscape ของ Wallet, Checkout, Billing, Payment Integration และ Web Portal จำแนก candidate Core, Supporting และ Generic Subdomains พร้อมติดป้าย assumption/evidence และ trace journey เพื่อค้นหาคำถามแทนการประกาศ microservices ล่วงหน้า

[!IMPORTANT] วิธีอ่านหลักฐานในบทนี้ คำที่เป็น Definition/Pattern มีแหล่งต้นทางอยู่ใกล้ claim ส่วน decision table, starting structure, checklist และ lab เป็น Heuristic/Trade-off หรือ Course Convention สำหรับฝึกตัดสินใจ ไม่ใช่มาตรฐานสากล เว้นแต่บทจะระบุแหล่งและขอบเขตไว้ชัดเจน

แยกแกนการตัดสินใจ

คำ 6 คำนี้ตอบคนละคำถาม:

Termคำถามที่ตอบตัวอย่างที่ยังเป็น hypothesis
Productลูกค้าซื้อหรือใช้อะไรWallet, Checkout, Billing
Subdomainธุรกิจต้องแก้ปัญหาส่วนใดpricing, ledger, invoicing
Bounded Contextmodel/language ใดสอดคล้องภายในWallet Accounting
Modulecode ส่วนใดมี public boundaryinvoicing package
Serviceอะไร deploy/operate แยกbilling-api process
Datastorestate ถูกเก็บที่ไหนMySQL schema, Redis cache

ความสัมพันธ์ไม่ใช่หนึ่งต่อหนึ่ง Product หนึ่งมีหลาย Subdomain/Context ได้ Context หนึ่ง อาจมีหลาย module และช่วงแรกหลาย Context อาจ deploy ใน service เดียวได้ Repository หนึ่งก็อาจ build หลาย binary โดยยังรักษา module boundary

หาก diagram มีเส้น Wallet → Billing ให้ถามต่อว่าเป็น command, event, query, shared table หรือแค่ทีมคุยกัน ลูกศรที่ไม่บอก semantic contract ยังใช้ตัดสิน ownership ไม่ได้

ภาพรวม Product ที่ยังเป็นสมมติฐาน

เริ่มด้วย 5 พื้นที่ที่ผู้ใช้กำหนด แต่ติดป้ายว่าเป็น discovery containers:

Wallet

อาจมี account lifecycle, ledger, balance availability, transfer และ top-up posting คำถามหลักคือ Wallet รับรองข้อเท็จจริงอะไรและใครมีสิทธิ์เปลี่ยน financial state

Checkout

อาจเป็นเจ้าของ checkout session, payment attempt, customer choice และสถานะที่ merchant เห็น แต่ไม่ควรคัดลอก provider lifecycle มาเป็น domain model โดยตรง

Billing

อาจประกอบด้วย subscription, meter usage, invoicing, credit note, receivable, receipt, tax และ seller/customer snapshots รายชื่อเหล่านี้ยังไม่บอกว่าควรเป็น context/module ใด

Payment Integration

อาจเป็นเพียง adapters ต่อ provider หรือเป็น capability ด้าน routing, credential, reconciliation และ provider operations ถ้ามี policy ของตัวเองอาจมี model boundary มากกว่า utility package แต่ไม่ควรเป็นเจ้าของทุก business payment rule

Web Portal

เริ่มจาก hypothesis ว่าเป็น channel/BFF/read composition ซึ่งเรียก use cases ของ context เจ้าของ หากภายหลังพบ workflow, language และ invariant เฉพาะ Portal จึงค่อยประเมินว่า มี domain capability ของตัวเองหรือไม่

ตัวอย่าง Subdomain Portfolio

ในศัพท์ของ DDD การจำแนก Core, Supporting และ Generic ใช้กับ Subdomain ไม่ใช่ Product, service หรือ repository ทั้งก้อน ส่วนคำว่า Core Domain ใช้พูดถึงพื้นที่เชิงกลยุทธ์ ที่องค์กรต้องให้ความสำคัญ การเขียนว่า “Wallet คือ Core Domain” จึงยังไม่พอสำหรับตัดสิน code architecture เพราะ Wallet product อาจรวม Subdomain ทั้ง 3 ชนิดไว้ด้วยกัน

ลองสมมติบริษัท Fintech ชื่อ AcmePay ซึ่งประกาศ strategy ที่ตรวจสอบได้ 3 ข้อ:

  1. เพิ่ม payment acceptance ด้วยการเลือก provider และ recovery ที่ดีกว่าคู่แข่ง
  2. ทำให้ merchant ใช้และเคลื่อนย้ายยอดเงินได้อย่างถูกต้องและรวดเร็ว
  3. รองรับ usage-based pricing ที่ปรับตามสัญญาของลูกค้าองค์กรได้เร็ว

ภายใต้ strategy นี้ ทีมอาจตั้ง candidate classification รอบแรกดังนี้:

ภาพนี้เป็น portfolio view ตาม strategy ปัจจุบันของ AcmePay ไม่ใช่ dependency diagram กล่องภายในแต่ละกลุ่มจึงไม่ได้แสดงลำดับหรือ dependency ส่วนตารางด้านล่างเก็บเหตุผล และเงื่อนไขทบทวนของแต่ละ candidate ไว้ให้ตรวจสอบได้

Product areaCandidate SubdomainCandidate typeเหตุผลและเงื่อนไขทบทวน
WalletAvailable Balance and Reservation PolicyCoreเป็นคำมั่นที่กระทบวิธีใช้เงินและประสบการณ์ merchant; ทบทวนถ้าบริษัทใช้ ledger product ซึ่งกำหนด policy ให้ทั้งหมด
WalletWallet Account LifecycleSupportingต้องมีกฎเฉพาะองค์กรเพื่อเปิด ระงับ และปิดบัญชี แต่ยังไม่มีหลักฐานว่าใช้สร้างความต่าง
WalletNotification DeliveryGenericตลาดมีบริการส่ง email/SMS/push; template และ consent อาจยังเป็น Supporting ตามข้อกำหนดขององค์กร
CheckoutPayment Attempt and Routing PolicyCoreเชื่อมโดยตรงกับ acceptance, cost และ recovery strategy ที่บริษัทเลือกแข่งขัน
CheckoutCheckout Session LifecycleSupportingจำเป็นต่อ product และมี state เฉพาะ แต่ตัวอย่างนี้ยังไม่มี evidence ว่า session model สร้างความได้เปรียบ
Payment IntegrationProvider ConnectivitySupportingต้องแปล request, response, webhook และ failure ของ provider ให้เป็นภาษาภายใน แต่การเรียก API อย่างเดียวไม่ใช่จุดแข่งขัน
BillingUsage Rating and Contract PricingCoreรองรับ pricing เฉพาะลูกค้าองค์กรและเปลี่ยนตาม commercial strategy
BillingInvoicing, Receivables and Credit NotesSupportingจำเป็นและมีกฎเฉพาะบริษัท แต่ strategy สมมติแข่งขันที่ rating/pricing ไม่ใช่รูปแบบเอกสาร
BillingTax CalculationGeneric candidateเริ่มจากประเมิน product ภายนอกก่อน; เปลี่ยนเป็น Supporting ได้หากตลาด/สัญญาทำให้ต้องมี model เฉพาะ
Web PortalOperations Case ManagementSupporting candidateถ้ามี workflow ตรวจเอกสาร อนุมัติ และแก้ exception จริง มันคือ business capability ไม่ใช่แค่หน้าจอ
Cross-productIdentity and AuthenticationGeneric candidateใช้มาตรฐานและ identity provider ได้ แต่ tenant mapping และ use-case authorization ยังต้องอยู่กับ context เจ้าของกฎ

คำว่า candidate สำคัญ เพราะตารางนี้เกิดจาก strategy สมมติ ไม่ใช่ taxonomy สากลของ Fintech ตัวอย่างเช่น Reconciliation มี operational criticality สูงมาก แต่อาจเป็น Supporting ถ้าไม่ได้สร้างความแตกต่าง ขณะเดียวกัน routing algorithm ที่มีโค้ดไม่มากอาจเป็น Core เพราะมันเปลี่ยน conversion และ cost ที่บริษัทแข่งขันโดยตรง

Generic ไม่ได้แปลว่าความเสี่ยงต่ำ

Identity, tax และ notification อาจเป็น Generic ในเชิง strategic differentiation แต่ยัง ต้องมี owner, security control, availability target, data classification และ compliance evidence ที่เหมาะสม ข้อกำหนดเหล่านี้ต้องมาจากเจ้าของที่รับผิดชอบ พร้อมชื่อและวันที่

Product เดิมเมื่อกลยุทธ์เปลี่ยน

หาก AcmePay เปลี่ยนจาก payment platform เป็น Billing SaaS ที่แข่งขันด้วยการออก invoice, credit note และ revenue workflow ข้ามประเทศ classification ก็เปลี่ยนได้:

StrategyCore candidatesSupporting candidatesGeneric candidates
Wallet-led Fintechbalance availability, transfer policycheckout session, provider connectivitynotification, identity integration
Payment Orchestratorprovider routing, recovery policycheckout session, reconciliation operationsnotification, document rendering
Billing SaaScontract pricing, invoicing workflow, revenue operationspayment collection, portal case managementidentity integration, commodity delivery channels

ดังนั้น landscape review ต้องถามว่า “เราแข่งขันด้วย capability ใดในช่วงเวลานี้” ก่อนถาม ว่า “ระบบนี้ชื่ออะไร” และบันทึก evidence, business owner, วันที่ และ trigger สำหรับทบทวน เสมอ การเปลี่ยน classification ไม่ได้บังคับให้ย้าย service ทันที แต่เป็นสัญญาณให้ทบทวน ระดับการลงทุนใน domain discovery, modelling, testing และความรู้ที่ต้องรักษาไว้ภายใน

ใส่หลักฐานก่อนวาดกล่อง

ให้ทุกกล่องมี evidence label:

  • Observed — มี scenario, language, owner หรือ runtime fact ยืนยัน
  • Proposed — boundary ที่ทีมเสนอและมีเหตุผล แต่ยังไม่ได้ทดสอบครบ
  • Unknown — คำถามสำคัญยังไม่มี owner/ข้อมูล
  • Legacy — เป็น constraint ปัจจุบัน ไม่ถือเป็น target domain boundary

ตัวอย่าง billing-service ที่มี invoice, tax, email และ portal query ใน process เดียว เป็น observed deployment fact แต่ไม่ได้ยืนยันว่าเป็น Bounded Context เดียว

แผนที่รอบแรกอาจเป็น:

ลูกศรทุกเส้นในรอบแรกต้องมี question log เช่น Billing ขอเก็บเงินด้วย CollectInvoice หรือสร้าง Checkout Session? Wallet รับ CreditWallet command หรือ subscribe PaymentConfirmed? Portal query ผ่าน API เจ้าของหรือ join database?

ไล่ 2 เส้นทางธุรกิจ

Journey ทำให้ ownership gap ปรากฏชัดกว่า context diagram

Wallet top-up

  1. Customer เริ่ม top-up ผ่าน channel
  2. Checkout สร้าง attempt และ Payment Integration เรียก provider
  3. Provider outcome ถูกแปลเป็น application language
  4. Wallet บันทึก credit โดย deduplicate business reference
  5. Reconciliation หา ambiguous/incomplete operation

Billing collection

  1. Metering สรุป usage ตาม contract
  2. Invoicing ออก Invoice และอาจออก Credit Note ภายหลัง
  3. Receivables ติดตามยอดค้างและขอ collect
  4. Payment capability ดำเนินการเรียกเก็บ
  5. Receipt ถูกออกจากหลักฐานการรับชำระ
  6. Portal แสดง composed view โดยไม่เป็นเจ้าของสถานะเหล่านั้น

Display journey ไม่ใช่ decision journey

Portal หรือ Redis read model อาจรวมข้อมูลหลาย context สำหรับหน้าจอ แต่การอนุมัติ Refund, Transfer หรือ Collection ต้องส่ง command ไปยัง context เจ้าของกฎ และให้ context นั้นอ่าน authoritative state ของตน อย่านำค่าที่ compose เพื่อ display ไปตัดสินเงิน

แบบฝึกปฏิบัติ: แผนที่พร้อมข้อสมมติ

สร้างแผนที่ 2 ชั้น ชั้นแรกเป็น Product/Channel ชั้นที่ 2 เป็น candidate contexts จากนั้นแนบ registry ต่อกล่อง:

Name and level: Product | Context candidate | Module | Service | Datastore
Status: Observed | Proposed | Unknown | Legacy
Candidate subdomain type: Core | Supporting | Generic | Unknown | Not applicable
Strategic evidence and review date:
Owned language and decisions:
Business and engineering owner:
Public commands/events/queries:
Authoritative data:
Dependencies and translations:
Evidence:
Questions and review date:

ห้ามวาด database ก่อนระบุ owner ของ data และห้ามใช้ repository name เป็น evidence ให้ trace อย่างน้อย 1 happy path กับ 1 ambiguous failure ผ่านทุกกล่อง

คะแนนแบบฝึกหัด:

  • ผ่าน เมื่อทุกกล่องระบุ level และ status
  • ดี เมื่อแตก Product เป็น candidate Subdomains, classification มี strategic evidence และ journey เปิดเผย contract/ownership gap พร้อม owner
  • ควรทำใหม่ เมื่อ Product = Context = Service = Database แบบหนึ่งต่อหนึ่งทั้งหมด

รายการตรวจสอบ

  • Product, Context, module, service และ datastore ถูกแยกเป็นคนละระดับ
  • Core/Supporting/Generic ถูกใช้กับ Subdomain ไม่ใช่ติดป้าย Product ทั้งก้อน
  • Candidate classification อ้าง strategy, owner, วันที่ และเงื่อนไขทบทวน
  • Core classification ถูกแยกจาก operational criticality และ compliance impact
  • Wallet/Checkout/Billing เป็น hypothesis ไม่ใช่ universal Fintech map
  • Payment Integration ระบุว่าเป็น adapter capability หรือมี policy ใดจริง
  • Portal เริ่มเป็น channel และไม่ยึด ownership จาก context อื่น
  • ลูกศรมี semantic contract หรือ question log
  • Journey มี ambiguous failure และ reconciliation owner
  • Display state ถูกแยกจาก authoritative decision state

สรุปบทนี้

Enterprise landscape ที่ดีไม่ได้ดูสวยเพราะมีกล่องเยอะ แต่ทำให้รู้ว่าแต่ละกล่องอยู่ ระดับใด Subdomain ใดเป็น Core, Supporting หรือ Generic ตาม strategy มีหลักฐานอะไร และคำถามใดยังเปิดอยู่ แผนที่นี้เป็น input ให้เลือก code architecture ราย module ใน Part ถัดไป ไม่ใช่คำสั่งให้สร้าง microservice ตามรูป

อ่านเพิ่มเติม