2

We have an existing CRUD-based system, but are hitting a number of pain points keeping the data organised for all the various views that are increasingly required of it. I'm assessing whether splitting the read and write models (i.e. CQRS) might provide some benefit here.

The system handles the product catalogue for an online store. Aside from adding and removing products to/from the catalogue, it is also possible to update an existing product's entry in the catalogue. Such updates could happen for a number of reasons, including:

  • to correct erroneous info;
  • to improve marketing presentation (new product names, descriptions, images, categorisation);
  • to effect new pricing; and
  • to effect changes to taxation.

Such updates are not currently distinguished by the existing CRUD system, but the intent behind them is of interest to other systems in our domain (e.g. marketing would like analyses of how each type of update correlates with sales data; legal would like to track what erroneous information has been corrected and when) although for the product catalogue system itself that intent is not very interesting.

My first thought is therefore that if we move from our CRUD system, we could introduce a task-based UI in which updates to the catalogue would be distinguished by different user actions—and these would in turn each give rise to a corresponding CQRS command:

  • CorrectErroneousInfo
  • ImproveMarketingPresentation
  • EffectNewPricing
  • EffectChangesToTaxation

But what events are we interested in? Coming from the existing CRUD system, I find it hard to escape thinking that the product catalogue system will want something like:

  • ProductNameChanged
  • ProductDescriptionChanged
  • ProductAddedToCategory
  • ProductRemovedFromCategory
  • ProductPriceIncreased
  • ProductPriceDecreased

But these events do not convey the original intent behind each update: they appear to be very "CRUD-like" in that they merely state that particular properties were updated without stating why (the first two are the worst offenders, but they all have this nature to some extent). Furthermore, a single command could clearly trigger multiple events—and the marketing team would like to maintain knowledge of which events originated from a single action. Should the events carry fields that relate them to the originating command? Coupling events to commands in this way feels wrong.

An obvious alternative would be just to raise one event for each command, for example:

  • ErroneousInfoCorrected
  • MarketingPresentationImproved
  • NewPricingEffected
  • ChangesToTaxationEffected

But then understanding how these "log-like" events have modified the domain model is much more complicated: one will essentially have to rerun the command, albeit infallibly. Whilst on some level this is akin to event sourcing, it feels like the tail is wagging the dog: our domain events are being determined by our commands, rather than by the facts our system needs to record.

A third option would be to do both: raise both "CRUD-like" events for the product catalogue, and also "log-like" events for those who wish to perform such analyses. But would this not be duplicating the same information across multiple events? I generally like to minimise duplication, but is it acceptable here? Is the logging of (successful) commands as domain events (in addition to more specific events to which those commands gave rise) a common pattern?

Is there some insight I'm lacking here? Should I be approaching this differently altogether? Or are one (or all) of the approaches outlined above actually reasonable?

1 Answer 1

1

the marketing team would like to maintain knowledge of which events originated from a single action.

First, ask yourself - do they really want this literally? On the abstraction level of "events"? Or do they just want a log of the original commands, maybe with the information who initiated it, and when / in which order? Note each command needs to have parameters which determine the kind of state change to the system in an unambiguous way, which should be part of any log. For example, a command like CorrectErroneousInfo needs to carry parameters which attribute has to be corrected and to which value. So when the log also gets these parameters, maybe that is sufficient for your stakeholders.

On the other hand, if you really want traceability at the event level, why not? If there is some not-so-obvious logic about how a specific command initiates a certain kind of price change, I would not hesitate to log the incoming commands in some database table or log file1, and associate each event with a reference to the related command object (or its ID)2. It is not uncommon in event-based systems to give events some means to determine their sender.

I would recommend to analyse this by looking at the data flow backwards:

  • first find out how the collected information is going to be used by your stakeholders, and how it should be presented to them

  • from these, derive the technical requirements how detailed the information needs to be collected and stored

  • and from here you can make a decision how to design your commands, their parameters and the events to serve these requirements.


1: Also known as Op Log

2: Also known as Correlation ID

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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