1

We're currently exploring CQRS in our future applications. To give a bit of a background, we use a simple CRUD-style service before something like this.

Old Pattern:

  1. Controller
  2. Command/Service
  3. Model

Then the validation logic is inside the model like ValidateSave(SalesOrderModel), ValidateSubmit(SalesOrderModel), ValidateApprove(SalesOrderModel), etc. Since it's validating the SalesOrderModel, it's very easy to reuse a lot of the validation logic and sometimes we straight up do something like this bool ValidateSubmit(SalesOrderModel model) => return ValidateSave(model)

Now that we're in CQRS the layout is something like this:

  1. Controller
  2. CommandRequest
  3. CommandHandler
  4. Entity/Model <-- POCO auto-generated by ORM

Then the common practice is to validate it against the CommandRequest which in this case will be SaveSalesOrderCommand, SubmitSalesOrderCommand, etc. Now the problem here is they are of different class so I have to separately code each of their validation logic. I find this hard to maintain since I always end up copy pasting my Save Validation to Submit Validation whenever a new validation comes up. Not to mention the other issues that rises up with non-DRY approach.

I can't seem to find any resources online that tackles this problem and I'm starting to think it's acceptable and it's a "me" issue. The validation is just one example, this is also applicable in Handler side where sometimes there are repetitive code in which in our previous pattern, we either do it in the Command or Model (so data to process is already mapped to Model). While here in CQRS, they seem to be vertically sliced to the point that a command request from a same module is completely separate from each other code-wise and file-wise.

My idea to solve this:

  1. Create an interface for the CommandRequest like ISalesOrderCommand which will be implemented by SaveSalesOrderCommand, SubmitSalesOrderCommand, etc. Then a SalesOrderValidation where all validation logic is placed and validates against SalesOrderCommand. I tried this and it works but I don't really prefer this mostly due to the added complexity and forcing other CommandRequest to implement fields that they don't really need.

  2. Similar to #1 but in this case, the SalesOrderValidation would validate against the entity SalesOrder. Then on each validation of the CommandRequest, I will map them to the SalesOrder entity. I like this and a lot simpler that #1. I just don't know if this has negative implications that I'm still not seeing.

Note: For simplicity sake, we don't implement a full-blown DDD design so the entity is just a POCO and not some entity with rich business implementations attached to it.

Thanks!

4
  • 1
    Could you explain why Save, Submit and Approve command payloads all need to contain the full SalesOrder? Usually, validating a command is rarely the same as validating an entity, as a very limited number of commands should contain the full entity. An alternative is to let the domain layer validate the entity. Jun 27, 2023 at 7:46
  • @guillaume31 For the Approve, yes, it doesn't necessarily need the full details. For Save and Submit it needs the full details since in our scenario, these actions are initiated right after the user encode/edit the form (not yet persisted in db). So a user can edit a form and click Save if it's not yet final or Submit if what they edited is final. Both of these actions would still have to persist the updated record in database and have a high probability of having same validation.
    – Lawrence
    Jun 27, 2023 at 10:22
  • I would agree that the domain layer is the best place for this but if we go this route, this would mean we'll maintain yet another set of POCOs aside from auto-generated entities of EF and command. There's a lot of mapping again. A rich domain layer would really solve most of these but we're looking for alternatives as much as possible to limit overengineering some of our simple applications.
    – Lawrence
    Jun 27, 2023 at 10:29
  • It is unclear to me why you don't just add a reusable component that both the Save and Submit command handlers depend on to perform the same validation. Did you miss this as an option or is there a reason you're not taking this route?
    – Flater
    Jul 27, 2023 at 0:20

1 Answer 1

0

Indeed, your problem is a common one, as the CQRS pattern by design encourages separation of commands and queries and their associated logic. Therefore, it may naturally lead to some code duplication. It's not a "you" issue, it's a system architecture design challenge that many developers face.

You've proposed two solutions and each has its own trade-offs:

1. Using interfaces (ISalesOrderCommand):

This would indeed allow you to share validation logic between command classes. However, as you pointed out, you'd be enforcing all command classes to have the same structure, even if they don't need all the fields. This could lead to confusion for other developers and even introduce bugs if fields are mistakenly used.

2. Validating against the SalesOrder entity:

This would avoid the problem of unnecessary fields in command classes. However, it would mean that your command classes would have to be mapped to the entity before validation, which might not always be desired or possible. Also, it would tightly couple the command validation with your domain model structure which can make your system less flexible to changes.

Another solution would be to introduce a new layer in your architecture: The Application Service layer. The Application Service layer would sit between the Controller and the CommandHandler. It could have methods such as SaveSalesOrder(SaveSalesOrderCommand command), SubmitSalesOrder(SubmitSalesOrderCommand command), etc. Inside these methods, you could perform validation that is common to all methods. Each individual command handler could then handle validation specific to that command. This would help reduce code duplication while still keeping your commands and their associated validation logic separate.

Consider the following structure:

Controller
Application Service
CommandRequest
CommandHandler
Entity/Model <-- POCO auto-generated by ORM

Another approach you might consider is to use Decorators or Middleware to handle validation logic that is common across commands. This would allow you to reuse validation logic without tightly coupling it to specific commands or entities. It also allows the validation logic to be modular and pluggable.

Lastly, you might consider using a validation library or framework that supports reusable and composable validation rules. This can help avoid writing duplicate validation code. FluentValidation, for example, is a popular library in the .NET ecosystem that enables this.

Remember, there is no one-size-fits-all solution to this problem. The best approach depends on the specifics of your project, your team's preferences, and the trade-offs you're willing to accept.

1
  • Thanks for these options! We currently implement something similar to what you have explained. We useIPipelineBehavior for validators so they are called automatically before invoking the command. We then create a SalesOrderCommonValidator using FluentValidation and these are called by SaveSalesOrderValidator and SubmitSalesOrderValidator. It's limitation though is we can only pass the primitive datatypes of command for validation. This means that both SaveSalesOrderValidator and SubmitSalesOderValidator still have to know the sequence of validation to call.
    – Lawrence
    Jun 27, 2023 at 10:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.