With examples from .NET
Design Patterns for implementing Event
Sourcing
Dennis Doomen
@ddoomen | The Continuous Improver
About Me
Hands-on architect in the .NET space with 26 years of experience on
an everlasting quest for knowledge to build the right software the right
way at the right time
@ddoomen | The Continuous Improver
Event Sourcing? What and why
Dennis Doomen | @ddoomen | The Continuous Improver
Command Handlers
Commands
Domain Model
Event Store
Events
App
Query Store
Data Access
Projectors
Events
Query HTTP API
Projections
Events
Command HTTP API
Great unit
for testing
Great unit
for testing
Auditability
comes for free
Can look at the
state in the
past
Can be scaled
independently
Aligns well with
Event Storming
Forces you to
understand your
domain thoroughly
No relational table
structure needed
anymore.
Can replay old data
against new rules
More difficult to
envisage domain
relationships
Great for
replication
Why? And why not?
Dennis Doomen | @ddoomen | The Continuous Improver
Replay
production
scenarios
Need to deal with
versioning issues
Bugs are sometimes
non-trivial
Rebuilding can take
time
Can be a source of
bugs for the
inexperienced
May have to deal
with eventual
consistency
May require end-
to-end tests to
cover everything
Lot of devs perceive it
as complex.
Supports fine-
grained
merging
Dennis Doomen | @ddoomen | The Continuous Improver
Application
Domain
NoSQL / RDBMS
OR/M / DAL
Web UI, HTTP API, etc
Lucene Index
Document Projector
Web UI, HTTP API, etc
Web UI, HTTP API, etc
Domain
Commands
Events
Event Store
Projections
Projectors
Uses Event
Sourcing
Uses traditional
CRUD architecture
Indexing-based
architecture
Subcribe
to
webhooks
Coarse-
grained
HTTP
requests.
Bus
Subscribe
Publish coarse-
grained event
When? And when not?
How?
Dennis Doomen | @ddoomen | The Continuous Improver
Application
Command
Service
Correct Customer
Email Handler
Customer
Unit of
Work
Projector
Data Access
Layer
Read Database
Write
Database
CorrectCustomerEmailCommand
HTTP API / In-process invocation
Get<Customer>(identity)
Correct Email
Event Store
Load(events)
Apply
Get changes
CustomerEmailCorrectedEvent
Submit changes
History
Aggregates.NET
SimpleDomain
Nstore
Eventuous
MartenDB (PostgreSQL)
Eventuous
Nstore
NEventStore (*)
SqlStreamStore
Equinox
Brighter
MediatR (*)
Eventuous
Propulsion
LiquidProjections (*)
Event Sourcing in .NET
Dennis Doomen | @ddoomen | The Continuous Improver
Any RDBMS
Any NoSQL
EventStoreDB
Aggregate (Custom)
Dennis Doomen | @ddoomen | The Continuous Improver
Event Source base (Custom)
Dennis Doomen | @ddoomen | The Continuous Improver
Aggregate State (Custom)
Dennis Doomen | @ddoomen | The Continuous Improver
Projector (Custom)
Projector (Custom)
See also https://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
Aggregate (Eventuous)
See also https://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
Event Source (NEventStore)
See also https://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
Best practices
Dennis Doomen | @ddoomen | The Continuous Improver
Event Store
Projector Projector
RDBMS
Subscribe
Subscribe
Document DB
Projector
RDBMS
Subscribe
Raw SQL
NHibernate RavenDB
Lookup
Autonomous &
independent
Storage technique
optimized for projection
No joining of projections
Avoid reusing the
projections for multiple
purposes
Use aggressive caching
during rebuilds.
Caching strategy
optimized for projector
Owned by projector
Dennis Doomen | @ddoomen | The Continuous Improver
Stream-by-stream
projections during
rebuilds
About well-factored
projections
Customer #123
Correct Customer Shipping
Address Command
Customer Shipping
Address Corrected Event
Event Store
Treat as a
message, not a
type
Order #456
Correct Shipping Address
Command Handler
Application
Customer Shipping Address
Corrected Handler
Order Redirected Event.
Identity != natural
key
Identify
partition key
Primitive types only
Avoid terms like
Create, Update,
Delete, Change.
Avoid property
change events
Don’t use as inter-
domain contracts
Don’t expose
outside the domain
Dennis Doomen | @ddoomen | The Continuous Improver
Inside the domain
Customer #123
Correct Customer Shipping
Address Command
Customer Shipping
Address Corrected Event
Event Store
Order #456
Correct Shipping Address
Command Handler
Application
Order Redirected Event
Dennis Doomen | @ddoomen | The Continuous Improver
Transaction Boundaries
Command Service
Some Command Handler
Customer #123
Event Store
Customer Created Event
Get<Customer>(“123”)
Customer Created Event
Converter
Customer Enrolled Event
May split or merge
events
Can also run as part
of migration
May change the
identity
Unaffected Events
Dennis Doomen | @ddoomen | The Continuous Improver
Versioning
Dealing with schema changes
Dennis Doomen | @ddoomen | The Continuous Improver
• Fix a code bug in the projection
• Restructure the projection for performance reasons
• New features require changes to projections.
Dennis Doomen | @ddoomen | The Continuous Improver
Reasons for reprojections
Event Store
Projector
Application
Version 2
Version 1
X Involves down-time until
the projection has been
rebuild.
Reads data from old
database
Dennis Doomen | @ddoomen | The Continuous Improver
In-place upgrades
Event Store
Projector
Application Application
Network Load Balancer
Event Store
Version 1 Version 2
events
Projection
Projector
Projection
bring off-line
Returns HTTP 503 (Service
Unavailable)
Returns HTTP 503 (Service
Unavailable)
Dennis Doomen | @ddoomen | The Continuous Improver
Requires full
rebuild of the
projections
Practically no
downtime.
Out-of-place / Blue-Green
upgrades
Q&A
…ping me at @ddoomen
…email me at dennis.doomen@avivasolutions.nl
Resources
Event Sourcing: The Good, The Bad and The Ugly
Liquid Projections
Eventuous

