developing functional domain models with event sourcing qconny
TRANSCRIPT
![Page 1: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/1.jpg)
@crichardson
Developing functional domain models with event sourcingChris Richardson
Author of POJOs in Action Founder of the original CloudFoundry.com
@crichardson [email protected] http://plainoldobjects.com http://microservices.io
![Page 2: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/2.jpg)
@crichardson
Presentation goal
How to develop functional domain models based on event
sourcing
![Page 3: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/3.jpg)
@crichardson
About Chris
Consultant & Founder of Eventuate.IO
![Page 4: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/4.jpg)
@crichardson
For more information
http://microservices.io http://github.com/cer/microservices-examples/ https://github.com/cer/event-sourcing-examples http://plainoldobjects.com/ https://twitter.com/crichardson http://eventuate.io/
![Page 5: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/5.jpg)
@crichardson
Agenda
Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing
![Page 6: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/6.jpg)
@crichardson
Tomcat
Traditional monolithic architecture
Browser/Client
WAR/EAR
RDBMS
Customers
Accounts
Transfers
Banking UI
develop test
deploy
Simple
Load balancer
scale
Spring MVC
Spring Hibernate
...
HTMLREST/JSON
ACID
![Page 7: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/7.jpg)
@crichardson
But large and/or complex monolithic applications
= Trouble!
![Page 8: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/8.jpg)
@crichardson
Using a single RDBMS has its limitations
![Page 9: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/9.jpg)
@crichardson
Apply the scale cube
X axis - horizontal duplication
Z axis
- data
partit
ioning
Y axis - functional
decomposition
Scale b
y split
ting s
imilar
thing
s
Scale by splitting
different things
![Page 10: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/10.jpg)
@crichardson
Today: use a microservice, polyglot architecture
Banking UI
Account Management Service MoneyTransfer Management Service
Account Database MoneyTransfer Database
Standalone services
Sharded SQLNoSQL DB
![Page 11: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/11.jpg)
@crichardson
But now we have distributed data management
problems
![Page 12: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/12.jpg)
@crichardson
Example: Money transfer
Account Management Service
MoneyTransfer Management Service
Account Database
MoneyTransfer Database
Account #1 Money Transfer
Account #2
No 2PC
No ACID
NoSQL SQL
![Page 13: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/13.jpg)
@crichardson
Use an event-driven architecture
Services publish events when state changes Services subscribe to events and update their state
Maintain eventual consistency across multiple aggregates (in multiple datastores) Synchronize replicated data
![Page 14: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/14.jpg)
@crichardson
MoneyTransferServiceMoneyTransfer
fromAccountId = 101 toAccountId = 202 amount = 55 state = INITIAL
MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = DEBITED
MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = COMPLETED
Eventually consistent money transfer
Message Bus
AccountService
transferMoney()
Publishes:Subscribes to:
Subscribes to:
publishes:
MoneyTransferCreatedEvent
AccountDebitedEvent
DebitRecordedEvent
AccountCreditedEventMoneyTransferCreatedEvent
DebitRecordedEvent
AccountDebitedEventAccountCreditedEvent
Account id = 101 balance = 250
Account id = 202 balance = 125
Account id = 101 balance = 195
Account id = 202 balance = 180
![Page 15: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/15.jpg)
@crichardson
How to atomically
update the database and
publish an event without 2PC?
(dual write problem)
![Page 16: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/16.jpg)
@crichardson
Event sourcing
For each aggregate: Identify (state-changing) domain events Define Event classes
For example, Account: AccountOpenedEvent, AccountDebitedEvent, AccountCreditedEvent ShoppingCart: ItemAddedEvent, ItemRemovedEvent, OrderPlacedEvent
![Page 17: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/17.jpg)
@crichardson
Persists events NOT current state
Account
balance
open(initial) debit(amount) credit(amount)
AccountOpened
Event table
AccountCredited
AccountDebited
101 450
Account tableX101
101
101
901
902
903
500
250
300
![Page 18: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/18.jpg)
@crichardson
Replay events to recreate state
Account
balance
AccountOpenedEvent(balance) AccountDebitedEvent(amount) AccountCreditedEvent(amount)
Events
![Page 19: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/19.jpg)
@crichardson
Before: update state + publish events
Two actions that must be atomic
Single action that can be done atomically
Now: persist (and publish) events
![Page 20: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/20.jpg)
@crichardson
Optimizing using snapshots
Most aggregates have relatively few events BUT consider a 10-year old Account ⇒ many transactions
Therefore, use snapshots: Periodically save snapshot of aggregate state Typically serialize a memento of the aggregate Load latest snapshot + subsequent events
![Page 21: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/21.jpg)
@crichardson
Request handling in an event-sourced application
HTTP Handler
Event Store
pastEvents = findEvents(entityId)
Account
new()
applyEvents(pastEvents)
newEvents = processCmd(SomeCmd)
saveEvents(newEvents)
Microservice A
(optimistic locking)
![Page 22: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/22.jpg)
@crichardson
Event Store publishes events - consumed by other services
Event Store
Event Subscriber
subscribe(EventTypes)
publish(event)
publish(event)
Aggregate
NoSQL materialized
view
update()
update()
Microservice B
![Page 23: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/23.jpg)
@crichardson
About the event storeHybrid database and message broker
Retrieve events for an aggregate Append to an aggregates events Subscribe to events
Event store implementations: Home-grown/DIY geteventstore.com by Greg Young My event store - bit.ly/trialeventuate
![Page 24: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/24.jpg)
@crichardson
Business benefits of event sourcing
Built-in, reliable audit log Enables temporal queries Publishes events needed by big data/predictive analytics etc. Preserved history ⇒ More easily implement future requirements
![Page 25: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/25.jpg)
@crichardson
Technical benefits of event sourcing
Solves data consistency issues in a Microservice/NoSQL-based architecture:
Atomically save and publish events Event subscribers update other aggregates ensuring eventual consistency Event subscribers update materialized views in SQL and NoSQL databases (more on that later)
Eliminates O/R mapping problem
![Page 26: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/26.jpg)
@crichardson
Drawbacks of event sourcing
Weird and unfamiliar Events = a historical record of your bad design decisions Handling duplicate events can be tricky Application must handle eventually consistent data Event store only directly supports PK-based lookup (more on that later)
![Page 27: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/27.jpg)
@crichardson
Agenda
Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing
![Page 28: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/28.jpg)
@crichardson
Use the familiar building blocks of DDD
Entity Value object Services Repositories Aggregates
With some differences
![Page 29: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/29.jpg)
@crichardson
Partition the domain model
into Aggregates
![Page 30: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/30.jpg)
Aggregate design
Graph consisting of a root entity and one or more other entities and value objects Each core business entity = Aggregate: e.g. customer, Account, Order, Product, …. Reference other aggregate roots via primary key Often contains partial copy of other aggregates’ data
Order
OrderLine Item
quantity productId productName productPrice
customerId
Address
street city …
![Page 31: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/31.jpg)
@crichardson
Aggregate granularity is important
Transaction = processing one command by one aggregate No opportunity to update multiple aggregates within a transaction If an update must be atomic (i.e. no compensating transaction) then it must be handled by a single aggregate
e.g. scanning boarding pass at security checkpoint or when entering jetway
![Page 32: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/32.jpg)
@crichardson
Aggregate granularity
Forum
Post
User
moderator
author
Forum
Post
User
moderator
author
Forum
Post
User
moderator
author
Consistency Scalability/ User experience
![Page 33: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/33.jpg)
@crichardson
ES-based Aggregate designclass Account { var balance : Money;
def debit(amount : Money) { balance = balance - amount } }
case class Account(balance : Money) {
def processCommand(cmd : Command) : Seq[Event] = ???
def applyEvent(event : Event) : Account = …
}
case class DebitCommand(amount : Money) case class AccountDebitedEvent(amount : Money)
Classic, mutable
domain model
Event centric, immutable
![Page 34: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/34.jpg)
Designing domain eventsRecord state changes for an aggregate Part of the public API of the domain model ProductAddedToCart
id : TimeUUID productId productName productPrice shoppingCartId
Required by aggregate
Enrichment: Used by consumers
![Page 35: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/35.jpg)
@crichardson
Designing commands
Created by a service from incoming request Processed by an aggregate Immutable Contains value objects for
Validating request Creating event Auditing user activity
![Page 36: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/36.jpg)
@crichardson
Events and Commands
![Page 37: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/37.jpg)
@crichardson
Hybrid OO/FP domain objects
![Page 38: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/38.jpg)
@crichardson
OO = State + Behavior
balance
Account
processCommand(cmd : Command) : Seq[Events]
applyEvent(event : Event) : Account
State
Behavior
![Page 39: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/39.jpg)
@crichardson
Aggregate traits
Map Command to Events
Apply event returning updated Aggregate
Used by Event Store to reconstitute aggregate
![Page 40: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/40.jpg)
@crichardson
Account - command processing
Prevent overdraft
![Page 41: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/41.jpg)
@crichardson
Account - applying events
Immutable
![Page 42: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/42.jpg)
@crichardson
Event Store API
trait EventStore {
def save[T <: Aggregate[T]](entity: T, events: Seq[Event], assignedId : Option[EntityId] = None): Future[EntityWithIdAndVersion[T]]
def update[T <: Aggregate[T]](entityIdAndVersion : EntityIdAndVersion, entity: T, events: Seq[Event]): Future[EntityWithIdAndVersion[T]]
def find[T <: Aggregate[T] : ClassTag](entityId: EntityId) : Future[EntityWithIdAndVersion[T]]
def findOptional[T <: Aggregate[T] : ClassTag](entityId: EntityId) Future[Option[EntityWithIdAndVersion[T]]]
def subscribe(subscriptionId: SubscriptionId): Future[AcknowledgableEventStream] }
![Page 43: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/43.jpg)
@crichardson
FP-style domain objects
![Page 44: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/44.jpg)
@crichardson
FP = Separation of State and Behavior
Account
balance
AccountAggregate
processCommand(Account, Command) : Seq[Events]
applyEvent(Account, Event) : Account
StateBehavior
![Page 45: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/45.jpg)
@crichardson
Aggregate type classes/implicits
Used by Event Store to reconstitute aggregate
![Page 46: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/46.jpg)
@crichardson
Functional-style Account Aggregate
State Behavior
![Page 47: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/47.jpg)
@crichardson
Functional-style Account Aggregate
Behavior
![Page 48: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/48.jpg)
@crichardson
FP-style event storeEnables inference of
T, and EV
Tells ES how to instantiate aggregate and apply events
= Strategy
![Page 49: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/49.jpg)
@crichardson
Haskell aggregate
https://gist.github.com/Fristi/7327904
![Page 50: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/50.jpg)
@crichardson
Haskell TicTacToe aggregate
![Page 51: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/51.jpg)
@crichardson
JavaScript aggregate
![Page 52: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/52.jpg)
@crichardson
Agenda
Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing
![Page 53: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/53.jpg)
@crichardson
Designing servicesResponsibilities and collaborations
Invoked by adapter, e.g. HTTP controller Creates a Command Selects new aggregate or existing aggregate to process command
Load aggregate from same bounded context, e.g. Add a Post to a Forum - load forum Load data from another other bounded context, e.g. addProductToCart()
Requests ProductInfo from ProductService Invokes PricingService to calculate discount price
Sometimes loads target aggregate before creating command e.g. addProductToCart() needs contents of shopping cart to calculate discounted price of product to add
![Page 54: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/54.jpg)
@crichardson
Money transfer example
As a customer of the bank I want to transfer money between two bank accounts So that I don't have to write a check
Given that my open savings account balance is $150 Given that my open checking account balance is $10 When I transfer $50 from my savings account to my checking account Then my savings account balance is $100 Then my checking account balance is $60 Then a MoneyTransfer was created
Story
Scenario
Post conditions
Pre conditions
![Page 55: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/55.jpg)
@crichardson
Old-style ACID…public class MoneyTransferServiceImpl …{
private final AccountRepository accountRepository; private final MoneyTransferRepository moneyTransferRepository; … @Transactional public MoneyTransfer transfer( String fromAccountId, String toAccountId, double amount) throws MoneyTransferException { Account fromAccount = accountRepository.findAccount(fromAccountId); Account toAccount = accountRepository.findAccount(toAccountId); // … Verify accounts are open … fromAccount.debit(amount); toAccount.credit(amount); return moneyTransferRepository.createMoneyTransfer( fromAccount, toAccount, amount); } }
![Page 56: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/56.jpg)
… becomes eventually consistent (BASE)
Updating multiple aggregates multi-step, event-driven flow each step updates one Aggregate
Service creates saga to coordinate workflow
A state machine Part of the domain, e.g. MoneyTransfer aggregate OR Synthetic aggregate
Post-conditions eventually true
MoneyTransfer
From Account
To Account
createddebited debit
recorded
credited
public MoneyTransfer transfer() { … Creates MoneyTransfer … }
![Page 57: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/57.jpg)
@crichardson
Need compensating transactions
Pre-conditions might be false when attempting to update an aggregate For example: an account might be closed transferring money:
from account when debiting ⇒ stop transfer
to account ⇒ reverse the debit
from account when attempting reversal ⇒ bank wins!
![Page 58: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/58.jpg)
@crichardson
MoneyTransferService Remoting proxy
DSL concisely specifies: 1.Creates Account aggregate 2.Processes command 3.Applies events 4.Persists events
![Page 59: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/59.jpg)
@crichardson
Event handling in Account
1.Load Account aggregate 2.Processes command 3.Applies events 4.Persists events
Durable subscription nameTriggers BeanPostProcessor
![Page 60: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/60.jpg)
@crichardson
JavaScript service
![Page 61: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/61.jpg)
@crichardson
Agenda
Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing
![Page 62: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/62.jpg)
@crichardson
Event Store only supports PK-based lookup Therefore….
![Page 63: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/63.jpg)
@crichardson
ES+CQRS-based microservices architecture
Event Store
Command-side
Updates
Events
Query-side
Queries
(Denormalized) View
Events
Aggregate
![Page 64: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/64.jpg)
@crichardson
Modular domain model
Forum
Post
User
moderator
author
Forum
Post
User
moderator
author
Tightly coupled ACID
Loosely coupled aggregates Eventually consistent
![Page 65: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/65.jpg)
@crichardson
MonolithicFirst approach
Tomcat
WAR/EAR
Forum
Post
User
moderator
author
Not entirely free though - Event Sourcing premium
![Page 66: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/66.jpg)
@crichardson
But no Big Ball of Mud to untangle
![Page 67: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/67.jpg)
@crichardson
Microservices deployment
Tomcat
WAR/EAR
Much higher - microservices premium
Forum
Tomcat
WAR/EAR
Post
Tomcat
WAR/EAR
User
![Page 68: Developing functional domain models with event sourcing QCONNY](https://reader034.vdocument.in/reader034/viewer/2022052419/58a2d0c11a28ab2d678b6699/html5/thumbnails/68.jpg)
@crichardson
SummaryEvent sourcing solves a variety of problems in modern application architectures Scala is a great language for implementing ES-based domain models:
Case classes Pattern matching Recreating state = functional fold over events
But Java, JavaScript and Haskell work too! ES-based architecture = flexible deployment