I am looking into Event Sourcing (ES) and having a play around with some code Greg Young put together (Greg Young Git Repo).
I like what ES offers in terms of functionality, but I am trying to apply that to my knowledge of a specific problem domain. Most applications I have worked on are all based around storing all data as state. Typically CRUD applications and a lot of DDD of late – pretty much in a SQL Server backend.
I see a lot of examples around Purchase Orders and Order Items for ES, which are pretty simplistic examples – although in my Purchase Order world we have far more complex domains – where there are all kinds of rules. Whilst these are a great starting point, I would like to broaden my horizon on slightly more complex domain scenarios.
So to test out ES in my hypothetical problem domain, suppose I have the following simplified scenario where:
Aggregate 1 – Business Configuration
Aggregate 1 is configured as a Group/Item relationship, for example:
Group 1 (Aggregate1Group) Item 1 (Aggregate1Item) Item 2 (Aggregate1Item) Group 2 (Aggregate1Group) Item 3 (Aggregate1Item) Item 4 (Aggregate1Item)
This is typically a one of task a the user would run through, but nothing ever stays that way!
Aggregate 2 – Business Rule Set
Aggregate2 is pretty much standalone set of rules. Its user configured business rule ranges which are used within Aggregate3, but require a “reference” to Aggregate1 Group.
BusinessRule1 (BusinessRule) Min: 0 Max: 100 Aggregate1Group: Group 1 BusinessRule2 (BusinessRule) Min: 200 Max: 300 Aggregate1Group: Group 2
Aggregate 3 – Enforcing Rules
Aggregate3 requires the user to pick an item and select a value, which would be implemented with the following method:
void Aggregate3.BookThisIn(int value, Aggregate1Item item, string someIrrevantInfo) { bool allowed = BusinessRules.Any(b => value >= b.Min && value <= b.Max && b.Aggregate1Group.Contains(item)); if (allowed) { IrrelevantInfo.Add(someIrrevantInfo); // raise events Events.Add(new IrrelevantInfoAddedEvent(...)); } }
So basically, if the value is between the Business Rule Min and Max, and the specified item is within that Business Rule group, then we are allowed to log the irrelevant info.
Hypothetical scenarios and questions
So lets suppose the following events have happened:
- User created Groups and Items as per Aggregate 1 – Business Configuration
- User created Business Rules as per Aggregate 2 – Business Rule Set
- User BookThisIn for value of 50 and Aggregate1Item of Item 1 with someIrrevantInfo of “Some Test”
All domain data is in a valid state so far… Or is it?
Now the user decides they got the configuration wrong. Aggregate1Item “Item 1” actually belongs to Aggregate1Group “Group 2”. Given that, the data entered in step 3 is now in fact incorrect.
Potentially, the data could be determined to be historically correct in other cases, where all current data is deemed correct at the point in time events occur.
So in the case of a state based SQL database, you could look at any entities stored in the IrrelevantInfo list (that would map onto a table – say IrrelevantInfos) and you could make the user resolve the issues within a UI.
But in an event based system, how would you play out this invalidation scenario – and how could you provide the information to the user to resolve? What patterns does ES offer to overcome this hurdles?