Abstract Away Event Sourcing?

This is a question that has been raised in our team with respect to our attempt to base a microservices architecture around EventStore.

I am currently working on a ServiceStack plugin that will act as a wrapper around the EventStore client. A colleague has suggested that we try, as much as possible, to abstract the details of persisting and rehydrating an aggregate from the development experience for each microservice and, so, hide all of this within the the plugin so that the developer does not need to know that the state of an aggregate has been built up by replaying events (and snapshots).

Now, I can agree with this aspiration with regards to stateful data storage: whether an aggregate is persisted to a relational database (possibly by means of an ORM) or to a document database is, to some extent, an implementation detail. State is persisted and the mechanism of storing it - PostgreSQL, RavenDB, etc - is arguably something that should abstracted away as much as possible.

When it comes to event sourcing, however, I do feel that we’re not in Kansas anymore. Event sourcing isn’t just a storage mechanism but, rather, a paradigm that possibly reaches into the heart of our domain logic. An event is not just an implementation detail but actually a unit of business behaviour.

The examples of event-sourced aggregates that are on the internet (such as here, here, or here) make events the centre point of their (internal) behaviour. For us to attempt to abstract away event sourcing, by hiding how state is achieved through applying events, would seem to me to be an attempt to impose a state-based model on top of a much richer model.

Anyway, I’d be interested in what your thoughts are. Does it make sense to keep your domain logic (and application services layer) as free as possible from the event paradigm?

I’d argue that even the difference between documents and rdbms is difficult to abstract away without leaks.

I have tried this by building a historical record in SQL ( with null-able fields) to keep the SQL guys happy but the end result was a lot of data and issues and a very leaky abstraction … with poor domain logic. The previous system had different data repositories eg IDAL etc and i think that model is poor and completely out of date - unless you have a genuine business reason .

Some services work well with CRUD others have complex domains and logic … Horses for courses especially so for services - dont try to make all services event sourced.


True. I agree that an abstraction over any data store tends to be quite leaky in that there are certain things you end up needing to do in your ‘POCOs’ for your system to play nice with the database/ORM.

I make you correct. Using event sourcing you save the events which can then be used to rebuild the aggregate as apposed the serialization the aggregate directly; so they are two different things. You can of course put an abstraction around the storage and retrieval of events. Whether you decide to do this or not then depends on how you feel about abstractions. Personally I think that most of the time that the store medium is abstracted away is over-architecture and a violation of YAGNI: how many times have you actually changed your storage medium for a production application?

Thinking about this a bit more, I wonder if part of the benefit of modelling business behaviour as events (which in a sense they are in reality) is that we then have a domain model that lays a greater emphasis on immutability? If state is not manipulated directly but only as a result of an immutable event then we may have an extra safeguard against the subtle bugs that direct manipulation of state can bring.

However, that’s really more of a question on my part rather than the result of observation.

Immutable domain models are nice, especially in a non-oo language like F# :slight_smile:

I’m not even sure what abstraction would cover both “update this entity with these values” and “here is a set of changes that took place”.

At any rate, IPersistence is the wrong vector for abstraction.

Instead, model the use cases.

Perhaps one case is best handled with graphs, another documents, another relational [also one OO, another functional, etc].

IPersistence isn’t nimble enough to change per use case.

If it turns out a graph model wasn’t a good idea, you probably have a lot bigger problems than swapping out the connection string.

ISoftware is a terrible abstraction.