3

I'm working on an invoicing web application which uses event sourcing and CQRS.

I have 2 denormalizers for different queries (one for a list of invoice summaries, and one for a single invoice with full details). I find it strange I need to copy a lot of the logic for these 2 denormalizers - for example, listen to events that change the total, subtotal, taxes etc.

I ended up passing the aggregate itself, which contains the real calculated data, on the messaging bus instead of just the events and had the denormalizers listen to it instead of the events.

This made it simpler for me, but seems different from the pattern. This approach was not mentioned in any of the articles I've read.

I liked the idea of passing just the events on the bus and having each denormalizer react to what it needs, but in practice it felt more cumbersome.

I'd love to hear what you think.

Thanks for your help!

amitayh
  • 770
  • 1
  • 8
  • 19
  • "copy a lot of the logic" : what logic exactly ? Can you give an example ? – guillaume31 Aug 05 '15 at 07:59
  • @guillaume31 Sure, for example - the user adds tax to the invoice. I have an event TaxAdded(rate: Double), which changes the invoice total. I want to update both the summary and the detailed views by adding the tax amount to the invoice total. By passing the aggregate itself I can simply do the calculation once (in the aggregate), and update both views based on that calculation – amitayh Aug 05 '15 at 08:36
  • 3
    You could also simply do the calculation once in the aggregate and only include the data that changed along with the event (e.g. the new total instead of the tax rate). No need to pass the whole aggregate. – guillaume31 Aug 05 '15 at 10:00
  • This seems a bit awkward to me as the event that actually happened in the system is the tax rate change. If tomorrow I want to change the logic behind the total calculation, I will still have events in the event store with the old logic. The total is supposed to be derived from current state of the aggregate and I cannot fully anticipate what related events I'll have in the future. Hope I'm making myself clear :) Thanks for your help – amitayh Aug 05 '15 at 10:41
  • But when looking at old invoices, you want the total that was charged at the time, not the total computed by current calculation logic, right ? – guillaume31 Aug 05 '15 at 11:06
  • 1
    I guess you have a point. I should probably add an event with the calculated (subtotal, total, taxes etc) fields, and publish it when some other event that affects these calculations occurs – amitayh Aug 05 '15 at 11:57

1 Answers1

2

As suggested by guillaume31 in above comment, you may simply enrich your domain model with special events such as NewTotalComputed. Depending on the number of events, this might however soon clutter your domain model.

Alternatively, you can refactor the computation logic into a special strategy class that is used from both the domain model (aggregate root) and the read model.

Alexander Langer
  • 2,883
  • 16
  • 18
  • 1
    True. But I was not necessarily implying a new event. You can keep `TaxAdded` which is IMO more intention-revealing, and send NewTotal instead of/ in addition to TaxRate along with it. – guillaume31 Aug 05 '15 at 10:16