0

I am implementing a CQRS pattern in ASP.NET Core with MediatR, and I am wondering what the general consensus is for handling duplicate validation logic for queries/commands which operate on the same underlying model/entity.

For more context, I am looking through Jason Taylor's clean architecture project here as a general reference. In his project, he has a CreateTodoListCommand, and an UpdateTodoListCommand. Both operate on the same underlying TodoList entity.

For validation, he has two validation classes: CreateTodoListCommandValidator, and UpdateTodoListCommandValidator. Both essentially perform the exact same validation. The code to perform this validation is duplicated. This seems like bad design to me, because, if there is a change to the validation in one place, you must remember to update validation in all places. In the two validation example from above, if the create command validator changed its length requirement from 200 to 100 characters, then I would need to remember to change the update command validator to max out at 100 characters as well. And this is a pretty trivial example. As the application grows, I feel this could easily grow way out of hand, and become extremely hard to maintain consistent validation across underlying entities.

Do people generally suck it up, and do their best to maintain the duplicate validation code?

One possible solution I have thought of is removing the ValidationBehaviour from the MediatR pipeline, and injecting a general purpose validator service to each handler instead. The handlers would map the query/command to the underlying entity (which is has to do anyway), and then the entity would be validated with a general purpose validation service. Each handler could pass in the field names that it wants validated for its specific case if needed.

Thoughts on this approach? Or any other solutions that others have come up with?

4
  • 1
    The bigger problem with those validators, imo, is that they not only validate the request (command) but also perform business rule validation. In Clean Architecture, Uncle Bob makes a distinction between application specific rules and enterprise wide rules. The latter should be enforced in the domain layer. In the example code, the domain model is completely anemic, but in any real world project putting business rules in the domain layer will automatically prevent a lot of code duplication between various commands that work with the same entities.
    – Rik D
    Apr 21 at 22:35
  • @RikD I agree with you on this. Except, I am not sure how I would map the validation failure from the BLL to the frontend UI. When FluentValidation finds failures it will produce a dictionary to map field name to validation results. Whereas the business level validation that I have seen involves throwing exceptions which can't really be mapped to a field that it came from. Apr 22 at 0:03
  • I’m sure you can find solutions for that. For example enterprisecraftsmanship.com/posts/…
    – Rik D
    Apr 22 at 6:02
  • Ideally, you validate on what can change state (Commands), and not on what doesn't (Queries). So CQRS isn't to blame here. Remember, Queries are not supposed to change state so there is no point of revalidating at that stage. Apr 22 at 11:28

1 Answer 1

1

CQRS does not introduce more difficulties re-using code than any other pattern or technique. Object-oriented languages have many code reuse options, a few of which are:

  • Inheritance/polymorphism
  • Composition
  • Extension methods (or utility classes)

Any of those options can work with command validators. Building on the todo list example, you could refactor the common code into an abstract base class called AddEditTodoListCommandValidator, and have the create and update validators inherit from that.

Another option is to make a general validator that would apply to creating or updating an entity, as long as you can inspect the data in the command in order to determine which use case is being executed. The benefit is that you have one validator, but the drawback is introducing conditional validation rules.

Then again, you could create a separate class for the common validations, and utilize composition to delegate these rules to another class while still keeping the create and update validators separate classes.

There is no single solution to this. It all comes down to existing patterns and practices for code re-use in object-oriented languages. Choose whichever one suits your use case.

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.