0

I had asked a question here, and someone had recommended that OrderLine be a Nested class within Order Header. Is that a standard practice in Domain Driven Design, or more one of many debated methods of conducting DD, with nested class? Just want to validate if this is industry wide practice recommended from DDD Author EricEvans.

https://stackoverflow.com/questions/57549607/domain-driven-design-order-and-order-line-classes

We know in a Database Model, Order and Orderline are generally two separate tables.

Database Models from Scaffold:

public class OrderHeader  
{
    public int OrderHeaderId { get; set; }
    public int CustomerId { get; set; }
    public int OrderLineNumber { get; set;}

    public virtual ICollection<OrderLine> OrderLine{ get; set; }
}


public class OrderLine
{
    public int OrderLineNumber { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; 

    public virtual ICollection<OrderHeader> OrderHeader { get; set; }
}

Recommended Example:

public class Order
{
    public int OrderId { get; }
    public int CustomerId { get; }

    private readonly List<OrderLine> _orderLine = new List<OrderLine>();

    public Order(int orderid, int customerId)
    {
        OrderId = orderId;
        CustomerId = customerId;
    }

    public IEnumerable<OrderLine> GetItems() => _orderLine .AsReadOnly();

    public void AddOrderItem(int productId, string description, intcount, decimal unitPrice)
    {
        _orderLine.Add(new Item(productId, description, count, unitPrice));
    }

    public class OrderItem
    {
        // get-only properties
        internal Item(intproductId, string description, int count, decimal unitPrice)
        {
        }
    }
}

https://stackoverflow.com/questions/4329322/ddd-aggregate-root-example-order-and-orderline

5
  • I would avoid nesting it. It makes testing that much harder. Also it seems to me like you are allowing multiple OrderHeaders per OrderLine is that intentional?
    – Kain0_0
    Aug 19, 2019 at 9:05
  • @Kain0_0: Nesting per se does not make testing harder. The design should be as intuitive and fluid as possible. The reason I do this is so that I do not end up with an Order and another public OrderItem class since an OrderItem class cannot, and should never, be used in isolation. I'm all for ease of testing, though :) --- An aggregate root in DDD encapsulates the relevant invariants so having the item coupled to the order seems a reasonable thing to do. YMMV
    – Eben Roux
    Aug 19, 2019 at 9:46
  • I don't believe DDD has anything at all to say about nested classes. They are a programming language artifact. DDD is more about humans and baking your domain experts vocabulary into your code regardless of its structure. Aug 19, 2019 at 19:49
  • @EbenRoux In what way would nesting make testing easier? The Order in this case is explicitly coupled to its Line. Need to use a different sort of Line? Of course you can do it, but the structure will fight you. Fighting with the structure is not conducive to good programming. As for the logical nesting would it not make more sense to using the scoping? ie: Shopping.Order and Shopping.Item where Shopping is a package/namespace. That would be both more informative (its a shopping order vs a fulfilment order vs. a stocking order), and provides a cleaner interface.
    – Kain0_0
    Aug 20, 2019 at 0:32
  • @Kain0_0: Nesting has no impact on making testing easier or harder. If you have a Shopping.Item that could be re-used in a Shopping.Order and in a Shopping.FulfilmentOrder then that is a design choice and may even be an internal "base" class to nested classes. Perhaps a fulfilment order is simply a type of order and can be handled using a normal order with a type. I haven't ever come across a fulfilment order in my career so my understanding may be lacking. In any event, the design should always aid in testing no matter the implementation details as alluded to by@ candied_orange.
    – Eben Roux
    Aug 20, 2019 at 3:48

1 Answer 1

1

From an RDBMS point of view, Order and OrderLine are two tables without a doubt. The decision on whether to nest OrderLine within Order is dependent on answers to three questions:

  • Do the business rules of Order include maintaining data spread across Order and OrderLine? For example, the order amount is always equal to the sum(qty * price) of all OrderLines. If so, then OrderLine is within the invariant boundary of Order, and Order aggregate should take responsibility for persisting and loading OrderLine items. That's the only way to make sure that the invariant rules are satisfied all the time.
  • The second aspect is an exception to the earlier rule. Sometimes, the child entity (OrderLine in your example) can be in huge numbers that it doesn't make sense to enforce invariant rules in real-time. For instance, Followers of a User, though very much part of the User aggregate, would need to be modeled separately as an aggregate of its own. Because as your application scales, loading and persisting all followers of a user is no longer viable or sensible. Unless the number of order items in your order exceeds, say, 100 pieces, it should be ok to keep OrderLine within Order. Still, if you observe performance issues on large orders, this may be the way to go.
  • The third aspect has to do with practical usage in your application. If you plan to access the child object on its own, without requiring the parent object to be present, then it may make sense to treat the child object as an aggregate of its own. For example, Tasks in a Project may have a considerable amount of functionality of their own, and may not need always to be referenced in the context of a project. There would be a ProjectId connecting the task to the project, but you wouldn't always traverse the project.tasks path for operating on tasks. In such cases, you would treat the child object as a new aggregate.

DDD Nomenclature-wise, the nested OrderLine would be called an Entity and would be part of the Order Aggregate.

Note that your code structure in the domain layer has nothing to do with persistence. For example, you may switch to a Document DB like Mongo tomorrow and store both Order and OrderLine as a combined structure. But this wouldn't change how you place the classes in the domain layer.

4
  • The nested OrderLine would probably be a value object, though. An entity would need to have a life-cycle of its own and have a unique identifier. I aim at a single root aggregate entity which contains value objects. If you look at this diagram in the blue book you'll see that entities are accessed via repositories (not just aggregates). But for some odd reason that has been a topic of disagreement for some years since most folks reckon only an AR should be retrieved via a repository.
    – Eben Roux
    Aug 20, 2019 at 3:53
  • I tend to refer to an element as Entity if it is persisted separately (thus has a unique identifier), and a Value Object if it is persisted inline with the owning domain element (thus having no unique identifier of its own). One of the entities is promoted to be an aggregate root based on domain concepts. That's usually how I arrive at aggregate roots, so the only differentiation between an aggregate root and an entity for me is the fact that entities don't own sub-entities.
    – Subhash
    Aug 20, 2019 at 7:52
  • The red book mentions that only Aggregates have Repositories. Even otherwise, it makes perfect sense to me that the repository of aggregate also persists and loads enclosed entities. It's much easier to ensure invariants and perform ACID transactions, that way.
    – Subhash
    Aug 20, 2019 at 7:53
  • hi, gave points and accepted answer, another question here softwareengineering.stackexchange.com/questions/396323/…
    – Matt Smith
    Aug 21, 2019 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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