Plyto
Plyto

Reputation: 751

Event Sourcing - Displaying older data

This is a noob (I think) Event Sourcing question.

As an example we have:

Shoemaker Bob has:

Say we have a "shoe_repair_order" (Aggregate Root?)

Question: How do we design the Event-Sourced system to show the old addresses for orders?

OR

Upvotes: 1

Views: 710

Answers (4)

TomW
TomW

Reputation: 4002

Here are a few options:

  1. In your shoemaker read model, include the list of addresses including the dates they became active. This way, when you process an order event in your order projection, you query the shoemaker read model and get the address that's correct for the order date (this will work even if you are rebuilding the projection later). The disadvantage of this are coupling between the two views (order projection now depends on shoemaker's query API, so you need to make sure the shoemaker projection is up to date and available)
  2. If you have a way of subscribing to multiple event streams so you receive events in approximate global order, in your order projection also handle shoemaker address events (creation and updates). Keep a mini table of shoemaker to 'current' address (meaning current as of the events you have processed, allowing replays to work correctly). Then when handling order creation events, just lookup the current address in the table and copy it into the order view. This is a bit more code, but avoids dependencies between views and avoids the need for address history in the shoemaker view (although you might need that anyway for other reasons).
  3. Make the shoemaker address part of your order domain model. It will need to be included in the order creation command (possibly by command enrichment in the controller layer, looking it up in the shoemaker read view). This doesn't seem necessary since the order doesn't have a concept of the shop address that's separate from the shop's concept (this is different from, say, delivery address, which is usually a per-order item in some way).

Upvotes: 0

Kanishk
Kanishk

Reputation: 431

The answer to your problem certainly depends on how you have defined your domain models (specifically how your Aggregates are defined).The way I would approach this problem is to have two aggregates:

  • ShoeMaker Aggregate (which in your case stores all the information like name of the shoemaker business, info about this business' owners, list of all the addresses for this shoemaker where each address can have information like email, phone number, and a bool field called current which can be true for the current address. I imagine this AR would have a command called - "ChangeShoeMakerCurrentAddress" which would raise an event called "ShoeMakerAddressesChanged".

  • Order Aggregate (which would have all the information about an order like customer name, price, details, order date, delivery date etc.).

Let's say we have a read-model called "ShoeMakerOrderReadModel" which can subscribe to events raised by ShoeMaker Aggregate and Order Aggregate. This read-model listens to events and denormalize them into a POJO/POCO object. This POCO/POJO model can have a list of shoemaker addresses (where each address can have information like email, phone number, and a bool field called current which can be true for the current address.) This AR can definitely subscribe to "ShoeMakerAddressesChanged" events from ShoeMaker Aggregate and then update the list of shoemaker addresses.

I hope this helps!

Upvotes: 1

Constantin Galbenu
Constantin Galbenu

Reputation: 17683

The answer is very simple thanks to CQRS: you must not listen to BusinessMovedToANewLocationEvent in the OrderDetailsReadModel. You just lookup and store only once the current Business address in the Order details in this Read model when the OrderPlacedEvent happens.

In this way you don't have to include any Address value object into the event. The Read model does all the work.

You could listen to the event, if you need for other reasons, but just don't update the address. Fir example, the Read model could be even smarter and additionally keep an addressChangedInTheMeanTime boolean flag in order to tell Alice that the Address that she sees is an old one but thus depends on your business needs.

Upvotes: 0

Aaron M. Eshbach
Aaron M. Eshbach

Reputation: 6510

I think the best way to do this will ultimately depend on how you've designed your Domain Model, but here's how I would approach the problem:

We need to represent Addresses in our Domain Model. This means, addresses will either be Value Objects, Entities, or Aggregates. Of the three, an Address could really only be a Value Object or an Entity in this Domain, since we are a shoe repair application and not an address book. Entities have certain properties, such as being distinguished by their ID, and certain restrictions, like only being part of one Aggregate, that Addresses don't seem to meet. Therefore, I would see an Address being a Value Object in this Domain.

When defining the OrderLocationAdded event on the "shoe_repair_order" Aggregate, you need to decide whether to include the full details of the Address on the event, or use a reference to the Address. Since the Address is a Value Object (it is defined by its data, not by an ID), the answer would be to include the Value Object on the event. This way, when you replay the events to build the current state of the order, it will still have the details of the original address.

If you want to also display the new address on the order, you can use another event, such as BusinessMovedToNewLocation, with the details of the new address, and add this to the order. This event would not replace the original address, it would just allow you display the informational message that the business is now located at a different location.

Upvotes: 1

Related Questions