Slides for my "Introduction to Event Sourcing and CQRS" session at the IASA-IL meeting.
Abstract:
Event sourcing is a pattern for modeling the application’s business logic. It states that all changes to application state should be defined and stored as a sequence of events.
Its advantages are many:
* Gives freedom to refactor the business logic, allowing better response to new requirements.
* Suitable for building scalable, highly concurrent, distributed systems.
* Stored events give the true history of a system, which is required by law in some industries.
* The system’s state can be reversed to any point in the past for retroactive debugging.
* The required infrastructure is simple - no monstrous databases are involved.
Vladik will also describe CQRS, an architecture that goes hand in hand with Event Sourcing.
13. Good Domain Model
• Not too much
• Not too less
• Sweet spot
• The information we need
• The information we will need
14. Why domain models fail
• We absolutely suck at predicting the future
• No single model can suit all the use cases
• Model transformations are painful
16. • 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)
17. • 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
18. 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)
)
19. • 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
20. • 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
21. • Analysts should be able to review status changes
history for each customer - change date and the
new status
22. 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)
)
23. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 04-2342343 New
24. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 04-2342343 CallLater 27/10/2014
25. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 08-9876653 CallLater 27/10/2014
26. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 08-9876653 Converted
27. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 08-9876653 Converted
33. 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);
}
}
34. Id Name Email Phone number Status
Scheduled
Call
10 John john@gmail.com 08-9876653 Converted
35. 1. new StatusChanged(Status.CallLater)
2. new FutureCallScheduled(’27/10/2014’)
3. new ContactDetailsWereUpdated(
NewPhoneNumber=’08-9876653’
)
4. new StatusChanged(Status.Converted)
37. 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);
}
}
38. 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)
);
}
….
….
}
39. class Customer {
int Id;
string Name;
string Email;
string PhoneNumber;
Status Status;
DateTime? ScheduledCall;
List<IEvent> Events;
}
40. class CustomerSearchModel {
int Id;
List<string> Names;
List<string> Emails;
List<string> PhoneNumbers;
Status Status;
DateTime? ScheduledCall;
}
41. class CustomerAnalysisModel {
int Id;
string Name;
string Email;
string PhoneNumber;
List<StatusChange> StatusChanges;
DateTime? ScheduledCall;
}
42. Good Domain Model
• Not too much
• Not too less
• Sweet spot
• The information we need
• The information we might need
43. 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
57. Before you try this at home
• Read “Implementing Domain Driven Design” by
Vaughn Vernon
• Read “Domain Driven Design” by Eric Evans
• Follow Greg Young, Udi Dahan, DDD community
• Read DDD/CQRS on Google Groups
• Join http://meetup.com/DDD-IL :)