Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Domain Driven Design: How to model relations that are large but have few behaviors

Let's say I have two entities User and Item. The sole behavior in the domain between these two entities is that a user can like an item. Since there is no restriction on how many items a user can like, this many-to-many relation can be large.

I don't think it makes sense performance-wise to have User contains a list of items they liked in its model or the other way around, since I'll have to load a potentially large collection of items in order to add just one item. From domain design point of view, it also doesn't make sense to me to have either entity reference the other in their fields as no behavior require the presence of a collection of items or users.

I do need to keep this relationship as the UI needs to display a list of items a user liked and a list of users that liked an item. The requirement can be served by a read model but I still need a domain concept to capture this relationship so that it can be persisted.

One way I can come up with is to introduce a relation type of aggregate, say UserLikeItem, and have method user.like(item) return an instance of UserLikeItem which I can then use UserLikeItemRepository to persist.

Is this a valid solution? What is the natural way in DDD to model this type of large but non-behavioral relations?

like image 261
Ziju Feng Avatar asked Nov 01 '22 15:11

Ziju Feng


1 Answers

Since I ran into this scenario some time ago, here's my take. User and Item are part of different aggregates they don't know/care about each other (even if an item has an userId). A "Like System" (LS) is a different aggregate tracking likes from who to what.

LS doesn't really care about User or Item either, although since I can't see of a case where something else other than a user can like something, I can say that Like will always imply a userId (not the whole User concept) and a subject (Item, VIdeo, Picture, Post etc).

LS simply keeps an association of user Id and another itemId of a certain type (that can be a string, if you want that LS to not be coupled to what an Item is). Every time a user like something a command is issued: RegisterLikeForItem { UserId, ItemId, ItemType} . A LS handler will store that info then publish an event UserLikedItem. One of its handler will be a counter which will count how many users liked that item. Another handler can make a list of what items were liked by one user (this will be queried by the UI).

Each handler serves one use case and probably each has its very own storage. I know it looks quite complicated, but it's actually simple (one use case requires a handler and maybe a storage) and bets of all, it's very flexible and maintainable. And the system works with one or 1000 item types.

like image 127
MikeSW Avatar answered Jan 04 '23 13:01

MikeSW