Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model sort order for many-to-one across two aggreagate roots

Take the domain proposed in Effective Aggregate Design of a Product which has multiple Releases. In this article, Vaughn arrives at the conclusion that both the Product and Release should each be their own aggregate roots.

Now suppose that we add a feature

  • As a release manager I would like to be able to sort releases so that I can create timelines for rolling out larger epics to our users

I'm not a PM with a specific need but it seems reasonable that they would want the ability to sort releases in the UI.

I'm not exactly sure how this should work. Its natural for each Release to have an order property but re-ordering would involve changing multiple aggregates on the same transaction. On the other hand, if that information is stored in the Product aggregate you have to have a method like product.setRelaseOrder(ReleaseId[]) which seems like a weird bit of data to store at a completely different place than Releases. Worse, adding a release would again involve modification on two different aggregates! What else can we do? ProductReleaseSortOrder can be its own aggregate, but that sounds downright absurd!

So what to do? At the moment I'm still leaning toward the let-product-manage-it option but what's correct here?

like image 425
George Mauer Avatar asked Jul 28 '14 18:07

George Mauer


1 Answers

I have found that in fact it is best to create a new aggregate root (e.g., ProductReleaseSorting as suggested) for each individual sorting and/or ordering purposes. This is because releaseOrder clearly is not actually a property of the Product, i.e., something that has a meaning on a product on its own. Rather, it is actually a property of a "view" on a collection of products, and this view should be modeled on its own.

The reason why I tend to introduce a new aggregate root for each individual view on a collection of items becomes clear if you think of what happens if you were to introduce additional orderings in the future, say a "marketing order", or multiple product managers want to keep their own ordering etc. Here, one easily sees that "marketing order" and "release order" are two different concepts that should be treated independently, and if multiple persons want to order the products with the same key, but using different orderings, you'll need individual "per person views". Furthermore, it could be that there are multiple order criteria that one would like to take into account when sorting (an example for the latter would be (in a different context) fastest route vs. shortest route), all of which depends on the view you have on the collection, and not on individual properties of its items.

If you now handle the Product Manager's sorting in a ProductReleaseSorting aggregate, you

  1. have a single source of truth support for the ordering (the AR),
  2. the ProductReleaseSorting AR can enforce constraints such as that no two products have the same order number, and you
  3. don't face the issue of having to update multiple ARs in a single transaction when changing the order.

Note that your ProductReleaseSorting aggregate most probably has a unique identity ("Singleton") in your domain, i.e., all product managers share the same sorting. If however all team members would like to have their own ProductReleaseSorting, it's trivial to support this by giving the ProductReleaseSorting a corresponding ID. Similarly, a more generic ProductSorting can be fetched by a per-team ID (marketing vs. product management) from the repository. All of this is easy with a new, separate aggregate root for ordering purposes, but hard if you add properties to the underlying items/entities.

like image 115
Alexander Langer Avatar answered Dec 02 '22 02:12

Alexander Langer