I received an interesting question about separation of concerns which I thought I would share with you:

In your courses you often refer to the CSharpFunctionalExtensions, and use it from within the domain model.

In your view what makes this acceptable vs let’s say a DataAnnotations attribute, or a package like FluentValidation, where is the line?

This is a great question, but let’s set some groundwork first before we answer it.

1. Domain Model Purity

I’ve talked about domain model purity in the past. First in the DDD trilemma article and also in discussions on this email list.

In short, domain model purity is a lack of certain types of dependencies in the domain layer:

  • Domain classes shouldn’t have explicit references to out-of-process dependencies or classes from the application layer. In other words, domain classes should only depend on other domain classes or the framework’s built-in primitive types.

    A typical example of violating this guideline is a dependency on the database, such as StudentRepository or IStudentRepository.

  • All inputs to the domain model should be referentially transparent. Referential transparency means that you can replace a method call or an expression with the output of that method call or expression, and it will not change the code’s behavior.

    A typical example of violating this guideline is a dependency on the DateTime.Now property, which returns different output on every call.

Notice that the notion of purity doesn’t tell us anything about dependencies on external libraries, such as CSharpFunctionalExtensions or FluentValidation.

Those libraries don’t refer to out-of-process dependencies, and their classes may very well be referentially transparent. Still, having some of those libraries as dependencies in the domain layer is a bad practice.

Why so?

2. Domain Model Purity vs Separation of Concerns

The reason is another principle: Separation of Concerns. The two principles (Domain Model Purity and Separation of Concerns) look similar, and I often use them interchangeably, but they are not exactly the same.

You can view domain model purity as a subset of the larger overarching Separation of Concerns principle.

The purpose of the Separation of Concerns is to keep the domain layer as simple as possible. In most projects, domain logic is already complex enough, and you should take any opportunity to reduce that complexity.

One way to do so is to keep all non-domain-related concerns out of the domain layer, including:

  • Out-of-process dependencies

  • External libraries that don’t help model the domain

Here’s a good representation of the relationship between domain model purity and Separation of Concerns:

[Enable Images]

Having that out of the way, let’s discuss the original question: where’s the line between acceptable and unacceptable library dependencies in the domain layer?

3. The line between good and bad library dependencies

Here’s the question again (just so that you don’t have to scroll up):

In your courses you often refer to the CSharpFunctionalExtensions, and use it from within the domain model.

In your view what makes this acceptable vs let’s say a DataAnnotations attribute, or a package like FluentValidation, where is the line?

First of all, let me address the premise of the question. Yes, I do consider a dependency on CSharpFunctionalExtensions acceptable for the domain layer, while a dependency on FluentValidation (or DataAnnotations) — not.

Here’s an example of using CSharpFunctionalExtensions (the Result class):

// Student domain class
public Result Enroll(Course course, Grade grade)
{
    /* The implementation */
}

And here’s an example of using DataAnnotations (the Required and EmailAddress attributes):

public class Student : Entity
{
    [Required]
    [EmailAddress]
    public Email Email { get; private set; }

    [Required]
    public string Name { get; private set; }
}

So what differentiates the use of CSharpFunctionalExtensions and FluentValidation (or DataAnnotations) from within the domain model? Why the former is good for the Separation of Concerns, while the latter is not?

To understand the difference, you need to do the mental exercise I mentioned in my past emails. You need to imagine how you would implement the domain model if there were no other layers sitting on top of that domain model.

Then you need to compare this implementation to what you ended up with in your project. The difference is the dent in the Separation of Concerns.

In the case with CSharpFunctionalExtensions, FluentValidation, and DataAnnotations, you need to ask yourself the following question:

Which of these 3 libraries would you use if there were no ASP.NET in the project and you just needed to model the domain in a vacuum?

You would still use the Result from CSharpFunctionalExtensions (or your own implementation of it) because you need to represent the result of an operation somehow.

But you would not use FluentValidation validator classes or DataAnnotation attributes because those are only needed for the application layer (ASP.NET), in order to display errors to the end user.

Hence, having these two libraries as dependencies in the your domain model does violate the Separation of Concerns principle.

This line of reasoning is applicable to any classes from any library of framework. For example, you would still use int, string and other primitive types from the .NET framework in your domain model, even if that model remains in a vacuum. Which makes those primitive types acceptable dependencies for the domain layer.

On the other hand, you wouldn’t use Thread or even Task from System.Threading because there’s no place for multi-threading or other technical concerns when it comes to domain modeling. This makes Thread and Task unacceptable dependencies for the domain layer.


Enjoy this message? Here are more things you might like:

Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.

Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »

My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »