SlideShare ist ein Scribd-Unternehmen logo
1 von 278
Downloaden Sie, um offline zu lesen
1 / 175
Event Sourcing
Explained
{ if at first you don't succeed }
2 / 175
About me
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 3 / 175
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
Half stack developer
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 4 / 175
Half stack developer
Guess which part
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 4 / 175
Agenda
Primer
Principles & Patterns
Common Problems & Solutions
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 5 / 175
Primer
Messages
Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 6 / 175
Primer - Messages
A message is a record of information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 7 / 175
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
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
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
Primer - Messages
Encoding is the conversion of messages into a specific form ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 9 / 175
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
Primer - Messages
Why use a schema and encoding to define your messages?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 10 / 175
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
Primer - Types of Messages
Commands
Events
Documents
Queries | Requests & Responses
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 11 / 175
Primer - Commands
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 12 / 175
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
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
Primer - Events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 13 / 175
Primer - Events
An event is an immutable record of historical information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 13 / 175
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
Primer - Documents
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 14 / 175
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
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
Primer - Queries
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 15 / 175
Primer - Queries
A query is a request to retrieve information ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 15 / 175
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
Primer - Commands
Example: Reserve a table at a restaurant
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 16 / 175
Primer - Commands
Example: Reserve a table at a restaurant
Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 16 / 175
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
Primer - Commands
Example: Reserving a table at a restaurant
PROTO
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 17 / 175
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
Primer - Commands
Example: Reserve a table at a restaurant
CSHARP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 18 / 175
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
Primer - Commands
Example: Reserving a table at a restaurant
SERIALIZATION
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 19 / 175
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
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
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
Primer - Commands
Example: Reserve a table at a restaurant
JSON
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 20 / 175
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
Primer - Commands
Example: Reserve a table at a restaurant
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 21 / 175
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
Primer - Events
Example: A table was reserved at a restaurant
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 22 / 175
Primer - Events
Example: A table was reserved at a restaurant
Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 22 / 175
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
Primer - Events
Example: A table was reserved at a restaurant
JSON
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 23 / 175
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
Primer - Events
Example: A table was reserved at a restaurant
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 24 / 175
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
Primer - Documents
Example: List of cuisines
HTTP
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 25 / 175
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
Primer - Queries
Example: Search for a table to reserve
Request Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 26 / 175
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
Primer - Queries
Example: Search for a table to reserve
Response Analysis
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 27 / 175
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
Primer - Queries
Example: Search for a table to reserve
HTTP - Request
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 28 / 175
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
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
Primer - Message Identity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 30 / 175
Primer - Message Identity
A message identifier uniquely identifies a message ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 30 / 175
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
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
Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 32 / 175
Primer - Event Store
Overview
Examples
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 32 / 175
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
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
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
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
Primer - Event Store
An event middleware decouples sources from destinations ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 35 / 175
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
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
Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 36 / 175
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
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
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
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
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
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
Primer - Event Store
An event store is a collection of streams
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 39 / 175
Primer - Event Store
An event store is a collection of streams
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 39 / 175
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
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
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 41 / 175
Primer - Event Store
Example: Online shopping
Events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 41 / 175
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 42 / 175
Primer - Event Store
Example: Online shopping
John's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 42 / 175
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
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
Primer - Event Store
Example: Online shopping
Jane's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
Primer - Event Store
Example: Online shopping
Jane's shopping cart stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 43 / 175
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
Primer - Event Store
Example: Online shopping
All stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
Primer - Event Store
Example: Online shopping
All stream
john: Guest started shopping
jane:
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 44 / 175
Primer - Event Store
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 45 / 175
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
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
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 47 / 175
Primer - Event Store
Example: Online shopping
All stream subscription from the beginning
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 47 / 175
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
Primer - Event Store
Example: Online shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 48 / 175
Primer - Event Store
Example: Online shopping
All stream subscription from a known position
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 48 / 175
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
Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 49 / 175
Primer - Event Store
Common Operations
Write Behavior
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 49 / 175
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
Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 50 / 175
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
Primer - Event Store
Common Operations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 51 / 175
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
Primer - Event Store
Implementations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 52 / 175
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
Primer
Questions?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 53 / 175
Principles & Patterns
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 54 / 175
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
Event Sourcing
To capture all state changes as a sequence of events.
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 55 / 175
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
Event Sourcing
Example - Online Shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 56 / 175
Event Sourcing
Example - Online Shopping
Cart
Item
Customer
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 56 / 175
Event Sourcing
Data Centric State Changes
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 57 / 175
Event Sourcing
Data Centric State Changes
V1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 57 / 175
Event Sourcing
Data Centric State Changes
V1 V2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 58 / 175
Event Sourcing
Data Centric State Changes
V2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 59 / 175
Event Sourcing
Data Centric State Changes
V2 V3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 60 / 175
Event Sourcing
Data Centric State Changes
V3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 61 / 175
Event Sourcing
Data Centric State Changes
V3 V4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 62 / 175
Event Sourcing
Data Centric State Changes
V4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 63 / 175
Event Sourcing
Data Centric State Changes
V4 V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 64 / 175
Event Sourcing
Data Centric State Changes
V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 65 / 175
Event Sourcing
Data Centric State Changes
V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 66 / 175
Event Sourcing
Event Centric State Changes
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 67 / 175
Event Sourcing
Event Centric State Changes
V1
GSS
- GSS = Guest Started Shopping
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 67 / 175
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
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
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
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
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
Event Sourcing
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 73 / 175
Event Sourcing
Focus of Data Centric State Changes
V1 V2 V3 V4 V5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 73 / 175
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
Event Sourcing
Event Centric Story Telling
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 74 / 175
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
Primer - Event Sourcing
Motivation
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 75 / 175
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
CQRS
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 76 / 175
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
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
CQRS - Example
Imagine a service to maintain customers ...
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 77 / 175
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
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
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
CQRS - Origins
Traditional Architecture
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 80 / 175
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
CQRS - Origins
Traditional Architecture
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 81 / 175
CQRS - Origins
Traditional Architecture
Advantages
Simple
Repeatable
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 81 / 175
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
CQRS - Origins
Capture intent
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 82 / 175
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
CQRS - Origins
Split writing and reading
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 83 / 175
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
CQRS - Origins
Split at the service boundary
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 84 / 175
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
CQRS - Origins
Split at the data boundary
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 85 / 175
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
Event Sourcing meets CQRS
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 86 / 175
Event Sourcing meets CQRS
Split writing and reading using events
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 86 / 175
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
Event Sourcing meets DDD
What changes?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 87 / 175
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
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
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
Event Sourcing meets DDD
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 88 / 175
Event Sourcing meets DDD
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 88 / 175
Common Problems & Solutions
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 89 / 175
How do I perform analysis and design for event
sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 90 / 175
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
So ... how do I write event sourced entities?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 92 / 175
Solution
Conceptual Model
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 93 / 175
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
Solution
Flow for a new entity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 94 / 175
Solution
Flow for a new entity
CH E
ES
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 94 / 175
Solution
Flow for an existing entity
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 95 / 175
Solution
Flow for an existing entity
CH E
ES
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 95 / 175
Solution
Stream
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 96 / 175
Solution
Stream
stream-x
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 96 / 175
Solution
Stream
stream-x
E1
T1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 97 / 175
Solution
Stream
stream-x
E1 E2
T1 T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 98 / 175
Solution
Stream
stream-x
E1 E2 E3 E4
T1 T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 99 / 175
Solution
Stream
stream-x
E1 E2 E3 E4 ...
T1 T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 100 / 175
Great ... but I meant in code ;-)
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 101 / 175
Authoring Abstractions
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 102 / 175
Authoring Abstractions
Event Source
public interface IEventSource
{
void RestoreFromEvents(object[] events);
object[] TakeEvents();
}
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 102 / 175
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
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
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
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
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
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
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
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
Authoring Abstractions
Recommendations
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 111 / 175
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
How come my events look like property sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 112 / 175
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
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
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
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
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
How do I enforce set constraints?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 116 / 175
Use Case - Email addresses uniqueness
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 117 / 175
Use Case - Email addresses uniqueness
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 117 / 175
Use Case - Email addresses uniqueness
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 118 / 175
Use Case - Monotonic invoice numbers
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 119 / 175
Use Case - Monotonic invoice numbers
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 119 / 175
Use Case - Monotonic invoice numbers
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 120 / 175
How do I handle failure?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 121 / 175
Unexpected Failure
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 122 / 175
Unexpected Failure
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 122 / 175
Expected Failure
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 123 / 175
Expected Failure
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 123 / 175
How do I deal with validation and authorization?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 124 / 175
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 125 / 175
How do I deal with large payloads?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 126 / 175
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
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
Pattern - Claim Check - Solution 1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 128 / 175
Pattern - Claim Check - Solution 2a
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 129 / 175
Pattern - Claim Check - Solution 2b
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 130 / 175
How do I integrate with other systems?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 131 / 175
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 132 / 175
Solution
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 133 / 175
How do I cope with time and scheduling?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 134 / 175
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
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
Solution
Time as a stream of events - V1
T1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 136 / 175
Solution
Time as a stream of events - V1
T1 T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 137 / 175
Solution
Time as a stream of events - V1
T1 T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 138 / 175
Solution
Time as a stream of events - V1
T1 T2 T3 T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 139 / 175
Solution
Time as a stream of events - V1
T1 T2 T3 T4 T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 140 / 175
Solution
Time as a stream of events - V2
T1
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 141 / 175
Solution
Time as a stream of events - V2
T1 T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 142 / 175
Solution
Time as a stream of events - V2
T2
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 143 / 175
Solution
Time as a stream of events - V2
T2 T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 144 / 175
Solution
Time as a stream of events - V2
T3
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 145 / 175
Solution
Time as a stream of events - V2
T3 T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 146 / 175
Solution
Time as a stream of events - V2
T4
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 147 / 175
Solution
Time as a stream of events - V2
T4 T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 148 / 175
Solution
Time as a stream of events - V2
T5
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 149 / 175
Help! My stream is too long!
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 150 / 175
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
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
Snapshotting
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 152 / 175
Snapshotting
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 153 / 175
Snapshotting
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 154 / 175
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
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
Superseding
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 156 / 175
How does testing work with event sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 157 / 175
Testing
Definition
Scenario
Scenario Builder
Example
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 158 / 175
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
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
Testing
Anatomy of scenario
CommandHandler
Givens
When
Thens / Throws
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 160 / 175
Testing
Anatomy of scenario builder
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 161 / 175
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 162 / 175
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 163 / 175
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
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
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
What should I be looking for while applying event
sourcing?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 167 / 175
Stream Patterns
Long vs Short Lived
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 168 / 175
Stream Patterns
Slow vs Fast Changing
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 169 / 175
Stream Patterns
Low vs High Volume
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 170 / 175
Stream Patterns
Beginning vs Ending
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 171 / 175
Stream Patterns
Cyclic Behavior
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 172 / 175
Common Problems and Solutions
Questions?
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 173 / 175
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
EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 175 / 175

