1

I just wanted to ask you guys if this CQRS architecture is too complex or am I doing something wrong? So just to explain picture below:

After one bounded context emits event (SomeEventHappended = DTO) that something happened, this event is received in another bounded context.

  1. After Event is received in another bounded context by saga (aka process manager) and after it decides which command to issue, this event is mapped to Command message.
  2. After saga sends command, this command is received by Command handler. Command handler will load AggregateRoot from repository and call some method on it. Since domain method that is called expects domain objects (and not command DTO), I have to map again -> command to domain objects.
  3. After method on AggregateRoot is invoked and since I would like to use event sourcing, I have to map data from this domain objects to DomainEventForEventSourcing which is also new DTO. Then I can call when(DomainEventForEventSourcing event) method on AggregateRoot.
  4. When method reacts on DomainEvents (either when rehydrated from event store or when received for the first time) - by calling when() method, we need again to map the data, but this time between DomainEventForEventSourcing DTO and domain objects.

Just one note - I'm using pretty complex DTO's in this case and it is not just 2-3 Integer or string variables. Usually all samples keep this things simple but when you start to make real world apps, it doesn't seem so easy.

So in total 4 mappings happening each time. Maybe it is legit but maybe I'm doning somethin worng...

enter image description here

  • 1
    What do you mean by "OK?" – Robert Harvey Nov 22 '16 at 19:40
  • I mean is it common practice. Are there any known side-effects etc. – Marko Kraljevic Nov 22 '16 at 19:52
  • 2
    I don't see how we can answer that. We don't take polls to determine how popular various computing techniques are. If it's very useful to you, but not commonly used, will you summarily discard it? That doesn't seem very exciting to me; nobody's ever been innovative or creative by taking the "common" approach, or being a follower. – Robert Harvey Nov 22 '16 at 19:55
  • 1
    @MarkoKraljevic while you do not use the term in your question, you are looking for a "best practice." Please read Why is asking a question on “best practice” a bad thing? and its accepted answer. – user22815 Nov 22 '16 at 19:57
  • 1
    This question is entirely appropriate for this website. If it gets closed, ping me and I'll vote to reopen it immediately. – Jim G. Nov 23 '16 at 19:11
0

I just wanted to ask you guys if this CQRS architecture is too complex or am I doing something wrong?

The basic pattern that you are sketching here is normal.

The justification for the transformations is that you are sending messages across a process boundary; the messages are part of the API which does not necessarily correspond 1:1 with your domain model(s).

For instance, one of the properties you want to have is the ability to deploy new implementations of the bounded contexts independently. So you should expect that the message (the event) shared between BCs to have an implementation agnostic representation (the DTO).

Saga isn't really the right term to use here - the term actually means something different from the normal thing that you are doing here (saga was a popular term in the literature, because the earliest innovators were confused on this point). Current terminology is that a process manager is responsible for listening to events and dispatching the commands.

The term "map" isn't quite right -- any given event may result in zero or more events, depending on the complexity of the process in question.

If the process manager and the aggregates are part of the same deployable unit, then you don't necessarily need to bounce the command through a DTO; the process manager can use the model to describe the command, and send it to the command handler directly (vs sending a API message across a process boundary to the command handler). In other words, the process manager doesn't have to be sending commands to the same command handler that would be used by an external process.

When the aggregate accepts the command, the events that it produces and applies make sense to stay in the language of the model -- no DTO needed here. However, when you write that event to a persistence store or to a message bus, you are likely to be crossing a process boundary again, and you will want to use a stable representation instead. (In particular, you want the persistence store to have a stable implementation so that you can replace the implementation of the aggregate itself).

In short: the motivation for using the DTOs is to have a stable API, so that you can deploy units independently. You are typically going to be performing the transforms to/from the DTO representations at the boundaries of your processes.

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.