Dealing with many to many relationships in DDD

Viewed 204

I've been reading about this so far, and I think that is just a design decision, but unfortanetly I couldn't figure out which is the best approach.

I have many entities, among them are Application, User, Role and Permissions. There are some rules as follows,

  • An Application must have at least one User.
  • An User must be in at least one Application.
  • Each User have different Roles, password, and others attributes in each Application it belongs.
  • Each Role have different Permissions, and so on.

My problem is how should I build each Aggregate?, my approaches have been the followings:

  • My first approach was create an Aggregate for Application, User, Role, etc. But should I create a different aggregate for the many to many relationship between Application and User because of the adittional attributes it will have?, or should I convert the many to many relationship in an one to many relationship?, if so, how could I achieve it?

  • The second one was create just one Aggregate for Application, and add User as a ChildEntity, but I'm not sure if it is appropiated for the given context, if so, should I have Role and Permission entities as ChildEnties in my Application Aggregate too?

Please let me to know your thoughts about this, and if there is another point of view that could help me, it will be great. thank you in advice.

1 Answers

Honestly these rules seem rather artificial. If you absolutely need strong consistency on all these then you need a giant ApplicationAccess aggregate which will certainly be very busy because any access rights changes for a given application would conflict with any other change for the same application.

That giant AR is not even enough on it's own to cover the "An User must be in at least one Application." rule which means you'd probably have to update the User AR along with the ApplicationAccess AR in every role member addition/removal.

e.g.

// Assume transactional
function removeUserFromRole(userId, applicationId, roleId) {
    applicationAccess = applicationAccessRepo.existingOfId(applicationId);
    user = userRepo.existingOfId(userId);
    applicationAccess.removeUserRole(user, roleId);
    user.trackRoleRemoved(); // decrement and throws if 0 (trackRoleAdded would increment)
}

Like you can guess this design doesn't seem very scalable. It might work for a small amount of users without too much concurrent access modifications but it's probably the wrong design otherwise. If you go for it you would probably want to use pessimistic locking rather than optimistic + retries.

If you want a more effective model I think you will have no choice but to explore the possibilities of loosening up the rules and allow them to be eventually consistent rather than strongly consistent.

For instance, why does it matter that much that a User has no access? Could you just run exception reports to list these? Could you just flag the Users so that their access need to be updated manually?

The same applies to all the other rules and there's endless possibilities to deal with eventual consistency. You could have automated compensating actions that reverts some actions if they are found to have violated some rules or just flag & have manual resolutions like described above etc.

Anyway, a good way to question the rules is to analyze the "cost" of a rule being violated through concurrent modifications and how often that might happen under expected concurrent usage should you put things in distinct ARs and have possibly stale checks of rules.

Related