2

I am building an application and trying to embrace Domain Driven design principles, CQRS and event sourcing.

We are having two applications one for reading and another for writing. The write application is using a event store data base. And after it completes a transaction on a aggregate, it publishes a domain event to the read application.

There is a need for both the read and write applications to get events and build the aggregate to its current state by applying the events.

  1. The write application does this in the repository when a aggregate is queried by the id.
  2. The read application does this in the domain event handler when it receives the event from the write application.

There is a lot of common code between the read application and write application especially for the building the aggregates and applying the events on aggregates.

The problem I am trying to solve is remove the duplicate code. I had some options in my mind, I have a fair understanding of the merits and demerits of these options. I am not sure if I am overlooking at something. Also trying to understand if there is no other easier way to do it. The options I have are as below

Option 1: Have a shared library that is used by read application and write application. Now there will be 3 code repositories. The independent deployability is partly lost here.

Option 2: Have one common code base for read and write application. Have two deployments for read application and write application by having different configurations. The independent deployability is lost here.

Option 3: The write application has the aggregate's state building logic. When the read application gets any event about an aggregate. It queries ( via http) the write application and builds the models

Option 4: I am doing something fundamentally wrong in CQRS. That is the reason for duplicated code. So I need to revisit concept.

  • 3
    Why should there be a large amount of duplicate code? Both sides will need to fetch events but that's it. Your aggregates and your read projections should not necessarily be the same and if they currently are that's probably because your model is currently very simple and trying to share or reuse them is probably premature as they will more than likely diverge over time. – Ant P Sep 26 '19 at 12:05
  • Makes lot of sense. Realised building unnecessary read models. Thanks @ant p – Nachiappan Kumarappan Sep 26 '19 at 14:15
6

It's pretty natural to have some duplication between the Command side and Query side, starting with knowing the same essential Events and payload structures. While standard structures might still be ok, there are many reasons you should not look to DRY or remove code duplication between them.

A Google search for "DDD and DRYing code" brings up many blog posts that make a valid case for not optimizing like this at the code level. I have burnt my fingers doing this too, introducing complexity accidentally by coupling similar-looking, but conceptually different code segments.

Consider the following three arguments:

  • Complex DDD implementations will end up having one write representation but multiple read representations. These representations will be similar but built for vastly different requirements (for UI views or for reporting or for performance). You don't want to mix these concepts because they are expected to get fully fleshed out and grow in complexity over time.
  • You should keep code decoupled even between read models, to allow complexity to increase in your system without creating regressions or having a snowball effect.
  • One of the underlying assumptions in CQRS is that the read side will scale differently compared to the write side. Social networks are good examples where the two sides different in orders of magnitude. So you actively want to keep the codebases independent and separated for ease of deployment and scaling. Even when you have the same codebase, you should keep them decoupled as much as possible, and they should only interact with each other in the form of domain events.
| 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.