Architectural Patterns
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages. |
Welcome to the Architectural Patterns reference. This section applies domain-driven design (DDD) to microservice architectures: it shows how to structure a single service’s code around its domain model, and, above all, why the data-consistency toolbox a monolith takes for granted — one ACID transaction spanning everything it touches — stops working the moment every service owns its own database. From there it builds up, pattern by pattern, the toolbox that replaces it: sagas coordinating local transactions with compensations, domain events as the currency those sagas exchange, the transactional outbox and listen-to-yourself patterns for publishing those events reliably, CQRS for the queries a decomposed data model can no longer answer directly, and event sourcing as an alternative persistence model built entirely out of events. The tactical DDD building blocks — entities, value objects, aggregates, repositories, factories and domain services — are what make "one transaction, one aggregate" possible in the first place, so this section covers them in depth too. Deciding whether to split a system into services in the first place, and the strangler-style migration that gets you there, was previously left out of scope here; that material now lives in the Architecture Decisions and Migration Paths reference, the other half of the Architecture reference.
Every code example in this section shares one running domain — an e-commerce Order / Inventory / Payment / Shipping set of bounded contexts — and is written and verified against Java 21, Spring Boot 4.1.x (Spring Framework 7.0.x), Spring Data JPA, Spring Modulith 2.x and Spring for Apache Kafka 4.1.x. The domain model itself stays plain Java — records, sealed interfaces, no framework — and Spring only appears in the application and infrastructure layers.
If you are new to this section, read Strategic Design for Microservices first, then Structuring a DDD Microservice’s Code, then the tactical building blocks — Entities, Value Objects, Aggregates and Repositories, Factories, and Domain Services — before moving on to Why Distributed Transactions Don’t Work Across Microservices, Sagas, Domain Events and Event Storming, then The Transactional Outbox Pattern and Listen to Yourself, CQRS and Event Sourcing, and finally Putting It All Together: The Place Order Flow, which assembles every prior page’s code into one coherent flow.
This section complements, rather than duplicates, four existing references. The SpringBoot Reference’s Architectural Patterns page gives a shorter, introductory tour of the same vocabulary — hexagonal architecture, the outbox, listen-to-yourself, a saga diagram — and now points here for the deeper treatment; its SpringBoot Reference landing page is the place for the Spring Data repository and JPA-mapping mechanics this section assumes rather than re-explains. The Messaging Reference’s Messaging Patterns in Practice documents the same outbox, saga and event-sourcing/CQRS patterns from the broker side — Kafka topics, RabbitMQ exchanges, log compaction — and its Kafka Connect page is the reference for the Debezium-based transaction-log-tailing option this section’s outbox page links to rather than repeats. The Quarkus Reference’s Datasources and Transactions page covers Narayana LRA as the Quarkus-native realization of saga compensation. And Choosing the Right Database covers CQRS from the storage-selection angle — polyglot persistence and CDC pipelines — which this section’s CQRS page complements with the command/query model split, view design and query services.
What’s covered
Foundations
-
Strategic Design for Microservices — domains and subdomains, the ubiquitous language, the bounded context as the unit that owns both a model and a database, the context map’s relationship patterns, and the three integration styles between contexts.
-
Structuring a DDD Microservice’s Code — transaction script vs. domain model, application services as the transaction boundary, inbound/outbound adapters, and the Maven module and Java package layout the running example follows throughout this section.
Tactical building blocks
-
Entities — identity over attributes, rich behavior instead of getters/setters, a state-machine view of
OrderStatus, and JPA mapping of a typed identifier. -
Value Objects — value objects defined by the absence of identity, equality by attributes, immutability, self-validation, when to promote a primitive to a value object, and their JPA persistence as
@Embeddable,@ElementCollection, or JSON columns. -
Aggregates — the tactical DDD building block that ties entities and value objects to a transactional consistency boundary — fuzzy boundaries, Richardson’s and Vernon’s rules, granularity trade-offs, optimistic locking, and eventual consistency between aggregates.
-
Repositories, Factories, and Domain Services — the collection-like Repository port and its Spring Data JPA adapter, static-factory vs. dedicated-factory construction, domain services vs. application-service orchestration, and modules as the coarsest-grained building block.
Consistency across services
-
Why Distributed Transactions Don’t Work Across Microservices — why the ACID transaction a monolith takes for granted stops at the service boundary — two-phase commit’s mechanics and real failure modes, the availability-product and CAP-theorem arguments against it, and the three strategies that replace it in practice.
-
Sagas — message-driven sequences of local transactions coordinating the Place Order Saga across bounded contexts — compensating transactions, choreography vs. orchestration, the ACD lack of isolation and its countermeasures.
-
Domain Events — past-tense facts about an aggregate — naming, the envelope and its metadata, minimal vs. enriched payloads, how the aggregate hands events off, in-process and out-of-process consumption, and event versioning.
-
Event Storming — the collaborative workshop that discovers domain events, commands, and aggregates before any code is written, and how the running domain’s own board maps onto the pages this section already covers.
-
The Transactional Outbox Pattern — how a service publishes a domain event reliably in the same local transaction as the state change it describes — the dual-write problem, the outbox table, polling publishers vs. transaction-log tailing, Spring Modulith’s event publication registry, and idempotent consumers on the receiving end.
-
Listen to Yourself — publishing a domain event before applying it to the publisher’s own database, and consuming that same event as the one code path that updates local state, contrasted with the transactional outbox and event sourcing.
-
CQRS — why cross-service queries need a different answer than the write model, the command side vs. query side split, designing a view module, idempotent projections, replication lag, and the canonical
OrderHistoryViewread model. -
Event Sourcing — the trouble with state-based persistence, the append-only event store, reconstituting state by replay, snapshots and evolving events, and the canonical
EventSourcedOrderdecide/apply split.
Putting it all together
-
Putting It All Together: The Place Order Flow — assembles every pattern in this section into one worked example — the happy path and the payment-failure path through the Place Order Saga, end to end from an HTTP request to the CQRS read model, plus a checklist of what to test at each layer.
Reference
-
Architectural Patterns Cheat Sheet — a one-page, printable summary of the whole section, with a downloadable PDF.
Bibliography
-
Pattern catalogues and canonical articles (primary online source for each page) — database per service, the saga pattern, transactional outbox, polling publisher, transaction log tailing, domain event, aggregate, CQRS and event sourcing on Chris Richardson’s microservices.io pattern catalogue, plus the idempotent consumer pattern; Martin Fowler’s Bounded Context, DDD_Aggregate, ValueObject, DomainEvent, CQRS and EventSourcing bliki entries; Eric Evans / Domain Language’s DDD portal and the free DDD Reference; Microsoft Learn’s Saga distributed transactions pattern, Compensating Transaction pattern, CQRS pattern, Event Sourcing pattern and the .NET microservices: DDD/CQRS guide (and its domain-model and domain-events-design-implementation pages); Oded Shopen’s Listen to Yourself: A Design Pattern for Event-Driven Microservices and Confluent Developer’s Designing Event-Driven Microservices — The Listen to Yourself Pattern for the listen-to-yourself pattern, which is not covered by any of the four consulted books; Alberto Brandolini’s eventstorming.com for event storming; and the foundational papers the books lean on — Garcia-Molina & Salem’s Sagas (SIGMOD 1987), Frank & Zahle’s Semantic ACID properties in multidatabases using remote procedure calls and update propagations (1998, ACM Digital Library) as the source of the saga countermeasures, Gregor Hohpe’s Starbucks Does Not Use Two-Phase Commit, X/Open XA and the CAP theorem.
-
Framework documentation (primary source for every code example) — Spring Data domain events from aggregate roots (
@DomainEvents/@AfterDomainEventPublication,AbstractAggregateRoot) and the Spring Data JPA reference; the Spring Framework transaction reference; Spring Modulith’s application events and event publication registry; the Spring for Apache Kafka 4.1 reference (linked only — the Messaging Reference is the primary reference for it); the Debezium outbox event router; Eventuate (Tram sagas, outbox, event sourcing), Axon Framework (aggregates, event sourcing, CQRS, sagas), Temporal and Camunda (durable workflow/BPM engines usable as saga orchestrators), and Narayana LRA via the existing Quarkus Datasources and Transactions page; and the Java 21 language reference (records, sealed interfaces, pattern matching forswitch). -
Consulted reference books (bibliography only — the concept narrative, never the primary source for any code example):
-
Richardson, Chris. Microservices Patterns: With Examples in Java. Manning, 2019. ISBN 978-1-61729-454-9 — publisher page. The primary narrative source for the distributed-transactions, saga, domain-event, outbox, CQRS and event-sourcing pages and for the aggregate rules; its Eventuate-framework and Spring Boot 2 / Java 8-era code is not reused. Chapters 1, 2, 8, 12 and 13 are also the narrative source for the sibling Architecture Decisions and Migration Paths section.
-
Golding, Tod. Building Multi-Tenant SaaS Architectures: Principles, Practices, and Patterns Using AWS. O’Reilly Media, 1st edition, May 2024. ISBN 978-1-098-14064-9 — publisher page, Amazon page, and the free AWS SaaS Architecture Fundamentals whitepaper by the same author. The source of the multi-tenancy angle shared with the Hibernate multitenancy page and the new SaaS migration page.
-
Brown, Kyle; Woolf, Bobby; Yoder, Joseph. Cloud Application Architecture Patterns: Designing, Building, and Modernizing for the Cloud. O’Reilly Media, 1st ed., April 2025. ISBN 978-1-098-11690-3 — publisher page. The cloud-native framing — self-managed data stores, service orchestrator, event-driven architecture, aggregate, repositories, domain service, CQRS, event sourcing.
-
Avram, Abel; Marinescu, Floyd. Domain-Driven Design Quickly. InfoQ / C4Media, 2006. ISBN 978-1-4116-0925-9 — free download from InfoQ. The Evans-faithful definitions of entities, value objects, services, modules, aggregates, factories, repositories and the strategic patterns.
-
Vernon, Vaughn. Domain-Driven Design Distilled. Addison-Wesley Professional, 2016. ISBN 978-0-13-443442-1 — publisher page for the original English edition; also distributed as the Spanish translation Domain-Driven Design Destilado (Carlos Buenosvinos, Leonardo Cano and Nicole Andrade, technical review Yuji Kiriki), free from the author’s company at Kalele. The four aggregate rules, eventual consistency between aggregates via domain events, domain-event design, event sourcing and event storming.
-
Also cited as further reading because the four books above lean on them: Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003 — domainlanguage.com; and Vernon, Vaughn. Implementing Domain-Driven Design. Addison-Wesley, 2013 — publisher page.
-
The books above are consulted references only, never the primary source for any code example: on any discrepancy, the pattern authors' current online catalogues — microservices.io, the Fowler bliki, the Domain Language DDD Reference — and the Spring / Java framework documentation are authoritative, and every code example in this section is verified against them at implementation time.