Weitere ähnliche Inhalte

Kürzlich hochgeladen

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Kürzlich hochgeladen (20)

Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 

Empfohlen

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
ThinkNow
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 

Empfohlen (20)

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 

Eventsourcing Xplained

  • 2. Event Sourcing Explained { if at first you don't succeed } 2 / 175
  • 3. About me EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 3 / 175
  • 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
  • 5. Half stack developer EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 4 / 175
  • 6. Half stack developer Guess which part EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 4 / 175
  • 7. Agenda Primer Principles & Patterns Common Problems & Solutions EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 5 / 175
  • 8. Primer Messages Event Store EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 6 / 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
  • 18. Primer - Commands EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 12 / 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
  • 21. Primer - Events EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 13 / 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
  • 24. Primer - Documents EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 14 / 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
  • 27. Primer - Queries EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 15 / 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
  • 114. Primer Questions? EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 53 / 175
  • 115. Principles & Patterns EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 54 / 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
  • 139. Event Sourcing EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 73 / 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
  • 146. CQRS EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 76 / 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
  • 179. Solution Conceptual Model EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 93 / 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
  • 185. Solution Stream EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 96 / 175
  • 186. Solution Stream stream-x EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 96 / 175
  • 187. Solution Stream stream-x E1 T1 EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 97 / 175
  • 188. Solution Stream stream-x E1 E2 T1 T2 EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 98 / 175
  • 189. Solution Stream stream-x E1 E2 E3 E4 T1 T2 T3 EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 99 / 175
  • 190. Solution Stream stream-x E1 E2 E3 E4 ... T1 T2 T3 EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 100 / 175
  • 191. Great ... but I meant in code ;-) EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 101 / 175
  • 192. Authoring Abstractions EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 102 / 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
  • 202. Authoring Abstractions Recommendations EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 111 / 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
  • 218. Unexpected Failure EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 122 / 175
  • 219. Unexpected Failure Solution EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 122 / 175
  • 220. Expected Failure EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 123 / 175
  • 221. Expected Failure Solution EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 123 / 175
  • 222. How do I deal with validation and authorization? EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 124 / 175
  • 223. Solution EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 125 / 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
  • 231. Solution EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 132 / 175
  • 232. Solution EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 133 / 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
  • 253. Snapshotting EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 152 / 175
  • 254. Snapshotting EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 153 / 175
  • 255. Snapshotting EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 154 / 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
  • 258. Superseding EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 156 / 175
  • 259. How does testing work with event sourcing? EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 157 / 175
  • 260. Testing Definition Scenario Scenario Builder Example EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 158 / 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
  • 263. Testing Anatomy of scenario CommandHandler Givens When Thens / Throws EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 160 / 175
  • 264. Testing Anatomy of scenario builder EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 161 / 175
  • 265. EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 162 / 175
  • 266. EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 163 / 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
  • 274. Stream Patterns Beginning vs Ending EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 171 / 175
  • 275. Stream Patterns Cyclic Behavior EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 172 / 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
  • 278. EventSourcing Xplained - © BitTacklr 2019 - @yreynhout - yves.reynhout@bittacklr.be 175 / 175