1

I am using CQRS. Everywhere I read tells me to put validation logic in the command objects. For example, see this link: https://lostechies.com/jimmybogard/2016/04/29/validation-inside-or-outside-entities/

Please see the command below (taken from the link):

public class ChangeNameCommand { 
   [Required] 
   public string FirstName { get; set; } 
   [Required] 
   public string LastName { get; set; } 
 } 

and the Business Object below (also taken from the link - note that I have changed the the parameter passed to the Customer constructor from a class to an interface):

public class Customer 
{ 
   public string FirstName { get; private set; } 
   public string LastName { get; private set; } 

   public void ChangeName(IChangeNameCommand command) { 
     FirstName = command.FirstName; 
     LastName = command.LastName; 
   } 
 } 

In my case the commands are stored in one class library and the business objects in others (because the commands are shared by multiple microservice type projects). If I follow the guidance (and put the validation in the commands) then I believe there is nothing to stop a developer doing this:

public class ChangeNameCommandWithoutValidation : IChangeNameCommand { 
   public string FirstName { get; set; } 
   public string LastName { get; set; } 
 } 

and then passing the command (without the validation) to the domain object. In this case I believe the Domain Object has no control what is passed to it?

Therefore should I be going against all of the guidance I can find and do the validation in the domain object? I believe I should do this because the commands are in a separate class library to the domain objects. Have I understood this correctly?

I believe this question is also relevant when passing an event to the customer domain object (when using event sourcing).

w0051977
  • 15,099
  • 32
  • 152
  • 329
  • I think you _might_ better have command handler handing the specific command. Then you can do validation of command there and after that invoke the aggregate or entity for execution of the domain logic. This way you can have a nice and clean way of use-cases. I'm not a fan of passing commands right into aggregates, since they should operate on themselves and their respective entites whom they should protect and so on. But all in all, there is no silver bullet here, do as your team/partners decide and could work/deal with. – kayess Jun 08 '18 at 11:46
  • @kayess, does that mean the domain model class could be invalid (If the developer forgets or accidentally removes the validation from the command)? – w0051977 Jun 08 '18 at 11:48
  • I don't think so, you should have unit/integration/whateverelse tests around your SUT which will be responsible to make sure such accidents cannot happen. But as my favorite quote holds about this: "there are no protection against human bosh". Also you can do validation AOP style, like having a decorator... Another way to think about this, you can have code reviews, etc. but this is getting out of hand as we are getting kinda too broad. – kayess Jun 08 '18 at 11:50
  • 1
    I'm not expert in CQRS, but I find it odd that you use an interface for the commands. Does it even make sense to have multiple implementations for one command interface? I think your `ChangeNameCommandWithoutValidation` example shows that it doesn't. And a less *"evil"* example would be a `IChangeNameCommand` with a middle name. Your `Customer` entity would accept such a command but can actually not really handle it. – Dirk Jun 08 '18 at 11:50
  • Regarding your last edit, you don't pass an event to a domain object. You pass (as you do) commands or other parameters to your domain object, telling them to do something. Your domain object or command handler raises events which get handled by event handlers...The distinction is commands = now, events = something happened because there were some interaction with domain logic. – kayess Jun 08 '18 at 11:53
  • @kayess, thanks. If using events then should the validation still go in the command? Should the command class always be in the same class as the domain object? – w0051977 Jun 08 '18 at 11:56
  • That's just a matter of taste. But you don't need to validate events, since they are the outcome of your domain logic, which (needs to be) is protected by validation earlier. Events are just outcomes of some already happened logic, telling the subscribers that _this_ happened. At least this is how I see it, leave it here to see how others do. – kayess Jun 08 '18 at 11:58
  • @kayess, are you saying the validation should be duplicated in the command and domain model? – w0051977 Jun 08 '18 at 12:00
  • No. I'm saying that you should validate every incoming data. Where you do it is really up to you, be it like: initial validation in command handler, and some domain centered validation in the domain object. Noone will force you to do it this or that way... :) Also take these blogs as examples, not rules written to stone. – kayess Jun 08 '18 at 12:01
  • @kayess, I believe validation should be done at the boundaries and there appears to be two boundaries I.e. at the command and at the event. I am trying to follow the principle of least astonishment. – w0051977 Jun 08 '18 at 12:04
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/172761/discussion-between-kayess-and-w0051977). – kayess Jun 08 '18 at 12:05
  • @kayess, I have asked a follow on question here if you would like to take a look: https://softwareengineering.stackexchange.com/questions/372338/zero-arguement-constructors-and-always-valid-entities. – w0051977 Jun 10 '18 at 14:17

