Should I Abstract the Validation Framework from Domain Layer

Should I abstract the validation framework from Domain layer?

Just like the repository abstraction?

Well, I see a few problems with your design even if you shield your domain from the framework by declaring an IUserValidator interface.

At first, it seems like if that would lead to the same abstraction strategy as for the Repository and other infrastructure concerns, but there's a huge difference in my opinion.

When using repository.save(...), you actually do not care at all of the implementation from the domain perspective, because how to persist things is not a domain concern.

However, invariant enforcement is a domain concern and you shouldn't have to dig into infrastructure details (the UserValidtor can now be seen as such) to see what they consist of and that's basically what you will end up doing if you do down that path since the rules would be expressed in the framework terms and would live outside the domain.

Why would it live outside?

domain -> IUserRepository
infrastructure -> HibernateUserRepository

domain -> IUserValidator
infrastructure -> FluentUserValidator

Always-valid entities

Perhaps there's a more fundamental issue with your design and that you wouldn't even be asking that question if you adhered to that school of though: always-valid entities.

From that point of view, invariant enforcement is the responsibility of the domain entity itself and therefore shouldn't even be able to exist without being valid. Therefore, invariant rules are simply expressed as contracts and exceptions are thrown when these are violated.

The reasoning behind this is that a lot of bugs comes from the fact that objects are in a state they should never have been. To expose an example I've read from Greg Young:

Let's propose we now have a SendUserCreationEmailService that takes a
UserProfile ... how can we rationalize in that service that Name is
not null? Do we check it again? Or more likely ... you just don't
bother to check and "hope for the best" you hope that someone bothered
to validate it before sending it to you. Of course using TDD one of
the first tests we should be writing is that if I send a customer with
a null name that it should raise an error. But once we start writing
these kinds of tests over and over again we realize ... "wait if we
never allowed name to become null we wouldn't have all of these tests" - Greg Young commenting on http://jeffreypalermo.com/blog/the-fallacy-of-the-always-valid-entity/

Now don't get me wrong, obviously you cannot enforce all validation rules that way, since some rules are specific to certain business operations which prohibits that approach (e.g. saving draft copies of an entity), but these rules aren't to be viewed the same way as invariant enforcement, which are rules that applies in every scenarios (e.g. a customer must have a name).

Applying the always-valid principle to your code

If we now look at your code and try to apply the always-valid approach, we clearly see that the UserValidator object doesn't have it's place.

UserService : IUserService
{
public void Add(User user)
{
//We couldn't even make it that far with an invalid User
new UserValidator().ValidateAndThrow(user);
userRepository.Save(user);
}
}

Therefore, there's no place for FluentValidation in the domain at this point. If you still aren't convinced, ask yourself how you would integrate value objects? Will you have a UsernameValidator to validate a Username value object everytime it's instanciated? Clearly, that doesn't make any sense and the use of value objects would be quite hard to integrate with the non always-valid approach.

How do we report all errors back when exceptions are thrown then?

That's actually something I struggled with and I've been asking that myself for a while (and I'm still not entirely convinced about what I'll be saying).

Basically, what I've come to understand is that it isn't the job of the domain to collect and return errors, that's a UI concern. If invalid data make it's way up to the domain, it just throws on you.

Therefore, frameworks like FluentValidation will find their natural home in the UI and will be validating view models rather than domain entities.

I know, that seems hard to accept that there will be some level of duplication, but this is mainly because you are probably a full-stack developer like me that deals with the UI and the domain when in fact those can and should probably be viewed as entirely different projects. Also, just like the view model and the domain model, view model validation and domain validation might be similar but serves a different purpose.

Also, if you're still concerned about being DRY, someone once told me that code reuse is also "coupling" and I think that fact is particularly important here.

Dealing with deferred validation in the domain

I will not re-explain those here, but there are various approaches to deal with deferred validations in the domain such as the Specification pattern and the Deferred Validation approach described by Ward Cunningham in his Checks pattern language. If you have the Implementing Domain-Driven Design book by Vaughn Vernon, you can also read from pages 208-215.

It's always a question of trade-offs

Validation is an extremely hard subject and the proof is that as of today people still don't agree on how it should be done. There are so many factors, but at the end what you want is a solution that is practical, maintainable and expressive. You cannot always be a purist and must accept the fact that some rules will be broken (e.g you might have to leak some unobtrusive persistence details in an entity in order to use your ORM of choice).

Therefore, if you think that you can live with the fact that some FluentValidation details makes it to your domain and that it's more practical like that, well I can't really tell if it will do more harm than good in the long run but I wouldn't.

In which layer should the validations be done mainly in the context of DDD?

In which layer should the validations be done mainly ?

Mainly in Domain, except for infrastructure related validation, e.g. xsd validation or json schema for instance.

Is it acceptable for the object to be in invalid state? because many
answers said that it's okay and mainly because of historical data and
the business rules may change over time and loading historical data
might cause problems?

