Into the darkness of ViewModels Lists Composition
We had a first look at what problem ViewModel Composition is designed to solve, then we analyzed what it means to compose a single item, using a Product as sample model. It’s now time to start exploring what it means to compose a list of Product ViewModels.
Looking for a ViewModel Composition framework? Take a look at the open source ServiceComposer.AspNetCore.
Why can’t we just…?
The trap of composing lists of ViewModels is that we cannot apply the same technique used for single items. If we have a list of items, where each item in the list is composed by data coming from multiple services, we cannot compose each item. Composing each item one by one means that our list will turn into a scary SELECT N+1
type of thing, but worse since it’ll be over HTTP
.
Composing a list is a matter of doing 3 steps:
- Step 1: get the keys of the items that should be included in the list
- Step 2: get all the data for all the items in the list
- Step 3: compose
This reduces the number of HTTP calls to the minimum required and also reduces the load on our datastore since we can retrieve the details we need in one request (for each service).
Business ownership
Let’s continue using the Product sample used in the previous article. We now need to display a list of Products. The first thing, looking at the above steps, is to retrieve the keys of the items we want to display/compose.
Who should perform that?
We have identified 4 different services so far:
- marketing owns name and description
- sales owns price
- warehouse owns availability
- shipping owns shipping options
Marketing should be really named product catalog, you know…naming is hard :-)
Continuing with our sample we could say that Marketing/Product Catalog is the one that makes decisions about the existence of a Product. Which means that from the business perspective, Marketing owns the concept of a Product.
In this case Marketing is the perfect place to ask for the list of Products we want to display. Marketing will be the one handling the /products
request:
The Marketing component, or RequestHandler
, will return a list of products, something similar to:
[{
key: 'products/1',
name: 'Banana Protector',
description: 'Benran Outdoor Travel Cute Banana Protector Storage Box (Pink, Green, Yellow, Pack of 3)'
},{
key: 'products/2',
name: 'Another prodcut',
description: 'Another product description'
}]
At this point Marketing is ready to notify all other interested parties that some products have been loaded:
The Marketing RequestHandler
publishes an in-memory event to notify that some products have been loaded. Sales and Shipping are interested in augmenting those products, thus they receive the ProductsLoaded
event, that contains all the keys of the loaded products.
Once all components have received the event they go to their respective backends to retrieve the information related to all the loaded products, in a single roundtrip.
Once the information has been retrieved, the last step (i.e. the composition) is not that different from the Single Item Composition scenario:
It’s as simple as an in-memory foreach
iterating over the loaded product, giving each interested party the opportunity to augment each product with their data.
Conclusion
Composing lists of items sounds complex and scary; we don’t want to fall into the SELECT N+1 trap over HTTP
. Looking deeply into the problem however, first we can identify who is the service responsible to get the list of items to display keys. Once we have all the keys we can apply an approach similar to the one used for the Single Item Composition and retrieve data in batches to optimize server-side communication.
It’s probably time to dive into some code. To be continued…