2

Thinking in the classic example of orders and lines.

I would like to use the domain classes in the presentation layer, so as to check if an action or a property is correct, the main code is in the domain classes and I only need to adapt the specific aspects for the UI, for example, nulls, that in the domain it common don't use null values but in the UI it is more common.

The order is the root entity and the line the child entity.

To check if a line can be created I have this:

    class Line
    {
        //bool to tell if it is enabled or not. string to tell the reason why it is not enabled.
        internal static (bool, string?) IsCreateEnabled(deicmal amount, decimal price)
        {
            //check if amount is correct.
            //check if price is correct.
        }
    
    
        public Line(decimal amount, decimal price)
        {
            (bool, string?) = IsCreateEnabled(amount, decimal);
             
            //if bool false throw exception.
    
    
            //Create the line
        }
    }


    class Order
    {
        //bool to tell if it is enabled or not. string to tell the reason why it is not enabled.
        public static (bool, string?) IsCreateLineEnabled(deicmal amount, decimal price)
        {
            return Line.IsCreateEnabled(amount, price);
        }
    
    
        public CreateLine(decimal amount, decimal price)
        {
            (bool, string?) = IsCreateLineEnabled(amount, decimal);
             
            //if bool false throw exception.
    
    
            //Create the line
        }
    }

How from a consumer it shouldn't access to the child entities directly, all it is through the root aggregate, I think that this is a possible solution. Internally the root aggregate delegates the validations to the child entity.

But the reason to can't access from a consumer to the child entities is to avoid incoherences, but if it is only for validations, not modify data, perhaps it would be not a bad idea to expose this kind of methods of the child entities to the consumers.

Although there could be better solutions.

1
  • "But the reason to can't access from a consumer to the child entities it is to avoid inchoerences." - this is not the (only) reason. It's also about maintainability. See Law of Demeter. Commented Feb 16, 2023 at 21:06

2 Answers 2

5

but if it is only for validations, not modify data, perhaps it would be not a bad idea to expose this kind of methods of the child entities to the consumers.

It is the root's job to ensure the integrity of the whole aggregate.

Only the root can show/change/create "children" (other elements of the aggregate) because only the root can be referenced from the outside, so there is no access to children that doesn't go via the root — thus, the children cannot have a referenceable endpoint with methods; if they do, then they are not "children" but their own aggregate roots.

How from a consumer it shouldn't can access to the child entities directly ... ...  expose this kind of methods of the child entities to the consumers.

The aggregate root is essentially the reference via which access to the children is offered.  The children should not directly referenced from the outside (they cannot be referenced from the outside, because they don't have their own global identity), so the children cannot directly offer methods.

Internally the root aggregate delegate the validations to the child entity.

DDD doesn't specify your internal implementation details, so you can do this.

But if you ask me, an order is either open, and being constructed, or has been submitted and cannot be changed without a proper change process.  To one way of looking at it, the "open" order is just a "shopping cart" or basket, with items in it, and which is freely edited, and then there is an Order, which is official, has been submitted to, and accepted by the order system, and should not be changed without an official and approved ChangeOrder, since that may require collection of additional funds, refunding, or other (financial) authorization.

2
  • When you tell the root can show child entities, do you mean it is correct if a consumer ask to the root entity for a child, the root entity can return the child that the consumer ask for? I mean, a consumer ask order for line 2, is correct the order return the line 2 to the consumer? The consumer will not can modify the line, because the line has not public methods to modify the line. The consumer will only can access data with readonly properties and get methods. If this is not correct, how could a consumer to know for example the price of a line? Commented Feb 20, 2023 at 10:08
  • DDD gives access to the whole aggregate via the root. In a simple implementation, reading the root order would return the entire aggregate, including all line items.
    – Erik Eidt
    Commented Feb 20, 2023 at 15:56
1

You're right, thinking about it in terms of properties and data, trying to interrogate these data structures and then executing some logic outside of them makes the whole exercise of hiding things rather pointless. Feels like one more obstacle to overcome just for some nebulous supposed advantages.

It all makes sense though, as soon as you start thinking about this in terms of behavior. You really don't want to interrogate line items of an order either directly nor indirectly. What you want is display the order. Have the logic inside the object and suddenly it's not an obstacle to be overcome, it's the thing you actually want. You don't have to care about the internals of the order or lines, it will do the right thing based on its own internal data. Neat!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.