Aggregates and domain validation

time to read 4 min | 789 words

I was asked about using NHibernate in a Domain Driven scenario, with the Entities, Aggregates and Repositories. Specifically, with regard to doing validation. A domain driven problem needs a domain, so I'll chose the Northwind one. We have an Order aggregate, which has OrderLines, Shipments (which has OrderLines as well) and billing.

I am not so hot about validation (beyond rudimetry input validation), because I believe that Invalid State make the application flexible. Here is a simple business rule:

The user may not order more than their credit limit allows.

Which can be translated in the code to:

public void AddLine(OrderLine lineItem)
   ifthis.TotalCost + lineItem.TotalCost > CreditService.GetLimit(this.Customer))
      throw new ValidationException("Passed credit limit");
  lineItem.Order = this;

This is all very well, until you realize that when the user is browsing the store, they are likely to place many more items on the order than they actually intend to buy. The code above basically forces the user to stop what they are doing and make a decision about what items they want the most. That is not a good idea, because the user flow is interrupted with completely arbitrary and needless error.

I am more in favor of validating specific rules when the state change require it. In this case, I would check this business logic when trying to move the order to processed state. Another thing is throwing an exception for validation error. This is counter productive, because you need to guard against those, and it makes it harder to deal with violations of more than a single business rule.

Using the Domain Driven approach, we would like to use the Agrregate as the place where to put validation and business rules for the entities contained in the aggregate.

Often, a case is made for validating the state when the entities are being persisted, this can be an issue if/when you have partially loaded object graphs that you need to handle, while stil keeping the logic in its rightful place. I can think of several solutions to this, which mostly involves NHibernate intecetors and some attributes. I am not going to show them, because I don't believe that this is the right approach.

Validation may be a cross cutting concern, but I don't like the idea of it being trasperant. There is also the issue of "what do you do if it is invalid?" From an interceptor, the only thing that you can do is to throw, which put the session (and the related object graph) into an invalid state, not something that you should be eager to do.

I thought about utilizing the respective repositories for this, but I don't see the point here. Repositories are for the getting data, I am usually not explicitly saving stuff unless I have just created it (Unit Of Work is cool!), so there isn't any point in putting it in something like the Save() method there.

Thinking about this, I come back to Udi's discussion about task oriented interface, this is a far better approach in my opinion, since it means that we no longer talk in abstract terms, but rather in clear, meaningful domain concepts. So instead of having a validator that would check the state of an order, and run the appropriate validation, I would have a method on the Order class that would tell it to change its state, and it would validate itself. This goes for deep object graphs as well, in my opinion. There aren't many actions on the aggregate boundary that it isn't the one to initiate.

In short, don't try to find a technical solution to this problem, this is possible, but I feel that it would result in a clearer design and implementation to make this far more explicit.