Design patterns for Event Sourcing in .NET

  • 1.
    With examples from.NET Design Patterns for implementing Event Sourcing Dennis Doomen @ddoomen | The Continuous Improver
  • 2.
    About Me Hands-on architectin the .NET space with 26 years of experience on an everlasting quest for knowledge to build the right software the right way at the right time @ddoomen | The Continuous Improver
  • 4.
    Event Sourcing? Whatand why Dennis Doomen | @ddoomen | The Continuous Improver
  • 5.
    Command Handlers Commands Domain Model EventStore Events App Query Store Data Access Projectors Events Query HTTP API Projections Events Command HTTP API Great unit for testing Great unit for testing Auditability comes for free Can look at the state in the past Can be scaled independently Aligns well with Event Storming Forces you to understand your domain thoroughly No relational table structure needed anymore. Can replay old data against new rules More difficult to envisage domain relationships Great for replication Why? And why not? Dennis Doomen | @ddoomen | The Continuous Improver Replay production scenarios Need to deal with versioning issues Bugs are sometimes non-trivial Rebuilding can take time Can be a source of bugs for the inexperienced May have to deal with eventual consistency May require end- to-end tests to cover everything Lot of devs perceive it as complex. Supports fine- grained merging
  • 6.
    Dennis Doomen |@ddoomen | The Continuous Improver Application Domain NoSQL / RDBMS OR/M / DAL Web UI, HTTP API, etc Lucene Index Document Projector Web UI, HTTP API, etc Web UI, HTTP API, etc Domain Commands Events Event Store Projections Projectors Uses Event Sourcing Uses traditional CRUD architecture Indexing-based architecture Subcribe to webhooks Coarse- grained HTTP requests. Bus Subscribe Publish coarse- grained event When? And when not?
  • 7.
    How? Dennis Doomen |@ddoomen | The Continuous Improver
  • 8.
    Application Command Service Correct Customer Email Handler Customer Unitof Work Projector Data Access Layer Read Database Write Database CorrectCustomerEmailCommand HTTP API / In-process invocation Get<Customer>(identity) Correct Email Event Store Load(events) Apply Get changes CustomerEmailCorrectedEvent Submit changes History Aggregates.NET SimpleDomain Nstore Eventuous MartenDB (PostgreSQL) Eventuous Nstore NEventStore (*) SqlStreamStore Equinox Brighter MediatR (*) Eventuous Propulsion LiquidProjections (*) Event Sourcing in .NET Dennis Doomen | @ddoomen | The Continuous Improver Any RDBMS Any NoSQL EventStoreDB
  • 9.
    Aggregate (Custom) Dennis Doomen| @ddoomen | The Continuous Improver
  • 10.
    Event Source base(Custom) Dennis Doomen | @ddoomen | The Continuous Improver
  • 11.
    Aggregate State (Custom) DennisDoomen | @ddoomen | The Continuous Improver
  • 12.
  • 13.
    Projector (Custom) See alsohttps://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
  • 14.
    Aggregate (Eventuous) See alsohttps://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
  • 15.
    Event Source (NEventStore) Seealso https://github.com/liquidprojections/LiquidProjections/blob/master/Samples/ExampleHost/CountsProjector.cs#L17
  • 16.
    Best practices Dennis Doomen| @ddoomen | The Continuous Improver
  • 17.
    Event Store Projector Projector RDBMS Subscribe Subscribe DocumentDB Projector RDBMS Subscribe Raw SQL NHibernate RavenDB Lookup Autonomous & independent Storage technique optimized for projection No joining of projections Avoid reusing the projections for multiple purposes Use aggressive caching during rebuilds. Caching strategy optimized for projector Owned by projector Dennis Doomen | @ddoomen | The Continuous Improver Stream-by-stream projections during rebuilds About well-factored projections
  • 18.
    Customer #123 Correct CustomerShipping Address Command Customer Shipping Address Corrected Event Event Store Treat as a message, not a type Order #456 Correct Shipping Address Command Handler Application Customer Shipping Address Corrected Handler Order Redirected Event. Identity != natural key Identify partition key Primitive types only Avoid terms like Create, Update, Delete, Change. Avoid property change events Don’t use as inter- domain contracts Don’t expose outside the domain Dennis Doomen | @ddoomen | The Continuous Improver Inside the domain
  • 19.
    Customer #123 Correct CustomerShipping Address Command Customer Shipping Address Corrected Event Event Store Order #456 Correct Shipping Address Command Handler Application Order Redirected Event Dennis Doomen | @ddoomen | The Continuous Improver Transaction Boundaries
  • 20.
    Command Service Some CommandHandler Customer #123 Event Store Customer Created Event Get<Customer>(“123”) Customer Created Event Converter Customer Enrolled Event May split or merge events Can also run as part of migration May change the identity Unaffected Events Dennis Doomen | @ddoomen | The Continuous Improver Versioning
  • 21.
    Dealing with schemachanges Dennis Doomen | @ddoomen | The Continuous Improver
  • 22.
    • Fix acode bug in the projection • Restructure the projection for performance reasons • New features require changes to projections. Dennis Doomen | @ddoomen | The Continuous Improver Reasons for reprojections
  • 23.
    Event Store Projector Application Version 2 Version1 X Involves down-time until the projection has been rebuild. Reads data from old database Dennis Doomen | @ddoomen | The Continuous Improver In-place upgrades
  • 24.
    Event Store Projector Application Application NetworkLoad Balancer Event Store Version 1 Version 2 events Projection Projector Projection bring off-line Returns HTTP 503 (Service Unavailable) Returns HTTP 503 (Service Unavailable) Dennis Doomen | @ddoomen | The Continuous Improver Requires full rebuild of the projections Practically no downtime. Out-of-place / Blue-Green upgrades
  • 25.
    Q&A …ping me at@ddoomen …email me at dennis.doomen@avivasolutions.nl
  • 26.
    Resources Event Sourcing: TheGood, The Bad and The Ugly Liquid Projections Eventuous