Applying Domain-Driven Design to Model a Payment System at Airwallex
This article explains how Airwallex uses Domain-Driven Design (DDD) to model a complex payment system, covering problem and solution spaces, bounded contexts, domain models, services, events, infrastructure, and the transition from domain concepts to microservices.
At Airwallex, the Domain-Driven Design (DDD) approach is employed to guide the modeling of complex business problems and system design for payment systems.
The blog provides a comprehensive introduction to using DDD patterns to model a payment system.
Introduction
Payment systems are intricate and ever‑changing, encompassing order handling, fraud detection, notifications, integration with various payment methods, and fund clearing and settlement.
Developers often encounter issues such as unclear boundaries and responsibilities, lack of isolation and modularity, and mixing core business logic with technical details.
Many design patterns in software engineering can address these problems; Airwallex adopts DDD to manage the complexity of its payment system.
What is DDD?
Domain‑Driven Design, introduced by Eric Evans, is a set of ideas, principles, and patterns that help design software systems based on a core domain model. DDD separates the problem space (strategic) from the solution space (tactical).
In the problem space, strategic patterns define the large‑scale structure, focusing on domains, sub‑domains, and a ubiquitous language. In the solution space, tactical patterns provide design tools such as bounded contexts, context maps, entities, aggregates, domain events, domain services, application services, and infrastructure.
Applying DDD in Practice
Scenario: a customer buys a $10 T‑shirt on a merchant’s website, pays with Visa or WeChat, receives a payment notification, and the merchant views payment details in the Airwallex Webapp.
Steps to model the payment system:
Analyze real‑world business use cases to identify domains and sub‑domains (often using Event Storming).
Define bounded contexts in the solution space.
Within each bounded context, apply tactical DDD patterns to define entities, aggregates, domain services, and events.
Use the results to determine microservices.
Problem Space
Domain: Payment System
Sub‑domain: Payment Processing – merchants accept payments via various methods.
Sub‑domain: Finance – clearing and settlement of merchant funds.
Ubiquitous Language (examples): Payment Intent – order created by merchant. Payment Attempt – transaction to accept payment for an order. Payment Method – way the customer pays. Payment Settlement – batch of payments settled to merchant wallet. Payment View – aggregated view of all data related to a payment.
Solution Space
Bounded Contexts identified:
Payment Gateway – API gateway for merchants to create or view payments.
Payment Core – manages payment intents, attempts, and method resources.
Payment Adapter – integrates external PSPs (WeChat, Alipay, Visa, Mastercard, etc.).
Payment Settlement – calculates fees and settles each payment.
Payment Fusion – aggregated view of payment details.
Context map illustration:
Domain Model
From the scenario and ubiquitous language, aggregates, entities, value objects, and domain events are identified.
Domain Services
Domain services provide stateless business logic for aggregates. For example, PaymentAttemptExecutorService encapsulates repository access, aggregate changes, and event publishing.
Domain Events
Domain events increase extensibility and avoid tight coupling. For instance, when PaymentCaptureCommand changes a payment status to captured, a PaymentAttemptCapturedEvent is emitted to notify other bounded contexts.
Infrastructure
The infrastructure layer separates core domain from technical details, often using an Anti‑Corruption Layer (ACL). Repositories define interfaces; implementations (e.g., PaymentAttemptPgRepository ) use PostgreSQL or MongoDB.
From Domain Model to Microservices
Having defined bounded contexts and their models, the next step is to map each bounded context to a microservice.
Conclusion
The blog demonstrates how DDD helps model a payment system by providing clear communication, modular boundaries, decoupled core logic, and a path to scalable microservices. Future work will explore deeper topics such as layer management, event storage, and context mapping.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.