Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to implement aggregate level permissions in DDD? [closed]

Assume I have an aggregate type of Order, which contains OrderItems. Depending on the state of an order, and the user-role operating on it, operations may be permitted or not permitted.

For example, if the user-role is Customer and the order's status is Open, then adding and removing items is permitted. Conversely, if the order's status is Processing then adding and removing items is not permitted. However, if the user-role is Manager and the order's status is Processing then adding and removing items is permitted.

My question is:

  • Should the Order type handle these kinds of permissions? ie, it encapsulates all the logic about which roles can do what and therefore has a dependency on user-role.
  • Or should this be handled outside of the Order type in a permissions service that would accept a role, an operation, and the subject of the operation (an order instance) and determine whether the action is allowed? ie, logic is externalized and assumed to be validated before the operation is executed on the Order, which has no knowledge of the concept of user-roles.

(Notes: The real-world use case is significantly more complex with large numbers of roles, statuses and actions. Authorization happens at an outer layer and has been applied already - this question is about instance specific permissions. In other words, a Customer is authorized to access the 'AddItemToOrder' API endpoint, but depending on the specific state of the order, the actual operation may or may not be allowed.)

like image 958
jimmy_terra Avatar asked Aug 09 '18 09:08

jimmy_terra


People also ask

What is the role of an aggregate in Domain-Driven Design?

Aggregates are a design pattern that play a big role in domain-driven development. In many systems, the relationships between entities can become so interwoven that attempting to eager-load an entity and all of its related entities from persistence results in attempting to download the entire database.

What is tactical DDD?

Tactical DDD is when you define your domain models with more precision. The tactical patterns are applied within a single bounded context. In a microservices architecture, we are particularly interested in the entity and aggregate patterns.

What is domain in DDD principle?

Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.

What is a repository in Domain-Driven Design?

Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.


2 Answers

I prefer to treat access control as applicative logic rather than domain logic, because not all domain operation calls will come from human users and need access control. Putting Permissions in a separate, cross-cutting layer or in a different Bounded Context also helps with Separation of Concerns.

In your example, I would try to come up with distinct domain method names for actions taken by a Customer and a Manager. Enriching the ubiquitous language can be a good arbiter when you're struggling with similar but slightly different concepts.

like image 120
guillaume31 Avatar answered Oct 22 '22 03:10

guillaume31


I kind of feel that you are relying on technical details rather than on a ubiquitous language. The ubiquitous language would already tell you what to do. But I assume you don't quite have such a language, or at least you have not hammered the user permissions through it, yet.

Here is my take on it, assuming that you used the ubiquitous language when you asked your question. Let's see where it takes us.

Given current User has Customer role
And Order status is Open and it has 1 Item
When User adds an Item to Order
Then Order should have 2 items

Here is how I model such a language (as a unit test for expressiveness):

//given.
var user = new User(role: new CustomerRole());
var order = new Order(status: OrderStatus.Open, items: new [] { new OrderItem(name: "Item 1", price: 1.00m });

//when.
order.AddItem(byUser: user, item: new OrderItem(name: "Item 2", price: 2.00m));

//then.
Assert.Equal(2, order.Items.Count);

So far, as we can see, the answer is somewhere inside Order.AddItem method. Most likely, inside it, you will have an expressive code like this:

public void AddItem(User user, orderItem item)
{
    if (user.Role.CanAddOrderItem() && this.Status.IsEqualTo(OrderStatus.Open))
    {
        this.items.Add(item);
    }
}

Now we can see that it's determined by both the Order and Role. Again, assuming that this is how your ubiquitous language sounds.

I hope this helps!

like image 27
Tengiz Avatar answered Oct 22 '22 04:10

Tengiz