Ivelin Matev
Ivelin Matev

Reputation: 382

Common service for READ and WRITE - CQRS + DDD

Hey I have an aggregate root with some properties which need to be calculated - totals. These properties are not saved, but are needed to fill a readDto while seeding and an Event for the EventStore when the aggregateRoot is created or updated.

Is it a good practice to have a COMMON service between the read and the write part, which will calculate these totals and provide them to dtos or events or wherever they are needed ?

Upvotes: 1

Views: 696

Answers (1)

Ruben Bartelink
Ruben Bartelink

Reputation: 61795

to have a COMMON service

It's permissible to use any valid technique you'd normally use to effect the DRY principle (but bearing in mind to temper this with the Rule of three).

Sometimes, this means copying a file of helpers between the write/decision process and a projection service. Sometimes you might even compile those into a single helper library. Sometimes is a piece of code in a dynamic language that can be run against an instance of an event (or series of events being folded) hydrated in the context of the decision process, the projection service or a reader process.

There is no fundamental law that says there must be exactly one thing (a compiled piece of code running as single service) which owns the rule - for starters, what happens if you want to deploy an update to that service without downtime?

In short - there is no hard and fast rule; any such a one size fits all prescriptive recipe would have hundreds of exceptions. A bit like an enterprise wide universal data model ;)

I am not that afraid of breaking DRY principle by using a single service.

My real concern is about if using common read/write stuff is against the CQRS pattern.

Quite often this can be legitimate - readers and writers both observe the stream of events in order to infer ('fold') a rolling state. Readers may be exposing contextual information which can be used to drive 'users' to formulate commands representing desired actions/state transitions, which necessarily have a degree of overlap. The key thing is that decision making itself should only live on the write side (bu this fits well with the general principle that a command should normally not result in feedback - typically it should be idempotently processable with any validation etc. being a fait accomplit security-driven double check)

And secondly if using logic in the read part is against the CQRS pattern.

One typically agreed no-no is having conditional logic in the fold which maintains the rolling state - this should be simple mechanical accumulation.

For a projection and/or denormalizer which is maintaining an eventually consistent read-only view based on observing the events will often be using overlapping simple projection logic. If that logic gets complex, involves transactions etc., that's a design smell though - if the Events represent what's going on naturally and not contrived, they should tend to be relatively straightforward to map/project - you should really only be 'indexing' them or laying them out in a form appropriate for the given necessities of the reader.

If you're ending up with complex flows in the projection system, that's a sign you probably have multiple different readers and should perhaps consider separate projections to that end (i.e. kinda like the Interface Segregation Principle)

Upvotes: 1

Related Questions