introduction to event sourcing and cqrs
DESCRIPTION
Event sourcing is a pattern for modelling your application’s business logic. It states that all changes to application state should be defined and stored as a sequence of events. The idea of recording events for information storage is nothing new. It has been used for decades in finance, healthcare, and other fields. A few years ago it was rediscovered in software design and its advantages are many: - Suitable for building scalable, highly concurrent, distributed systems. - The stored events give you the true history of a system. This audit is required by law in some industries. - The system’s state can be reversed to any point in the past for retroactive debugging and data analysis. - Gives freedom to refactor your business logic, thus allows much better response to new requirements. - The required infrastructure is simple - no monstrous databases are involved. The focus of my talk will be the Event Sourcing pattern, but I’ll also briefly describe CQRS - an architecture that goes hand in hand with Event Sourcing.TRANSCRIPT
Introduction to Event Sourcing … and CQRS
Vladik KhononovSolutions Architect at Plexop
http://il.linkedin.com/in/vladikkhononov/
vladikk vladikkhttp://vladikk.com
Introduction to Event Sourcing… and CQRS
Domain Driven Design?
IntroductionHow we are used to do things
PresentationDALBusiness Logic
Domain Model
– www.dictionary.com
Model: A simplified representation of a system or phenomenon.
– www.wikipedia.org
מודל: ייצוג תאורטי של מערכת מורכבת, שמטרתו לחקות את המערכת בהיבטים מהותיים. המודל
אינו מתאר כל תופעה במערכת, אלא מתייחס להיבטים מוגדרים ומצומצמים שלה. המודל
מבוסס על קירוב של המציאות בדרך של הפשטה, איחוד ישויות והתעלמות מגורמים שהשפעתם
אינה מהותית.
User Interface StorageDomain
Model
Domain Model
Good Domain Model• Not too much
• Not too less
• Sweet spot
• The information we need
• The information we might need
Why domain models fail
• We absolutely suck at predicting the future
• No single model can suit all the use cases (e.g.: transactional processing, business intelligence, search)
• Model transformations are painful
Case Study: Customers Management
• A customer has customer id number and a name • A customer has contact information: email, phone
number • A customer can be in on of the following states:
New, CallLater, Converted, NotInterested • A seller has seller id number, name and password • The selling home page contains a list of the
customers in the following statuses: • New • CallLater (when scheduled call date is met)
• Seller chooses a customer to call from the home page
• Seller can change the customer’s status to “Converted”, “Not Interested”
• Seller can schedule a future call by setting the future call date. The Customer’s status will change to “CallLater”
• Seller can change name, email, and phone number
enum Status { New, CallLater, Converted, NotInterested }
class Customer { int Id; string Name; Status Status; DateTime? ScheduledCall; string Email; string PhoneNumber;}
CREATE TABLE Customers ( ID INTEGER, Name CHAR(40), Email CHAR(40), PhoneNumber CHAR(40), Status INTEGER, ScheduledCall DATETIME, PRIMARY KEY (ID))
class Seller { int Id; string Name; string Password;}
CREATE TABLE Sellers ( ID INTEGER, Name CHAR(40), Password CHAR(40) PRIMARY KEY (ID))
• Seller can find customers by name, email, and/or phone number in the search page
• The customers should be found by the current and the past values
• If no new customers are available on the home page, it should display customers in the NotInterested status, if it was set more than a 30 days ago
• Analysts should be able to review status changes history for each customer - change date and the new status
class Seller { int Id; string Name; string Password;}
CREATE TABLE Sellers ( ID INTEGER, Name CHAR(40), Password CHAR(40) PRIMARY KEY (ID))
enum Status { New, CallLater, Converted, NotInterested }
class Customer { int Id; string Name; Status Status; DateTime? ScheduledCall; string Email; string PhoneNumber;}
CREATE TABLE Customers ( ID INTEGER, Name CHAR(40), Email CHAR(40), PhoneNumber CHAR(40), Status INTEGER, ScheduledCall DATETIME, PRIMARY KEY (ID))
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 04-2342343 New
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 04-2342343 CallLater 27/10/2014
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 08-9876653 CallLater 27/10/2014
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 08-9876653 Converted
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 08-9876653 Converted
Event SourcingCapture all changes to an application
state as a sequence of events ~ Martin Fowler
class StatusChanged : IEvent { Status NewStatus; DateTime CreatedOn; int CreatedBy; }
class FutureCallScheduled : IEvent { DateTime ScheduledCallTime; DateTime CreatedOn; int CreatedBy; }
class ContactDetailsWereUpdated : IEvent { string NewName; string NewEmail; string NewPhone; DateTime CreatedOn; int CreatedBy; }
class Customer { int Id; string Name; string Email; string PhoneNumber; Status Status; DateTime? ScheduledCall;
List<IEvent> Events; …
void Apply(StatusChanged e) { Status = e.NewStatus;Events.Add(e);
} …. ….}
class Customer { int Id; string Name; string Email; string PhoneNumber; Status Status; DateTime? ScheduledCall;
List<IEvent> Events; … …
void Apply(FutureCallScheduled e) { ScheduledCall = e.ScheduledCallTime;Events.Add(e);
} …}
class Customer { int Id; string Name; string Email; string PhoneNumber; Status Status; DateTime? ScheduledCall;
List<IEvent> Events; … … …
void Apply(ContactDetailsWereUpdated e) { Name = e.NewName;Email = e.NewEmail;PhoneNumber = e.NewPhoneNumber;Events.Add(e);
} }
Id Name Email Phone number Status Scheduled Call
10 John [email protected] 08-9876653 Converted
1. new StatusChanged(Status.CallLater)
2. new FutureCallScheduled(’27/10/2014’)
3. new ContactDetailsWereUpdated( NewPhoneNumber=’08-9876653’)
4. new StatusChanged(Status.Converted)
Event Storage
Entity Id + New events
Entity IdEvent1,Event2,Event3,
….
class CustomerSearchModel { int Id; List<string> Names; List<string> Emails; List<string> PhoneNumbers; Status Status; DateTime? ScheduledCall; … … …
void Apply(ContactDetailsWereUpdated e) { Names.Add(e.NewName);Emails.Add(e.NewEmail);PhoneNumbers.Add(e.NewPhoneNumber);
} }
class CustomerAnalysisModel { int Id; string Name; string Email; string PhoneNumber;
List<StatusChange> StatusChanges; DateTime? ScheduledCall; …
void Apply(StatusChanged e) { StatusChanges.Add(
new StatusChange(e.CreatedOn, e.NewStatus));
} …. ….}
class Customer { int Id; string Name; string Email; string PhoneNumber; Status Status; DateTime? ScheduledCall; List<IEvent> Events;}
class CustomerSearchModel { int Id; List<string> Names;
List<string> Emails;List<string> PhoneNumbers;
Status Status; DateTime? ScheduledCall;}
class CustomerAnalysisModel { int Id; string Name; string Email; string PhoneNumber;
List<StatusChange> StatusChanges; DateTime? ScheduledCall; }
Good Domain Model✓ Not too much
✓ Not too less
✓ Sweet spot
✓ The information we need
✓ The information we might need
Why domain models fail
✓ We absolutely suck at predicting the future
✓ No single model can suit all the use cases (e.g.: transactional processing, business intelligence, search)
✓ Model transformations are painful
Event Storage
Entity Id + New events
Entity IdEvent1,Event2,Event3,
….
CQRSCommand Query Responsibility Segregation
Laye
red
Arch
itect
ure
Step
1
Step
2
Step
3
CQ
RS
• Event based models
• Effective modeling
• No future predicting required
• Time machine
• Retroactive debugging
• Infrastructural freedom
• Infinite scalability
• Easy to scale writes
• Easy to scale reads
Conclusions
Before you try this at home
• Read “Implementing Domain Driven Design” by Vaughn Vernon
• Read “Domain Driven Design” by Eric Evans
• Follow Greg Young
• Read DDD/CQRS on Google Groups
Questions?
http://il.linkedin.com/in/vladikkhononov
http://twitter.com/vladikk
http://facebook.com/vladikk
http://vladikk.com