DDD and many-to-many relationships

Imagine that you are building a social network. There are users who can add other users as friends. How do you model this in DDD? Naturally, you cannot just have a list of friends in the User class, because any cycle of friends will cause infinite recursion when such a user is received from the repository.

How would you change your model if you need to track friends' requests that may be delayed, canceled, accepted or rejected?

+3
source share
3 answers

hmm ... It’s actually quite easy to do what you requested and your situation is standard. You do not need to store the actual User object in the Friendslist your User aggregate, just enter the identifiers of users who are friends for User .

This is one of the rules for aggregate implementation proposed by Vaugh Vernon: a link to another aggregate and entities by their identifier. So there are no loops, just a list of identifiers.

In this situation, someone will become a friend to someone who needs to change two units at once. This may be an undesirable behavior, because a change cannot happen instantly in a single transaction. But for this case, you have domain events, and friend requests can be easily modeled: your aggregates can communicate with each other with the events FriendshipRequested , FriendshipAccepted , FriendshipCancelled or FriendshipDeclined and change their state accordingly.

In this case, you also receive magazines and notifications for free.

+2
source

A User may have a Friend s list. A Friend can consist of UserId, FriendType, GroupId, etc.

A User may also have a FriendRequest s list. A FriendRequest can have UserId, RequestMessage, RequestStatus, etc.

User , Friend and FriendRequest can be part of the same aggregate. But there may be some duplication. Another option would be to have one FriendRequest for both users, and each user would have a list of received and sent FriendRequest identifiers.

This is just to give you some ideas, because in DDD your design will depend on how your application will work and what features are needed .; -)

+1
source

This will greatly depend on where the boundaries of the sequence should be. It will also depend on what business rules you have.

While Meta-Knight has FriendRequest in the same aggregate, I would use it as my own and use events to communicate between the Aggregates, so I created Person, and FriendRequests was ultimately consistent. This will allow you to do something like.

 public class DomainRouter { public void When(FriendRequestCreated event) { //Send command to each Person to record request } public void When(FriendRequestAccepted event) { //Send command to Person to record request accepted and add friend. //Send comamnd to Person who accepted to add Friend } public void When(FriendRequestDeclined event) { //Send command to update Friend request on person. //Send command to Person who declined to record they have declined? } } 

Thus, information about a person will be just a state record. FriendRequest will be where the whole process takes place.

In DDD, it's important to think about behavior. FriendRequest request can be requested, withdrawn, accepted and rejected. What can a person do? Should the person be DDDd or could you make him beautiful and just CRUD + store the information in the graph database, etc.

Maybe you want to simulate it so that you can go person.requestFriendAcceptance (Person id), in which case the router will probably just handle the FriendRequestCreated event, notifying the FriendRequest friend.

+1
source

All Articles