1 Answers1

0

A few thoughts:

  • The blog post you linked to is confusing because it equates validation with invariants.

    In DDD literature, invariants refer most of the time to domain rules that are enforced in the root entity and nowhere else. Regarding this domain validity, not "all of the guidance", as you put it, is for enforcing them on the command side - much the contrary. Popular schools of thought consider that an entity should always be valid and therefore should take care of its own rules (aka invariants).

    The kind of validity that the samples in Jimmy Bogard's post speak to, on the other hand, is on the borderline between domain validity and user input validity. I wouldn't make it a stone-set rule to put that kind of validation on one side or the other. While it's legitimate to consider that it's really a job for the Command, with some typesystems you can perfectly encode that kind of non-null constraints in the entity property types and it would be a shame not to take advantage of that free extra correctness.

  • As has been said in the comments, putting an interface on top of a command seems strange.

  • Thinking about what could happen if someone subclassed the command in a malicious way is probably pointlessly defensive. Within a team, you have total control over what is implemented and I can't think of a good reason for "command programmers" to be on a different team than "entity programmers".

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • Thanks. I believe you are saying that an entity is valid if all its invariants are respected. I believe you are also saying that it is possible for an entity to be valid with data like this: ID=Guid.Empty, Name="", Age=0 etc. Is that right? – w0051977 Jun 08 '18 at 13:06
  • As I said, *valid* is a loaded term. For a domain oriented definition of valid, yes. For a user input oriented definition, no. – guillaume31 Jun 08 '18 at 13:18
  • I have just found your answer here: https://stackoverflow.com/questions/30190302/what-is-the-difference-between-invariants-and-validation-rules. I like the comment, which says: "you use validation to ensure the input data is in valid format, then the business rules decide how/if the input changes a model". I interpret that as meaning validation is done at the Command and invariants are considered in the domain model. +1 for the other answer. – w0051977 Jun 08 '18 at 13:25
  • For example, lets say a Customer has a Customer.Offer property. An offer is created if the Customer is over 21 years old and has spent £1000. In this case validation (in the command) would check that the age is greater than or equal to 0 and that the expenditure is greater than or equal to 0 and the domain model would check that the customer is over 21 years and has spent £1000 or more before assigning the offer. Is that right? – w0051977 Jun 08 '18 at 13:29
  • I guess, as long as you treat these as examples and not stone-set rules like "> 0 always means command validation no matter the context" ;-) – guillaume31 Jun 08 '18 at 13:59
  • Again, I'm saying that because from a strongly typed functional programming perspective fror instance, you get much more of this validation baked in the type system and as a consequence, baked in entities, so the distinction sort of becomes void. – guillaume31 Jun 08 '18 at 14:02
  • Before I answer and draw a line under this - "> 0 always means command validation no matter the context". If there is a context then I believe that would be domain specific and should appear in the domain model? – w0051977 Jun 08 '18 at 14:10
  • It could be either way. Depending on the context there are domain > 0's and applicative > 0's. Use best judgment to decide ;) – guillaume31 Jun 08 '18 at 14:25
  • I have asked a follow on question here if you would like to take a look: https://softwareengineering.stackexchange.com/questions/372338/zero-arguement-constructors-and-always-valid-entities – w0051977 Jun 10 '18 at 14:18