DDD Domain Models and Business Logic

domain-driven-design

I'm a seasoned programmer but a novice with DDD. I have a project that I'm trying to implement with DDD and my understanding is that there is some ambiguity with regard to the use of domain models and application services. In the purest of DDD implementations, my understanding is that domain models are supposed to contain all business logic. However, this doesn't seem like a realistic goal to me. In simple validation scenarios and such, this is all well and good, but the goal of encapsulating business logic in domain models gets a little slippery when we think about logic requiring additional services such as database lookups/persistence and other external dependencies.

For example, I have a domain model "Order" that has a method "IsValid". To determine whether an order is valid, a database read must be performed. In order to keep the model clean, I don't want to inject any database work into it. OK fine – I create an OrderService to do the database hit and pass in a result to "IsValid" so that the dependency on the database resides with the service. However, what happens if there are multiple database hits that depend on business logic? Is it appropriate to add that logic to the application service? If so, it seems that business logic is leaking into the application services layer which is a violation of DDD. However, if we move the logic inside the domain model and do the database hit there, we're mixing concerns and also violating DDD.

Can anyone experienced with DDD provide any insight into how to deal with this sort of an issue? DDD seems like it provides a lot of nice value, but I'm worried about these kinds of issues leading to design "rot".

Best Answer

This is a very broad question but I will try to give you an answer.

...there is some ambiguity with regard to the use of domain models and application services

There is no ambiguity if you design well your bounded contexts, the domain models and the relationships between them.

However, what happens if there are multiple database hits that depend on business logic?

In DDD, all the operations go through the Aggregate root (AR). The application services load the ARs from the persistence, send commands to them, then persist those ARs back. ARs don't need to hit the database at all. In fact a good designed AR does not even know that databases exists at all. All they touch/see/smell is their internal state and the immutable arguments that they receive in their command methods. If an AR needs something from the database then the Application service pass that thing as argument.

ARs should be pure, side effects free objects/functions. One reason is that commands applied on them must be retry-able, in case of concurrent modifications.

As an example: ARs don't send emails, they return a value object that holds the email data (from, to, subject and body) and the Application service takes that value object and passes it to a infrastructure service that does the actual sending of the email.

For example, I have a domain model "Order" that has a method "IsValid". To determine whether an order is valid, a database read must be performed.

You don't need an isValid method, as an Order cannot get into an invalid state anyway because any modifications are done through it's methods. If you are referring to the existence of an Order then this kind of validation is done by the Application service: if it does not find the Order in the persistence then it does not exist, as simple as that. Maybe you are referring to the ShoppingCart as being valid, not the Order. What about then? Well, you could try to create an Order from a ShoppingCart and if you succeed then a Cart is ready to be ordered. As the Order is side effect free, no order will actually be created. Just an example of how you might think in DDD.

DDD seems like it provides a lot of nice value, but I'm worried about these kinds of issues leading to design "rot".

If you follow the DDD approach well, your design will never rot. Never.

As a foot note: In the beginning I was a little miss-leaded by the Layered architecture. Don't make the same mistake. Take a look at some newer architectures like CQRS that fits very well with DDD.