Weitere ähnliche Inhalte
Kürzlich hochgeladen (20)
Eventsourcing Xplained
- 4. About me
A journeylist with a passion for well-designed, properly decomposed, working
software.
Professional experience:
25 years,
Mainly building products,
In domains such as patient logistics, real estate, manufacturing, construction,
transportation, oil & gas, content & collaboration, government, finance
Contractor | Consultant | Trainer | Analyst | Designer @ BitTacklr
Community experience:
DDD community member,
Occasional speaker, blogger on the topic of Domain Driven Design, Command
and Query Responsibility Segregation, Event Sourcing and Messaging and
related topics.
Author of AggregateSource / Projac | Contributor to SqlStreamStore (OSS).
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 3 / 175
- 6. Half stack developer
Guess which part
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 4 / 175
- 9. Primer - Messages
A message is a record of information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 7 / 175
- 10. Primer - Messages
A message is a record of information ...
that captures meaning and data
that can be transmitted
that can be stored
that typically has a header and a body (i.e. an envelope)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 7 / 175
- 11. Primer - Messages
A schema describes the shape or structure of messages in a formal language ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 8 / 175
- 12. Primer - Messages
A schema describes the shape or structure of messages in a formal language ...
such as XML or JSON schema, Protocol Buffers' Language, etc.
that can be shared between parties
for which code can be generated
that can be interpreted
that optionally contains constraints, requirements and/or metadata
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 8 / 175
- 13. Primer - Messages
Encoding is the conversion of messages into a specific form ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 9 / 175
- 14. Primer - Messages
Encoding is the conversion of messages into a specific form ...
such that it can form a protocol with other parties
such as XML, JSON, BSON, Protocol Buffers, UTF-8|16|32,
which is often classified as either binary or character
which is a more general form of serialization
https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 9 / 175
- 15. Primer - Messages
Why use a schema and encoding to define your messages?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 10 / 175
- 16. Primer - Messages
Why use a schema and encoding to define your messages?
Your programming language supports things your encoding format does not
Your encoding format supports things your programming language does not
Your encoding format is dictating your message type system, not your programming
language
Your code is simply too refactor friendly
Generally, people suck at versioning - schema helps you get serious about that
Schema allows for up-front design and is a collaboration medium
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 10 / 175
- 17. Primer - Types of Messages
Commands
Events
Documents
Queries | Requests & Responses
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 11 / 175
- 19. Primer - Commands
A command is a request to change state or to invoke behavior ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 12 / 175
- 20. Primer - Commands
A command is a request to change state or to invoke behavior ...
that can be classified as a type of message,
that can denote the body of a message,
that captures meaning and data of something that should happen,
that can capture business or domain relevant change requests,
uses imperative (think German),
uses domain specific language,
expressed using verbs, preferably sentences.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 12 / 175
- 22. Primer - Events
An event is an immutable record of historical information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 13 / 175
- 23. Primer - Events
An event is an immutable record of historical information ...
that can be classified as a type of message
that can denote the body of a message
that captures meaning and data of something that has happened
that - to the best of our knowledge - happened at a certain instant
that can capture business or domain relevant changes
uses past tense (think French - passé composé)
uses domain specific language,
expressed using verbs, preferably sentences.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 13 / 175
- 25. Primer - Documents
A document message acts as a data container and lets the receiver decide what to do
with it ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 14 / 175
- 26. Primer - Documents
A document message acts as a data container and lets the receiver decide what to do
with it ...
is used to integrate / exchange information between systems,
is often associated with canonical or stable data models,
is also the shape used to communicate the result of a query,
the timing of when it's sent or received and the intent is less important, thus
differentiating itself from commands and events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 14 / 175
- 28. Primer - Queries
A query is a request to retrieve information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 15 / 175
- 29. Primer - Queries
A query is a request to retrieve information ...
usually represented as the combination of a request and response message
that can capture business or domain relevant requests,
where the request message often contains criteria to select, filter and page results
where the response message often contains the result that meets the request criteria
often aligns with the needs of consumers, e.g. the data on a screen or the shape of
an API
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 15 / 175
- 30. Primer - Commands
Example: Reserve a table at a restaurant
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 16 / 175
- 31. Primer - Commands
Example: Reserve a table at a restaurant
Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 16 / 175
- 32. Primer - Commands
Example: Reserve a table at a restaurant
Analysis
Who wants to make the reservation?
How many guests are you?
When are you coming?
Which restaurant?
What's the occasion? (optional)
Any special request? (optional)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 16 / 175
- 33. Primer - Commands
Example: Reserving a table at a restaurant
PROTO
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 17 / 175
- 34. Primer - Commands
Example: Reserving a table at a restaurant
PROTO
message ReserveTable = {
string MemberId = 1;
int32 Guests = 2;
string Date = 3
string Time = 4;
string RestaurantId = 5;
string Occasion = 6;
string SpecialRequest = 7;
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 17 / 175
- 35. Primer - Commands
Example: Reserve a table at a restaurant
CSHARP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 18 / 175
- 36. Primer - Commands
Example: Reserve a table at a restaurant
CSHARP
public class ReserveTable
{
public Guid MemberId { get; set; }
public Int32 Guests { get; set; }
public DateTime Date { get; set; }
public TimeSpan Time { get; set; }
public Guid RestaurantId { get; set; }
public String Occasion { get; set; }
public String SpecialRequest { get; set; }
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 18 / 175
- 37. Primer - Commands
Example: Reserving a table at a restaurant
SERIALIZATION
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 19 / 175
- 38. Primer - Commands
Example: Reserving a table at a restaurant
SERIALIZATION
var message = new ReserveTable { MemberId = Guid.NewGuid(), /* ... */ };
Console.WriteLine(JsonConvert.SerializeObject(message));
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 19 / 175
- 39. Primer - Commands
Example: Reserving a table at a restaurant
SERIALIZATION
DESERIALIZATION
var message = new ReserveTable { MemberId = Guid.NewGuid(), /* ... */ };
Console.WriteLine(JsonConvert.SerializeObject(message));
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 19 / 175
- 40. Primer - Commands
Example: Reserving a table at a restaurant
SERIALIZATION
DESERIALIZATION
var message = new ReserveTable { MemberId = Guid.NewGuid(), /* ... */ };
Console.WriteLine(JsonConvert.SerializeObject(message));
var serialized =
@"{""MemberId"": ""6e98e539-eb01-47e9-8961-efd9728a14df"", /*...*/ }";
var message = JsonConvert.DeserializeObject<ReserveTable>(serialized);
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 19 / 175
- 41. Primer - Commands
Example: Reserve a table at a restaurant
JSON
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 20 / 175
- 42. Primer - Commands
Example: Reserve a table at a restaurant
JSON
{
"MemberId": "6e98e539-eb01-47e9-8961-efd9728a14df",
"Guests": 2,
"Date": "2018-01-27", "Time": "19:00:00",
"RestaurantId": "200edce7-263e-4799-81fe-834f84fff17a",
"Occasion": "Birthday",
"SpecialRequest": "Please don't play any birthday music."
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 20 / 175
- 43. Primer - Commands
Example: Reserve a table at a restaurant
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 21 / 175
- 44. Primer - Commands
Example: Reserve a table at a restaurant
HTTP
HTTP/1.1 200 OK
Content-Type: application/vnd.tableau.reservetableatrestaurant+json
Content-Length: 319
{
"MemberId": "6e98e539-eb01-47e9-8961-efd9728a14df",
"Guests": 2,
"Date": "2018-01-27", "Time": "19:00:00",
"RestaurantId": "200edce7-263e-4799-81fe-834f84fff17a",
"Occasion": "Birthday",
"SpecialRequest": "Please don't play any birthday music."
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 21 / 175
- 45. Primer - Events
Example: A table was reserved at a restaurant
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 22 / 175
- 46. Primer - Events
Example: A table was reserved at a restaurant
Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 22 / 175
- 47. Primer - Events
Example: A table was reserved at a restaurant
Analysis
Who made the reservation?
When was it made?
How many guests are you?
When are you coming?
Which restaurant?
Which table was reserved?
What's the occasion? (optional)
Any special request? (optional)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 22 / 175
- 48. Primer - Events
Example: A table was reserved at a restaurant
JSON
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 23 / 175
- 49. Primer - Events
Example: A table was reserved at a restaurant
JSON
{
"MemberId": "6e98e539-eb01-47e9-8961-efd9728a14df",
"Guests": 2,
"Date": "2018-01-27", "Time": "19:00:00",
"RestaurantId": "200edce7-263e-4799-81fe-834f84fff17a",
"TableReference": "C2", "Occasion": "Birthday",
"SpecialRequest": "Please don't play any birthday music.",
"When": "2018-01-07T20:47:00"
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 23 / 175
- 50. Primer - Events
Example: A table was reserved at a restaurant
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 24 / 175
- 51. Primer - Events
Example: A table was reserved at a restaurant
HTTP
HTTP/1.1 200 OK
Content-Type: application/vnd.tableau.tablereservedatrestaurant+json
Content-Length: 319
{
"MemberId": "6e98e539-eb01-47e9-8961-efd9728a14df",
"Guests": 2,
"Date": "2018-01-27", "Time": "19:00:00",
"RestaurantId": "200edce7-263e-4799-81fe-834f84fff17a",
"TableReference": "C2", "Occasion": "Birthday",
"SpecialRequest": "Please don't play any birthday music.",
"When": "2018-01-07T20:47:00"
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 24 / 175
- 52. Primer - Documents
Example: List of cuisines
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 25 / 175
- 53. Primer - Documents
Example: List of cuisines
HTTP
POST /api/lists HTTP/1.1
Host: tableau.fr
Content-Type: application/vnd.tableau.list-of-cuisines+json
Content-Length: 483
{ "Options": [
"American", "Italian", "Steakhouse", "French", "Pacific Rim",
"Indian", "Mexican", "Japanese", "British", "Wine Bar",
"Chinese", "Spanish", "Pizzeria", "Greek", "Thai", "South American",
"Tapas / Small Plates", "Grill", "Comfort Food", "Turkish",
"Argentinean", "Afternoon Tea", "Burgers", "Nepalese", "Wild Game",
"Halal", "Café", "Contemporary European", "Southeast Asian"
"Dim Sum", "European", "Gastro Pub", "Modern European" ] }
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 25 / 175
- 54. Primer - Queries
Example: Search for a table to reserve
Request Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 26 / 175
- 55. Primer - Queries
Example: Search for a table to reserve
Request Analysis
What date do you want to reserve on?
At what time?
What type of food / cooking do you want to have?
How many guests will you be?
Where will you / do you want to be?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 26 / 175
- 56. Primer - Queries
Example: Search for a table to reserve
Response Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 27 / 175
- 57. Primer - Queries
Example: Search for a table to reserve
Response Analysis
For each restaurant with sufficient capacity
indicate whether it's verified or not
state its name, type of food served, address, location, relative distance if
applicable
give an indication of the price range, the rating by other members, its performance
statistics
offer the available time slots
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 27 / 175
- 58. Primer - Queries
Example: Search for a table to reserve
HTTP - Request
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 28 / 175
- 59. Primer - Queries
Example: Search for a table to reserve
HTTP - Request
POST /api/search HTTP/1.1
Host: tableau.fr
Authorization: Bearer
Content-Type: application/vnd.tableau.searchrequest+json
Content-Length: 108
{
"Date": "2020-01-27",
"Time": "19:00",
"Guests": 5,
"Location": "Nearby(50.844795,4.356717)",
"Cuisine": "Italian"
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 28 / 175
- 60. HTTP - Response
HTTP/1.1 200 OK
Content-Type: application/vnd.tableau.searchresponse+json
Content-Length: 634
[ { "Restaurant": {
"Id": "d937eeb1-9ebc-4d0c-a53e-c7ac349adcbd", "Verified": false,
"Name": "La Cucina Della Nonna", "Cuisine": "Italian Food",
"PriceRange": "€€", "Rating":"***", "TotalReviews": 12,
"ReservationStatistics" : {
"Total": 3000, "TotalToday": 0, "TotalByMembers": 300
},
"Address": [ "Rue des Bouchers 5", "1000 Brussels", "Belgium" ],
"Distance": "500m", "Coordinates": "50.847821,4.354781" },
"AvailableTimeSlots": {
"18:30" : [ "A", "B" ], "18:45" : [ "A" ],
"19:00" : [ "E" ], "19:15" : [ "B", "D" ],
"19:30" : [ "A", "D" ] } } ]
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 29 / 175
- 61. Primer - Message Identity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 30 / 175
- 62. Primer - Message Identity
A message identifier uniquely identifies a message ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 30 / 175
- 63. Primer - Message Identity
A message identifier uniquely identifies a message ...
and is usually transmitted as a header,
and is useful for traceability purposes (causation & correlation),
and is useful for message deduplication and idempotent processing,
the use of global unique identifiers is fairly common (uuid | guid).
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 30 / 175
- 64. Primer - Messaging
If you want to learn more about messaging I can highly recommend ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 31 / 175
- 65. Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 32 / 175
- 66. Primer - Event Store
Overview
Examples
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 32 / 175
- 67. Primer - Event Store
An event source is where events come from or took place ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 33 / 175
- 68. Primer - Event Store
An event source is where events come from or took place ...
and could be either hardware or software
and there could be one or more
and is brought to our attention by a producer or publisher or emitter
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 33 / 175
- 69. Primer - Event Store
An event destination is where events go to and are interpreted or handled ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 34 / 175
- 70. Primer - Event Store
An event destination is where events go to and are interpreted or handled ...
and there could be none, one or more than one
and is facilitated by a consumer or receiver or sink
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 34 / 175
- 71. Primer - Event Store
An event middleware decouples sources from destinations ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 35 / 175
- 72. Primer - Event Store
An event middleware decouples sources from destinations ...
or said differently, decouples producers from consumers
of which Apache Kafka, Event Store, Azure Event Grid, Amazon SNS are examples
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 35 / 175
- 73. Primer - Event Store
An event middleware decouples sources from destinations ...
or said differently, decouples producers from consumers
of which Apache Kafka, Event Store, Azure Event Grid, Amazon SNS are examples
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 35 / 175
- 74. Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 36 / 175
- 75. Primer - Event Store
An event stream is a sequence of events partitioned by a name or key
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 37 / 175
- 76. Primer - Event Store
An event stream is a sequence of events partitioned by a name or key
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 37 / 175
- 77. Primer - Event Store
An event stream is a sequence of events partitioned by a name or key
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 37 / 175
- 78. Primer - Event Store
Each event appears at a certain version within an event stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 38 / 175
- 79. Primer - Event Store
Each event appears at a certain version within an event stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 38 / 175
- 80. Primer - Event Store
Each event appears at a certain version within an event stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 38 / 175
- 81. Primer - Event Store
An event store is a collection of streams
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 39 / 175
- 82. Primer - Event Store
An event store is a collection of streams
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 39 / 175
- 83. Primer - Event Store
Each event appears at a certain position within an event store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 40 / 175
- 84. Primer - Event Store
Each event appears at a certain position within an event store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 40 / 175
- 85. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 41 / 175
- 86. Primer - Event Store
Example: Online shopping
Events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 41 / 175
- 87. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 42 / 175
- 88. Primer - Event Store
Example: Online shopping
John's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 42 / 175
- 89. Primer - Event Store
Example: Online shopping
John's shopping cart stream
> Guest started shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 42 / 175
- 90. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
- 91. Primer - Event Store
Example: Online shopping
Jane's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
- 92. Primer - Event Store
Example: Online shopping
Jane's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
- 93. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
- 94. Primer - Event Store
Example: Online shopping
All stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
- 95. Primer - Event Store
Example: Online shopping
All stream
john: Guest started shopping
jane:
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
- 96. Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 45 / 175
- 97. Primer - Event Store
A subscription is an agreement to be notified when new events are written to a stream
...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 46 / 175
- 98. Primer - Event Store
A subscription is an agreement to be notified when new events are written to a stream
...
and is typically set up by a consumer
and is typically facilitated by an event store's client API
and is one of many ways to feed events to projections
and starts off at a known position in the all stream
or starts off at a known version in a stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 46 / 175
- 99. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 47 / 175
- 100. Primer - Event Store
Example: Online shopping
All stream subscription from the beginning
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 47 / 175
- 101. Primer - Event Store
Example: Online shopping
All stream subscription from the beginning
john: Guest started shopping
0 2 4 5 7
jane:
1 3 6 8
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 47 / 175
- 102. Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 48 / 175
- 103. Primer - Event Store
Example: Online shopping
All stream subscription from a known position
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 48 / 175
- 104. Primer - Event Store
Example: Online shopping
All stream subscription from a known position
john: Item was removed from cart
0 2 4 5 7
jane:
1 3 6 8
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 48 / 175
- 105. Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 49 / 175
- 106. Primer - Event Store
Common Operations
Write Behavior
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 49 / 175
- 107. Primer - Event Store
Common Operations
Write Behavior
AppendToStreamAtVersion: append one or more events to a stream, expecting
the stream to be at a certain version (OCC), as an atomic operation (ACID)
AppendToStreamAtAnyVersion: append one or more events to a stream,
regardless of which version the stream is at, as an atomic operation (ACID)
AppendToStreamAtNoVersion: append one or more events to a stream,
expecting there to be no stream (OCC), as an atomic operation (ACID)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 49 / 175
- 108. Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 50 / 175
- 109. Primer - Event Store
Common Operations
Read Behavior
ReadStreamForwards: read a slice of events from a stream, as of a certain
version, progressing towards the end of the stream
ReadStreamBackwards: read a slice of events from a stream, as of a certain
version, progressing towards the beginning of the stream
ReadAllStreamForwards: read a slice of events from the all stream, as of a
certain position, progressing towards the end of the all stream
ReadAllStreamBackwards: read a slice of events from the all stream, as of a
certain position, progressing towards the beginning of the all stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 50 / 175
- 110. Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 51 / 175
- 111. Primer - Event Store
Common Operations
Observation Behavior
SubscribeToStream: observe events in a stream, as of a certain version
SubscribeToAllStream: observe events in a stream, as of a certain position
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 51 / 175
- 112. Primer - Event Store
Implementations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 52 / 175
- 113. Primer - Event Store
Implementations
EventStore - https://eventstore.org/ [.NET HTTP]
SqlStreamStore - https://sqlstreamstore.io/ [.NET C#]
Marten - https://jasperfx.github.io/marten/ [.NET C#]
Equinox - https://github.com/jet/equinox [.NET F#]
AxonIQ - https://axoniq.io/ [JAVA]
PROOPH - http://getprooph.org/ [PHP]
Broadway - https://github.com/broadway [PHP]
Commanded - https://github.com/commanded/eventstore [ELIXIR]
Eventide - https://eventide-project.org/ [RUBY]
...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 52 / 175
- 116. Principles & Patterns
Event Sourcing (ES)
... meets Command & Query Responsibility Segregation (CQRS)
... meets Domain Driven Design (DDD)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 54 / 175
- 117. Event Sourcing
To capture all state changes as a sequence of events.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 55 / 175
- 118. Event Sourcing
To capture all state changes as a sequence of events.
captures and carries intent forward,
captures semantics and data together,
better fit for behavior centric problems,
not so much for data centric problems,
captures domain specific language,
emphasis is on intent, rather than on the data that goes with that intent
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 55 / 175
- 119. Event Sourcing
Example - Online Shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 56 / 175
- 120. Event Sourcing
Example - Online Shopping
Cart
Item
Customer
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 56 / 175
- 121. Event Sourcing
Data Centric State Changes
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 57 / 175
- 122. Event Sourcing
Data Centric State Changes
V1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 57 / 175
- 123. Event Sourcing
Data Centric State Changes
V1 V2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 58 / 175
- 124. Event Sourcing
Data Centric State Changes
V2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 59 / 175
- 125. Event Sourcing
Data Centric State Changes
V2 V3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 60 / 175
- 126. Event Sourcing
Data Centric State Changes
V3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 61 / 175
- 127. Event Sourcing
Data Centric State Changes
V3 V4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 62 / 175
- 128. Event Sourcing
Data Centric State Changes
V4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 63 / 175
- 129. Event Sourcing
Data Centric State Changes
V4 V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 64 / 175
- 130. Event Sourcing
Data Centric State Changes
V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 65 / 175
- 131. Event Sourcing
Data Centric State Changes
V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 66 / 175
- 132. Event Sourcing
Event Centric State Changes
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 67 / 175
- 133. Event Sourcing
Event Centric State Changes
V1
GSS
- GSS = Guest Started Shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 67 / 175
- 134. Event Sourcing
Event Centric State Changes
V1
GSS
V2
IA
- GSS = Guest Started Shopping
- IA = Guest Added Item To Shopping Cart
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 68 / 175
- 135. Event Sourcing
Event Centric State Changes
V1
GSS
V2
IA
V3
IA
- GSS = Guest Started Shopping
- IA = Guest Added Item To Shopping Cart
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 69 / 175
- 136. Event Sourcing
Event Centric State Changes
V1
GSS
V2
IA
V3
IA
V4
IR
- GSS = Guest Started Shopping
- IA = Guest Added Item To Shopping Cart
- IR = Guest Removed Item From Shopping Cart
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 70 / 175
- 137. Event Sourcing
Event Centric State Changes
V1
GSS
V2
IA
V3
IA
V4
IR
V5
IA
- GSS = Guest Started Shopping
- IA = Guest Added Item To Shopping Cart
- IR = Guest Removed Item From Shopping Cart
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 71 / 175
- 138. Event Sourcing
Event Centric State Changes
V1
GSS
V2
IA
V3
IA
V4
IR
V5
IA
- GSS = Guest Started Shopping
- IA = Guest Added Item To Shopping Cart
- IR = Guest Removed Item From Shopping Cart
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 72 / 175
- 140. Event Sourcing
Focus of Data Centric State Changes
V1 V2 V3 V4 V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 73 / 175
- 141. Event Sourcing
Focus of Data Centric State Changes
V1 V2 V3 V4 V5
Focus of Event Centric State Changes
V1
GSS
V2
IA
V3
IA
V4
IR
V5
IA
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 73 / 175
- 142. Event Sourcing
Event Centric Story Telling
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 74 / 175
- 143. Event Sourcing
Event Centric Story Telling
Customer started shopping
Item added to cart
Item added to cart
Item removed from cart
Customer checked out cart t
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 74 / 175
- 144. Primer - Event Sourcing
Motivation
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 75 / 175
- 145. Primer - Event Sourcing
Motivation
the software is acting as the book of record,
the history needs to be kept, i.e. audit heavy,
the history itself brings value,
there's a need for pro- and retroactive behavior,
there's a need for temporal queries,
how we got here is as important as where we are now (intent carried forward),
the (sub-)domain itself highly collaborative,
driven by behavior rather than data,
multiple representation of the same data is required,
other pieces of software are interested in our state changes,
history of disconnected clients needs to be reconciled.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 75 / 175
- 147. CQRS
To split reading from writing, to create two objects where there used to be one
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 76 / 175
- 148. CQRS
To split reading from writing, to create two objects where there used to be one
at the object level better known as CQS (by Bertrand Meyer, Eiffel | Design by
Contract),
usually applied at the application or service boundary,
rather localized, definitely not system wide,
does not require but can benefit from
a task based UI
event sourcing
messaging
eventual consistency
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 76 / 175
- 149. CQRS - Example
Imagine a service to maintain customers ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 77 / 175
- 150. CQRS - Example
Imagine a service to maintain customers ...
Before
public interface CustomerService
{
void MakeCustomerPreferred(CustomerId id);
Customer GetCustomer(CustomerId id);
CustomerSet GetCustomersWithName(Name name);
CustomerSet GetPreferredCustomers();
void ChangeCustomerLocale(CustomerId id, Locale locale);
void CreateCustomer(Customer customer);
void EditCustomerDetails(CustomerDetails details);
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 77 / 175
- 151. CQRS - Example
Imagine a service to maintain customers ...
After
public interface CustomerWriteService
{
void MakeCustomerPreferred(CustomerId id);
void ChangeCustomerLocale(CustomerId id, Locale locale);
void CreateCustomer(Customer customer);
void EditCustomerDetails(CustomerDetails details);
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 78 / 175
- 152. CQRS - Example
Imagine a service to maintain customers ...
After
public interface CustomerReadService
{
Customer GetCustomer(CustomerId id);
CustomerSet GetCustomersWithName(Name name);
CustomerSet GetPreferredCustomers();
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 79 / 175
- 153. CQRS - Origins
Traditional Architecture
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 80 / 175
- 154. CQRS - Origins
Traditional Architecture
Data
Store
Model
Application Services
Service Boundary
Client
Legend
Data
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 80 / 175
- 155. CQRS - Origins
Traditional Architecture
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 81 / 175
- 156. CQRS - Origins
Traditional Architecture
Advantages
Simple
Repeatable
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 81 / 175
- 157. CQRS - Origins
Traditional Architecture
Advantages
Simple
Repeatable
Disadvantages
Noun centric
Read & write mismatch resulting in lots of mapping
Anemic & structural (*)
Little logic / mostly transaction script (*)
Loss of intent / decision
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 81 / 175
- 158. CQRS - Origins
Capture intent
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 82 / 175
- 159. CQRS - Origins
Capture intent
Data
Store
Model
Application Services
Service Boundary
Client
Legend
Data
Command
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 82 / 175
- 160. CQRS - Origins
Split writing and reading
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 83 / 175
- 161. CQRS - Origins
Split writing and reading
Data
Store
Model
Command Handling Query Handling
Service Boundary
Client
Legend
Data
Command
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 83 / 175
- 162. CQRS - Origins
Split at the service boundary
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 84 / 175
- 163. CQRS - Origins
Split at the service boundary
Data
Store
Model
Command Handling
Service Boundary
Query Handling
Service Boundary
Client
Legend
Data
Command
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 84 / 175
- 164. CQRS - Origins
Split at the data boundary
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 85 / 175
- 165. CQRS - Origins
Split at the data boundary
Data
Store
Data
Store
Model
Command Handling Query Handling
Service Boundary
Client
Legend
Data
Command
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 85 / 175
- 166. Event Sourcing meets CQRS
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 86 / 175
- 167. Event Sourcing meets CQRS
Split writing and reading using events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 86 / 175
- 168. Event Sourcing meets CQRS
Split writing and reading using events
Event
Store
Data
Store
Model
Command Handling
Projections
Query Handling
Service Boundary
Client
Legend
Data
Command
Event
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 86 / 175
- 169. Event Sourcing meets DDD
What changes?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 87 / 175
- 170. Event Sourcing meets DDD
What changes?
Entities become event sourced,
Events become part of the model,
Repositories deal with streams, events and event stores.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 87 / 175
- 171. Event Sourcing meets DDD
What changes?
Entities become event sourced,
Events become part of the model,
Repositories deal with streams, events and event stores.
What remains?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 87 / 175
- 172. Event Sourcing meets DDD
What changes?
Entities become event sourced,
Events become part of the model,
Repositories deal with streams, events and event stores.
What remains?
the importance of language,
the focus on the domain one is active in,
models to tackle problems,
strategic design there of,
other tactical patterns (e.g. Value Objects, Services, Factories, etc.)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 87 / 175
- 173. Event Sourcing meets DDD
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 88 / 175
- 174. Event Sourcing meets DDD
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 88 / 175
- 175. Common Problems & Solutions
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 89 / 175
- 176. How do I perform analysis and design for event
sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 90 / 175
- 177. Solution
Apply event storming to uncover the events, commands, entities, boundaries,
processes at play in your domain - https://www.eventstorming.com/
Apply event modeling if you have a good grasp of the personas, ux and/or ui,
integrations, processes at play in your domain - https://eventmodeling.org/
Apply domain story telling if you want to uncover actors, work objects, actions but
above all scenarios at play in your domain - https://domainstorytelling.org/
Learn about state machines to model the life cycle of entities - use visual methods to
uncover invariants and when each behavior is possible - unravel and challenge
accidental complexity
Pay attention to the language and temporal aspects in your domain
Note: though event sourcing may warrant different analysis and design techniques,
that doesn't mean existing methods are obsolete.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 91 / 175
- 178. So ... how do I write event sourced entities?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 92 / 175
- 180. Solution
Conceptual Model
CH E
ES RS
CH = Command Handler (Controller / Actor)
E = Entity
ES = Event Store (Client / Repository)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 93 / 175
- 181. Solution
Flow for a new entity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 94 / 175
- 182. Solution
Flow for a new entity
CH E
ES
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 94 / 175
- 183. Solution
Flow for an existing entity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 95 / 175
- 184. Solution
Flow for an existing entity
CH E
ES
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 95 / 175
- 191. Great ... but I meant in code ;-)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 101 / 175
- 193. Authoring Abstractions
Event Source
public interface IEventSource
{
void RestoreFromEvents(object[] events);
object[] TakeEvents();
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 102 / 175
- 194. Authoring Abstractions
Event Recorder
public class EventRecorder {
private readonly List<object> _recorded = new List<object>();
public bool HasRecordedEvents => _recorded.Count != 0;
public object[] RecordedEvents => _recorded.ToArray();
public void Record(object @event) {
if (@event == null)
throw new ArgumentNullException(nameof(@event));
_recorded.Add(@event);
}
public void Reset() => _recorded.Clear();
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 103 / 175
- 195. Authoring Abstractions
Event Player
public class EventPlayer {
private readonly Dictionary<Type, Action<object>> _handlers
= new Dictionary<Type, Action<object>>();
public void Register<TEvent>(Action<TEvent> handler) {
if (handler == null)
throw new ArgumentNullException(nameof(handler));
var typeOfEvent = typeof(TEvent);
if (_handlers.ContainsKey(typeOfEvent))
throw new InvalidOperationException(
"There's already a handler registered for the event of type " +
$"'{typeOfEvent.Name}'");
_handlers.Add(typeOfEvent, @event => handler((TEvent)@event));
} // to be continued ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 104 / 175
- 196. Authoring Abstractions
Event Player
public void Play(object @event) {
if (@event == null)
throw new ArgumentNullException(nameof(@event));
if (_handlers.TryGetValue(@event.GetType(),
out Action<object> handler)) {
handler(@event);
}
}
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 105 / 175
- 197. Authoring Abstractions
Event Source - Explicit Player / Recorder
public abstract class EventSource : IEventSource {
private readonly EventPlayer Player
= new EventPlayer();
private readonly EventRecorder Recorder
= new EventRecorder();
protected void On<TEvent>(Action<TEvent> handler) {
Player.Register<TEvent>(handler);
}
protected void Apply(object @event) {
Player.Play(@event);
Recorder.Record(@event);
} // to be continued ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 106 / 175
- 198. Authoring Abstractions
Event Source - Explicit Player / Recorder
// continued ...
void IEventSource.RestoreFromEvents(object[] events) {
if(events == null)
throw new ArgumentNullException(nameof(events));
if(Recorder.HasRecordedEvents)
throw new InvalidOperationException(
"Restoring from events is not possible when an instance " +
"has recorded events.");
foreach(var @event in events)
Player.Play(@event);
} // to be continued ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 107 / 175
- 199. Authoring Abstractions
Event Source - Explicit Player / Recorder
// continued ...
object[] IEventSource.TakeEvents() {
if(!Recorder.HasRecordedEvents)
return Array.Empty<object>();
var recorded = Recorder.RecordedEvents;
Recorder.Reset();
return recorded;
}
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 108 / 175
- 200. Authoring Abstractions
Event Source - Explicit Player / Recorder - Usage
public class RestaurantService : EventSource {
public void ReserveTable(MemberId member, GuestCount guests,
TimeSlot timeSlot, Text occasion, Text specialRequest) {
// .. guards, conditional and computational logic here
Apply(new TableReserved {
RestaurantId = this.restaurantId, Date = this.date,
Time = timeSlot, TableReference = availableTable,
MemberId = member, Guests = guests,
Occasion = occasion, SpecialRequest = specialRequest
});
}
} //continued
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 109 / 175
- 201. Authoring Abstractions
Event Source - Explicit Player / Recorder - Usage
private readonly HashSet<TableReference> tablesTaken =
new HashSet<TableReference>();
private RestaurantService() {
On<RestaurantTableWasReserved>(@event => {
this.tablesTaken.Add(new TableReference(@event.Table));
});
On<RestaurantServiceScheduled>(@event => {
this.restaurantId = new RestaurantId(@event.RestaurantId);
this.date = @event.Date;
this.serviceHours = TimeRange.From(@event.ServiceHours);
})
}
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 110 / 175
- 203. Authoring Abstractions
Recommendations
Don't do stream version management in a base / entity class.
Do put the expected version on a base / entity class if that's how you go from the
read path to the write path.
Don't mix command handling and entities.
Don't overdo it with too much framework - kills creativity.
Be idiomatic with regard to your programming language - e.g. it looks very different in
a functional programming language.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 111 / 175
- 204. How come my events look like property sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 112 / 175
- 205. Pattern
Property sourcing is an event sourcing anti-pattern where each change to a field /
property causes an event.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 113 / 175
- 206. Pattern
Property sourcing is an event sourcing anti-pattern where each change to a field /
property causes an event.
Forces
Any products that require arbitrary or a high degree of customization at the field level
(e.g. ERP systems).
Solutions
If accidental, stop and align your commands / events with the actual use cases
instead of this.
If on purpose, expect your streams to become very chatty and have low domain
relevance - even to the point where you'll have to infer what happened - which kinda
defeats the purpose of event sourcing.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 113 / 175
- 207. How come my events only have verbs that sound
like I'm building an expensive database?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 114 / 175
- 208. Pattern
Event names in event sourcing that have a lot of Create, Update, Delete in them are
an anti pattern.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 115 / 175
- 209. Pattern
Event names in event sourcing that have a lot of Create, Update, Delete in them are
an anti pattern.
Solutions
Focus on building task based user interfaces that capture use cases an end-user /
automated part of the system is trying to achieve.
If you focus on UX and domain first, language will follow.
Accept that sometimes the domain is not interesting or there's nobody there that can
really explain it - maybe you shouldn't be trying to apply event sourcing here.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 115 / 175
- 210. How do I enforce set constraints?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 116 / 175
- 211. Use Case - Email addresses uniqueness
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 117 / 175
- 212. Use Case - Email addresses uniqueness
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 117 / 175
- 213. Use Case - Email addresses uniqueness
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 118 / 175
- 214. Use Case - Monotonic invoice numbers
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 119 / 175
- 215. Use Case - Monotonic invoice numbers
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 119 / 175
- 216. Use Case - Monotonic invoice numbers
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 120 / 175
- 217. How do I handle failure?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 121 / 175
- 222. How do I deal with validation and authorization?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 124 / 175
- 224. How do I deal with large payloads?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 126 / 175
- 225. Pattern - Claim Check
Store message data in another store and pass a Claim Check to subsequent
components via commands and/or events. These components can use the Claim
Check on the command and/or event to retrieve the stored information.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 127 / 175
- 226. Pattern - Claim Check
Store message data in another store and pass a Claim Check to subsequent
components via commands and/or events. These components can use the Claim
Check on the command and/or event to retrieve the stored information.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 127 / 175
- 227. Pattern - Claim Check - Solution 1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 128 / 175
- 228. Pattern - Claim Check - Solution 2a
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 129 / 175
- 229. Pattern - Claim Check - Solution 2b
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 130 / 175
- 230. How do I integrate with other systems?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 131 / 175
- 233. How do I cope with time and scheduling?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 134 / 175
- 234. Pattern
Time can be represented as a series of events that mimick the ticking of the clock
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 135 / 175
- 235. Pattern
Time can be represented as a series of events that mimick the ticking of the clock
when the granularity is coarse grained (days, months, years, dates)
when the observation of the clock ticking at the right time is less important than
knowing the clock ticked, i.e. reduced precision
you'll have to think about the timezone the clock is ticking in and whether or not that
is important for your observers
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 135 / 175
- 236. Solution
Time as a stream of events - V1
T1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 136 / 175
- 237. Solution
Time as a stream of events - V1
T1 T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 137 / 175
- 238. Solution
Time as a stream of events - V1
T1 T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 138 / 175
- 239. Solution
Time as a stream of events - V1
T1 T2 T3 T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 139 / 175
- 240. Solution
Time as a stream of events - V1
T1 T2 T3 T4 T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 140 / 175
- 241. Solution
Time as a stream of events - V2
T1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 141 / 175
- 242. Solution
Time as a stream of events - V2
T1 T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 142 / 175
- 243. Solution
Time as a stream of events - V2
T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 143 / 175
- 244. Solution
Time as a stream of events - V2
T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 144 / 175
- 245. Solution
Time as a stream of events - V2
T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 145 / 175
- 246. Solution
Time as a stream of events - V2
T3 T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 146 / 175
- 247. Solution
Time as a stream of events - V2
T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 147 / 175
- 248. Solution
Time as a stream of events - V2
T4 T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 148 / 175
- 249. Solution
Time as a stream of events - V2
T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 149 / 175
- 250. Help! My stream is too long!
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 150 / 175
- 251. Pattern
Snapshotting is the act of taking a copy of the state of an entity at a certain version in
the stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 151 / 175
- 252. Pattern
Snapshotting is the act of taking a copy of the state of an entity at a certain version in
the stream
typically implemented as a memento on the entity,
can be stored inside the stream or elsewhere,
it needs to know what it is a snapshot of,
can be negotiated (e.g. different snapshots for different versions of the software),
can be performed while appending to the stream or as a separate process,
beware that if your entity's state changes, your snapshot might become invalidated.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 151 / 175
- 256. Pattern
Superseding is the act of starting off a new stream that only copies the relevant state
as its initial event and makes the old stream point to the new stream.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 155 / 175
- 257. Pattern
Superseding is the act of starting off a new stream that only copies the relevant state
as its initial event and makes the old stream point to the new stream.
could be based on last event time, stream age, stream depth, something else ...
useful pattern to break up large streams which seem to be never ending
only useful if not the entire history is needed to make the next decision
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 155 / 175
- 259. How does testing work with event sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 157 / 175
- 261. Testing
The act of verifying that a command handler and the event source affected behave as
expected ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 159 / 175
- 262. Testing
The act of verifying that a command handler and the event source affected behave as
expected ...
written as a specification,
preferably executed as an integration test with the event store (*),
usually integrated with a unit testing framework
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 159 / 175
- 267. Testing Example
public class RestaurantReservationScenarios {
[Fact] public Task when_reserving_a_table() {
return new Scenario()
.Given(EmptyRestaurantService.SetupFor(Today))
.When(new ReserveTable {
RestaurantId = Restaurants.Default, Date = Today,
Time = "19:00", MemberId = Members.Default, Guests = 2,
Occasion = Text.None, SpecialRequest = Text.None
})
.Then(RestaurantService.Today, new TableReserved {
RestaurantId = Restaurants.Default, Date = Today,
Time = "19:00", TableReference = Tables.DefaultFor(2),
MemberId = Members.Default, Guests = 2,
Occasion = Text.None, SpecialRequest = Text.None
}).AssertAsync(); }
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 164 / 175
- 268. Testing Example
public class RestaurantReservationScenarios {
[Fact] public Task when_reserving_a_table_while_fully_booked() {
return new Scenario()
.Given(FullyBookedRestaurantService.SetupFor(Today))
.When(new ReserveTable {
RestaurantId = Restaurants.Default, Date = Today,
Time = "19:00", MemberId = Members.Default, Guests = 2,
Occasion = Text.None, SpecialRequest = Text.None
})
.Throws(new AllTablesTakenAtTimeException(
RestaurantService.Today, Today, "19:00"
).AssertAsync(); }
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 165 / 175
- 269. Testing
Recommendations
Try to find the right level of abstraction to write tests at,
For scenario driven tests that means being able to change your implementation
without having to touch your tests,
Try to assert that only what you expected occurred and nothing else,
Keep the boilerplate / distraction out of your tests,
Value objects and test data generation help anonymize / randomize valid values.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 166 / 175
- 270. What should I be looking for while applying event
sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 167 / 175
- 271. Stream Patterns
Long vs Short Lived
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 168 / 175
- 272. Stream Patterns
Slow vs Fast Changing
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 169 / 175
- 273. Stream Patterns
Low vs High Volume
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 170 / 175
- 276. Common Problems and Solutions
Questions?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 173 / 175
- 277. The End
Join the DDD-ES-CQRS community
http://j.mp/ddd-es-cqrs
Reading Material
Versioning in an Event Sourced System https://leanpub.com/esversioning
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 174 / 175