It can be acceptable, because validation is done into domain it should not be the case. On a point of view of business, objects cannot be in an invalid business state, however, some times, like in the real life, process can be in an invalid/temporary state. We call it eventual consistency (https://en.wikipedia.org/wiki/Eventual_consistency), I suggest you take a look at this. At the end the system will be in a valid state and that's all that matter, if its temporarily invalid, well, the effort might be bigger to maintain such system but sometimes you have no choice.

Many implementations consider throwing exceptions in the domain layer
and mapping the messages to the UI although Martin Fowler recommends
to Replacing Throwing Exceptions with Notification in Validations!
When to return messages and when to throw exceptions in the validation
context ?

I am not a big fan of exceptions in the domain layer unless this is clearly a pre-requisite thesis broken. For instance an input too large for a field, or a negative price for an item. If you cannot build a valid business object, then in my opinion this is a very valid case for an exception. In case this is a business case, a message is best suited.

Many articles explain some tips or paths to follow like Vladimir
Khorikov and jbogard in their articles but in the comments they
confess that they do things a wee differently now. Are these patterns
still valid?

Should I use framework like FluentValidation and if I use it, Is this
frame work used only in the application layer as an alternative to the
MVC annotations ?

Best recommendations in DDD is to never use framework, Spring or JDBC might help however but in general you should do it by hand. We have written even stores by hand, application services and Oracle projections and event bus. Its more faster, more maintainable, and you learn a lot more. Vaughn Vernon in his book (Implementing Domain Driven Design) gives very good examples and a project you can look at: https://github.com/VaughnVernon/IDDD_Samples (written in Java)

When Should I use Business Rule Framework (BRF) instead?

Again, don't use a framework

Is it bad practice to have validation in the application service that checks if a DTO's id is valid or if one of the dto's properties is blank?

I usually ask the question Is it something the user could have done wrong or is something the developer implementing against the API could have done wrong?. By the latter I mean, the developer implementing against the API should not have allowed the user to send some incomplete request in the first place.

If your API strictly defines that a property has to be set (i.e. is mandatory) I would already verify this at the API or application layer. There is no need to pass this on to the domain layer. So if the developer who implemented against the API (e.g. in front-end code) forgot to make sure that the data sent corresponds to the specification an error should be raised already when receiving and processing the data from the REST call, message from a queue or whatever other communication protocol is used. I am of course talking about invariants that are not related to business logic at this level.

That does of course not mean that something similar will also be checked in the domain layer in some cases. Domain model classes should not allow to be constructed with invalid data so raising an error when invalid properties are received will also be the responsibility of the domain layer.

Checking against obvious errors before handing it over to the domain layer also adheres to the fail fast principle and might avoid unnecessary operations such as loading an aggregate from database to fail when calling a domain model operation that will fail because a parameter has not been passed properly with the request anyway.

Also consider, if this happens once there might not be much of an implication but consider there is some error in the client code you really can save a lot of resources on your side if lots of invalid calls would be made.

Is it bad practice to have validation in the application service that checks if a DTO's id is valid or if one of the dto's properties is blank?

So if you are not checking against business invariants but against invalid API specifications I say it is even good practice.

Should I validate inside DDD domain project?

As soon as your entities don't depend nor rely on this third party library, it's ok and valid. Actually, the idea behind having the domain layer, is to have a common language between developers and people from the business area, so it should be the most clean and natural possible. Then you could show the domain to a business analyst, make sure they understand it and discuss further. If the validation code has validations which make sense to the business, then it's valid. Actually a business analyst could even see it and make additional observations (e.g this validation rule should be that way). Your validation code looks fine to business.

Where should I put validation code?

Message is one thing. A container of data.

Validation is a separate thing. Validation is separate from the Message because validation depends on non-Message data. Validation includes one or more algorithms that establishes if a valid Message could be built from some data.

You want Messages to be built only when they're valid. You want all of the the methods of a message to require and depend on validity. That gives you easy-to-understand responsibility.

Therefore, a Message should not contain any validation logic. That logic lives just outside the boundaries of a valid Message. It's part of a MessageFactory or MessageValiadtor that determines if some given puddle of data could be used to build a valid Message.

You have two things: MessageValidator (or MessageFactory) and Message.

There is no isValid in a Message. It must be valid or it would not exist.

MessageValidator builds Messages from source data. If it cannot build a message can can throw an exception. It should also accumulate the list of errors it finds so it can be interrogated to determine what the various problems were.

Consider the possible mutations: Multiple variant subclasses of Message. The Validator may identify a specific subclass. No application changes are required to implement this.

Multiple Validators for special situations, exceptions, extensions, etc. It's just a subclass of MessageValidator with the same interface all validators have and emits an instance of Message (or one of it's subclasses.)

Since the validation rules are separate from a valid message, the Validator can provide different assumed defaults or derived data, also.

Sharing domain validation logic in application layer by using FluentValidation

The two numbers are really in different models – the request model and the domain model. In re-reading the question and my original answer, I think I see the mismatch here.

Front end validation should be limited to basic data types. If you’re expecting an integer, ensure the caller sent an integer, dates are dates, and strings are strings. This is the responsibility of the Controller (or whatever receives the request directly from user). If the user sends an invalid integer, it is rejected at this level. No range checks are done here, we only check to ensure the request is well-formed.

The controller then creates a command. The role of the Command is to communicate the user’s desire to the domain logic, which performs business logic to execute that desire. We assume the user really does want to create a student with the given number therefore the Command should communicate this desire to the Domain, i.e. no validation of range should be in the Command. Command validation is typically done just with constructor arguments of the appropriate type.

The Domain logic tries to carry out the users’ desire and create a new student with an invalid number. The Domain decides this is not a valid number and throws the exception at this level, making the Command execution fail. The controller senses the failed Command execution and returns an appropriate failure to the caller (or, if command execution is async, processes the error in the appropriate way).

Your initial instinct was correct that you were violating DRY. This can be shown by changing the business rule to allow a broader range. This single business rule change would require two code changes, thus proving you were repeating yourself.

Best practice to implement business logic validation - Entity Framework

Have a look at validation with EF - the validation is inside the entities themselves.

It's a very clean way to organise your project.

When you have POCOs, the obvious place for entity validation is in the POCO itself.

It makes sense that any validation of the Customer object is actually in the Customer class.



Related Topics



Leave a reply



Submit