DDD, Saga & Event-Sourcing: Can a Compensate Action Be a Delete?

cqrsdomain-driven-designevent-sourcing

I realize the above question probably raises a few 'what??'s, but let me try to explain :

I'm trying to wrap my head on a couple of related concepts, basically the Saga-pattern ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf) in combination with Event-sourcing (A DDD-concept: http://en.wikipedia.org/wiki/Domain-driven_design)

A good post that wraps it together:
https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

I'm getting to the question in a minute, but I think I have to try to summarize what I understand of it first (which might well be wrong, so please correct if that's the case) since this might well impact why I'm asking the question to begin with:

  1. The Saga pattern is a sort of broker that given an action (end-user, automated, etc. essentially anything that is going to change data) divides that action up in business activities and sends each of these activities as messages to a Message Bus which in turn sends it to the respective aggregate roots to be taken care of.
  2. These aggregate roots can operate completely autonomously (nice separation of concerns, great scalability, etc. )
  3. A Saga-instance itself doesn't contain any business logic, that is contained in the aggregate roots it sends activities to. The only 'logic' contained in the Saga is 'process'-logic, (often implemented as a Statemachine), which determines based on actions received (as well as follow-up events) what to do (i.e: what activities to send)
  4. The Saga-patterns implements a kind of distributed transaction pattern. I.e: when one of the aggregate roots (which again work autonomously, without knowing of eachothers existense) fails, the entire action might have to be rolled back.
  5. This is implemented by having all aggregate roots, upon completion of their activity report back to the Saga. (In case of success as well as error)
  6. In case all aggregate roots return a success, the internal statemachine if the Saga determines what to do next (or decides it's done)
  7. In case of failure, the Saga issues to all aggregate roots that took part in the last action a so called Compensation Action, i.e: an action to undo the last action each of the aggregate roots did.
  8. This might be simply doing a 'Minus 1 vote' if the action was "plus 1 vote' but it could be more complicated like restoring a blogpost to it's previous version.
  9. Event-sourcing (see the blogpost combining the two) aims to externalize saving the results of each of the activities that each of the aggregate roots undertake to a centralized Event Store (the changes are called 'events' in this context)
  10. This Event store is the 'single version of the truth' and can be use to replay the state of all entities simply by iterating the events stored (essentially like an event log)
  11. Combining the two (i.e: letting aggregate roots use Event-sourcing to outsource saving their changes before reporting back to the Saga) enables lots of nice possibilities, one of which concerns my question…

I felt I needed to get this off of my shoulder, since it's a lot to grasp in one go. Given this context/mindset (again, please correct if wrong)

the question: When an aggregate root receives a Compensate Action and if that aggregate root has outsourced it's state-changes using Event-sourcing, wouldn't the Compensate Action in all situations just be a delete of the last event in the Event Store for that given Aggregate Root? (Assuming the persist-implementation allows deletes)

That would make sense to me a lot (and would be another great benefit of this combination) but as I said I might be making these assumptions based on a incorrect/incomplete understanding of these concepts.

I hope this didn't get too long-winded.

Thanks.

Best Answer

You shouldn't delete the events from your event store. These represent something that happened. If something happens now, then you should know it too, therefore add an event that will force your aggregate to go back to some previous state. That's a pity to delete information from your database.

think about the example of the cart from greg young and the removed items. May be tomorrow the information of compensating action might be of any value..

As for the saga, every thing is correct, as far as I know myself. You should think of the saga as of a state machine. It does only that.

It is a Command the saga is issuing to tell the aggregate to do something. Of this action there will be an event. This event might be the corrective action you need, or might need to be denormalised in a view so that some user will see it to decide what to do.

It depends on your business rules. Either, there is an easy fix : the aggregate root knows that in such case , you do that, or the choice is too complex to be done programmatically ( development cost are too high) and therefore, you might propose this to some user, who might choose between different action. Everything depend on the context of the compensating action. This is pure business rules. What should we do in this case or that case. This is something to ask your domain expert, and then choose with him, if it is better to develop an automatic solution or if the solution is to ask the user Ronald R., because he is the one to answer this question usually.

Related Topic