Does a CQRS project need a messaging framework like NServiceBus?
Asked Answered
G

2

4

The last 6 months learning curve have been challenging with CQRS and DDD the main culprits.

It has been fun and we are 1/2 way through our project and the area I have not had time to delve into is a messaging framework.

Currently I don't use DTC so there is a very good likely hood that if my read model is not updated then I will have inconsistency between the read and write databases. Also my read and write database will be on the same machine. I doubt we will ever put them on separate machines.

I don't have a large volume of messages in my system so my concern is more to do with consistency and reliability of the system.

So, do I have to put in a messaging framework like NServiceBus (even though both read and write databases are on the same machine) or do I have other options? Yes there is learning curve but I suppose there would be a hell of a lot to learn if I don't use it.

Also, I don't want to put in a layer if it is not necessary

Thoughts?

Goral answered 14/10, 2012 at 8:30 Comment(0)
J
6

Currently I don't use DTC so there is a very good likely hood that if my read model is not updated then I will have inconsistency between the read and write databases.

Personally, I dislike the DTC and try to avoid it. Instead, it is often possible to implement a compensation mechanism, especially for something like a read model where eventual consistency is already acceptable and updates are idempotent. For example, you could implement a version on entities and have a background task which ensures versions are in-sync. Having a DTC will provide transactional retry functionality, but it still won't solve cases where failure occurs after retries - you still have to watch the error log and have procedures in place to deal with errors.

So, do I have to put in a messaging framework like NServiceBus (even though both read and write databases are on the same machine) or do I have other options?

It depends on a few things. What you often encounter in a CQRS system is need for pub/sub where several sub-systems publish events to which the query/caching system subscribes to. If you see a need for pub/sub beyond basic point-to-point messaging, then go with something like NServiceBus. Also, I wouldn't immediately shy away from using NServiceBus even if you don't need it for scalability purposes because I think the logical partitioning is beneficial on its own. On the other hand, as you point out, adding layers of complexity is costly, therefore first try to see if the simplest possible thing will work.

Another question to ask is whether you need a separate query store at all. If all you have is a single machine, why bother? You could use something simpler like the read-model pattern and still reap a lot of the benefits of CQRS.

Jasmin answered 14/10, 2012 at 16:25 Comment(1)
Thank you so much for the info. I'll have a look at the read-model pattern. You mentioned version on entities, you mean on the aggregate roots or on events?Goral
H
5

Does a CQRS project need a messaging framework like NServiceBus?

The short answer: no.

It is the first time I hear about the 'read-model pattern' mentioned by eulerfx. It is a nice enough name but there is a bit more to it:

The general idea behind the 'query' part is to query a denormalized view of your data. In the 'read-model pattern' link you will notice that the query used to populate the read-model is doing some lifting. In the mentioned example the required data manipulation is not that complex but what if it does become more complex? This is where the denomalization comes in. When you perform your 'command' part the next action is to denormalize the data and store the results for easy reading. All the heavy lifting should be done by your domain.

This is why you are asking about the messaging. There are several techniques here:

  • denormalized data in same database, same table, different columns
  • denormalized data in same database, different table
  • denormalized data in different database

That's the storage. How about the consistency?:

  • immediately consistent
  • eventually consistent

The simplest solution (quick win) is to denormalize your data in your domain and then after saving your domain objects through the repository you immediately save the denomarlized data to the same data store, same table(s), different columns. 100% consistent and you can start reading the denormalized data immediately.

If you really want to you can create a separate bunch of objects to transport that data but it is simpler to just write a simple query layer that returns some data carrying object provided by your data-access framework (in the case of .Net that would be a DataRow/DataTable). Absolutely no reason to get fancy. There will always be exceptions but then you can go ahead and write a data container.

For eventual consistency you will need some form of queuing and related processing. You can roll your own solution or your may opt for a service bus. That is up to you and your time / technical constraints :)

BTW: I have a free open-source service bus here:

Any feedback would be welcomed. But any old service bus will do (MassTransit / NServiceBus / etc.).

Hope that helps.

Hesitancy answered 16/10, 2012 at 6:6 Comment(3)
Well completed answer. Interesting project (Shuttle) - I'm now looking into it.Vidal
If I use different tables for my denormalised data (your second option), am I right to say that the domain persistence and the denormailised data will be in the same transaction?Goral
@JD: that would depend on how consistent you need your data to be. If it is absolutely necessary to have it 100% consistent (such as, maybe, an account balance) then yes; if your query data can be stale for a while then you do not need to use the same transaction.Hesitancy

© 2022 - 2024 — McMap. All rights reserved.