I am reading Vaughn Vernon's series of articles about effective aggregate design.

On the subject of deciding between transactional vs eventual consistency, it states the following:

Discussing this with Eric Evans revealed a very simple and sound guideline. When examining the use case (or story), ask whether it's the job of the user executing the use case to make the data consistent. If it is, try to make it transactionally consistent, but only by adhering to the other rules of aggregate. If it is another user's job, or the job of the system, allow it to be eventually consistent. That bit of wisdom not only provides a convenient tie breaker, it helps us gain a deeper understanding of our domain. It exposes the real system invariants: the ones that must be kept transactionally consistent. That understanding is much more valuable than defaulting to a technical leaning.

This advice confuses me. Large parts of the software that I've written in my career were useful to the end user because it freed them from the responsibility of keeping data consistent. As a result of this, users expect to observe a consistent state all the time, without delay. To a customer paying for a consistency-achieving software, every inconsistent state observed is a bug.

In my experience, when submitting a request, users would usually rather wait a bit and observe a consistent state than have an immediate answer that is changed later on in order to be consistent.

Inversely, when it is the user's responsibility to achieve consistency, our system would warn him about inconsistencies, but allow him to eventually achieve consistency by executing several smaller commands, instead of requiring the user to do so with one giant command.

Why are Evans and Vernon recommending eventual consistency when it is the system's job to get consistency right and transactional consistency when it's the user's responsibility?

Could you point out example constraints and use-cases where transactional or eventual consistency are considered suitable according to the above rule?


There's a fundamental principle about microservices that cannot be denied. Microservices are independent entities; if you are building a system that is based on microservices, then by definition you cannot have them depend on a central data authority (like a relational database), because your microservices would no longer be independent. Giving each microservice its own independent data store means that you must settle for eventual consistency.

It doesn't have to be that way, of course. You could certainly tie all of your "microservices" to a central data store and get transactional consistency everywhere; the Actor Model does this all the time. I just don't know that purists would call that a microservice architecture.

I think Vernon Vaugn's point is that the User is generally not responsible for achieving consistency; the system is. Consistency is a non-functional requirement; it doesn't take the form "As a User, I want to [perform some action] so that I can [achieve some goal]."

That said, users do expect some interactions (like moving money from one checking account to another) to be transactionally consistent, not eventually consistent. You don't want a bank customer to be asking "where has my money gone," only to have it show up in the target account hours later.

| improve this answer | |
  • Thanks, this certainly helps. Followup question: "Settling for eventual consistency" sounds a lot like giving up transactional consistency in order to gain something else instead, I'm assuming mainly unlimited scaling. In my domain I think that scaling is actually much less of a concern than immediate consistency... Is there something else that would motivate the use of eventual consistency over transactional consistency? – blubb Jun 1 '18 at 18:29
  • Not that I know of. – Robert Harvey Jun 1 '18 at 18:50

This advice confuses me.

Not your fault.

I suspect that he's trying to express ideas similar to those of Udi Dahan in When to avoid CQRS; a distinction between collaborative and non-collaborative use cases.

Consider a cheque register; a ledger of entries describing each negotiable instrument drawing against an account. Each entry would typically include the unique identifier for the cheque (the account it draws against is usually implicit -- each register is associated with a single account), a memo field, the amount, and a running balance.

That running balance is derived from the details of the cheque itself, and the previous balance entry in the register (state). There's not typically surprise entries from other's, or congestion from trying record several cheques simultaneously. So it's reasonable to assert an invariant that the running balance should match the accumulated total of the entries.

On the other hand, getting the register balance to match the account balance is more complicated - the account balance is going to depend on other collaborators depositing the cheques, transferring the funds, crediting the account. Thus, the work of trying to reconcile the running total in the register with the account total can (and should) be deferred until later.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.