Where should the validation be?

2,287 views
Skip to first unread message

hector.T

unread,
May 13, 2013, 2:49:02 PM5/13/13
to ddd...@googlegroups.com
Hi,

I would like to have your advice on where should I put or not put a validation.

Let's take the Order example, I have a command CreateOrder which is supposed to create an order and takes in parameters; 
- Quantity,
- Price,
- Product.

Now if I would want to make a validation check on the quantity saying; the quantity can't be lesser than one item and the price/product must not be null.
From where should I validate this?

1 - Should I validate it in the command handler by checking the parameter of the command CreateOrder? 
2 - Should I validate it in the aggregate Order when the behavior is called?
3 - Should I just not validate it at all and let the UI validate it? (which does not sound like the good solution for me)
4 - Should I put logic inside the command? (which also does not sound good)

Thanks!

Dennis Traub

unread,
May 13, 2013, 4:55:40 PM5/13/13
to ddd...@googlegroups.com

Hi,

In DDD it is considered common practice to let an Aggregate enforce its own validity. In other words, an Aggregate can never be in an invalid state. In your case this means that the constructor ensures the arguments meet the requirements.

You can (and often should) enforce simple rules at the boundaries (UI, app service, etc.) as well, but the most important concern is (business) rule enforcement on an aggregate level.

Best

Dennis

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Gabriel Schenker

unread,
May 13, 2013, 5:48:03 PM5/13/13
to ddd...@googlegroups.com
of course you would also want to validate in the UI to not make an unnecessary round trip and to make it highly likely that the command succeeds...

Ben Kloosterman

unread,
May 13, 2013, 11:28:04 PM5/13/13
to ddd...@googlegroups.com

Pros and cons

 

·         UI  - No round trip .. very useful for web UI else you need to build a mechanism to send arrays of errors  back to the UI . No complex logic checks though

·         Command -  Keeps aggregates light  ( eg good for things that do not relate to business logic eg  must be a number with 2 decimals) , allows  using asynchronous handlers without a complex mechanism to communicate back to the source ( eg you can fire and forget after doing the check) .  Bad commands are never added to the command bus. Full access to query model !

·         Command Handlers – I very rarely use these. The only advantage is it keeps it out of the aggregate and it could fetch other aggregates ( but this is better than command) . Maybe in cases where you don’t trust the layer that creates the commands.

·         Aggregates – Good for business logic type validation , Eg consider a courier company where a shipping label is damaged and only some of the chars can be entered , but it must still be recorded and someone later needs to hunt down the details. Similar validation code can be more easily shared. 

 

So I use 3 for web type UIs.

·         UI with local checking  sometimes with Regular Expressions eg is it an email or phone.

·         Commands basic checking at constructor  is it an int ,non zero int ,  is it a non empty string. Just 1-2 lines per command  , but sometimes  I put a query here eg is the name already used .

·         Aggregates . The rest  

 

Regards,

 

Ben

Luis Abreu

unread,
May 14, 2013, 4:57:24 AM5/14/13
to ddd...@googlegroups.com
How about cross-aggregate validation? for instance, shouldn't there be also be another "validation" option? for instance, an event handler which would check for uniqueness and then generate some sort of compensating command when there is an invalid option?


--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Regards,
Luis Abreu

Alexey Raga

unread,
May 15, 2013, 6:02:39 AM5/15/13
to ddd...@googlegroups.com
Depends on what you call "validation".

I would recommend to validate the _command_, not the parameters of behavior methods of your aggregates.

In other words, commands are part of your ubiquitous language. There is already an understanding in business what is a valid command and what is not. So you can easily validate the command against these criteria. If the command is not valid then it just does not make it into the domain at all. Often you don't even need to show any nice validation error messages in UI. Just piss it off, because your UI (or other logic) does not produce invalid commands. If the command happens to be invalid then it means that there is some violation of the rules (or hacks) somewhere, and you neither want to compensate for hacks nor to provide hackers with a nice error messages :)

So the validation concern is simple: you validate commands as far from your domain as you can trust. It depends on where your commands are received. 
You may do it at command handlers just before calling the domain, and it is fine as you normally have only _one_ handler for a given _command_ so the validation would live in one place only. 
Or have another step in the pipeline which validates commands before passing them to handlers...
Or you can even enforce this kind of validation (product != null, quantity > 0) on the command itself (perhaps it its constructor). Whatever you prefer, and depends on your situation.

Because of that, when you are in the domain you can always assume that the command is valid. So there is no reason for the command to fail within the domain.

Aggregares, in my opinion, have nothing to do with validation, but they have everything to do with business rules. It means that an aggregate can reject the command (not the command directly but the behavior) not because it is invalid, but because business rules dictate that. 
The command can be perfectly valid, but still can be rejected. Example: I give you a perfectly valid pregnancy leave form to approve. But I just had a baby one month ago and your business logic dictates that it is impossible for me to have another one already. Beside, you discover that I am a man! :) 
But the form was still populated correctly, and it was a perfectly valid command to it made all the way to your eyes. Otherwise it could be rejected by one of your secretaries way before you :)

[here we can talk about rejections as throwing exceptions, or publishing another kind of event, etc, that's not the point]

Resuming: There is a big difference between validation and business rules. The second one (business rules) belong to aggregates. The first one (validation), in my opinion, does not. Anyway, some people even don't check aggregate method parameters at all assuming that if it made into the domain then it cannot be an invalid call.

Wim van Gool

unread,
May 18, 2013, 2:51:23 PM5/18/13
to ddd...@googlegroups.com
A very interesting discussion, especially since I have been struggling with the same question recently: how to go about validation of commands, where to put it and how to deploy it?

I think that as been noted here, there's a difference between 'quick validation' of a command and the actual business logic inside aggregates that will either accept the arguments provided or deny them based these business rules. Quick validation, in my view, can and should be used to deny commands before they enter the domain, but this validation is limited to simple value-checking, such as null-checks, range-checks or regex-checks (in a sense just sanity-checks). This type of validation is primarily useful for performance and/or user-experience reasons so that unnecessary round-trips are prevented or malicious commands can be denied before all kinds of resources are reserved to process them in your domain. Personally, I would never take away these checks from my aggregates as they are your ultimate state-transition components and should be built very robustly. (Better to double-check than to rely on some upper-layer to protect you.)

However, given this scenario, I was wondering how one would actually implement and deploy this. Right now I am developing a sample application where I have the following three modules/assemblies:

1) Application.MessageHandlers
2) Application.Commands
3) Application.Domain

Obviously, 1) references 2) and 3), but these last two are 'stand alone'. From the beginning I have been thinking that Application.Commands would be deployed both to server and client. But now I was wondering how I could best go about implementing validation. For example, suppose I have an EmailAddress-VO in my domain, which has a static method like so:

public sealed class EmailAddress
{
    public static EmailAddress Parse(string value)
    {
       ...
    }
}

When the value is not a valid email-address, an exception is thrown. However, to prevent invalid email-addresses from entering my domain in the first place, I'd like to validate my commands that contains an email-field before they are send to the server. So I might have a command like:

public class RegisterUser
{
    public string Name;
    public string EmailAddress;
}

Now I could of course implement a simple regex-validation check and put this in the Commands-module. That would keep my Command-module isolated, but it also means that the logic of what is considered a valid email-address has now been duplicated. I would much rather have some validation-logic be able to check with my EmailAddress-class whether or not we are dealing with a valid address, like so:

EmailAddress.IsValid(command.EmailAddress)

The advantage of this approach is that the validation-logic is kept in one place - same goes for the error-messages that could be part of UI-messages or exceptions. The downside of this is that now a reference is created between the Commands-module and the Domain-module, forcing them to both be deployed to the client. This does not have to be a problem of course, but it does not feel like a clean way to do it either.

So basically my question is: how are people implementing the (client-side) validation-logic of commands that's also part of the business logic from your domain? Duplicate your logic and error-messages, or share them and deploy your domain-module to the client as well?

--

Alexey Raga

unread,
May 19, 2013, 7:37:31 AM5/19/13
to ddd...@googlegroups.com
>>Better to double-check than to rely on some upper-layer to protect you.
Protect from what? From an exception thtown by EmailAddress.Parse? 

What you are effectively saying is "I want to validate everywhere" :)

Well, assume you do, and in the domain, or in a handler you call the EmailAddress.IsValid(email) and it returns "false", what would you do then? You know that someone probably workarounded the UI validation and gave you some bad data, so what next? You piss him off and throw and exception, right? :) Because you don't want to compensate for bad hacked data.
So what is the difference then? Why not just call EmailAddress.Parse and let it fail if the address is invalid? Same result: the exception is thrown.

Also, the domain normally speaks in the ubiquitous language. It means that it is command handlers' job to translate the command into something that the domain understand. For example, the command handler will not pass a string to the domain method, it will call EmailAddress.Parse and then pass the result EmailAddress. So the domain will always have valid objects and will not have to re-validate things again. Because if the email address was incorrect, then the command handler will fail doing EmailAddress.Parse and this incorrect data will never make into the domain.

Again, in most of the cases even within my command handlers I will just fail badly if the data is wrong (like invalid email address). The Parse method fails - so be it, you gave me an invalid command - I throw, fair enough :)
In this very scenario the only place where I would _validate_ the email address will be the UI. If someone workarounds the UI then I'll throw at him because I don't like him :) And I don't really care how it happens and when, and I don't see any reason to be worried about it.

My "rule of thumb" is that I will only _validate_ things in a way you want to do validation when there is a _compensation_ logic. But it is another story :)

Cheers,
Alexey.

Wim van Gool

unread,
May 19, 2013, 8:35:22 AM5/19/13
to ddd...@googlegroups.com
Alexey, thanks for posting your view on this. Reading it, I think I did not express myself well enough, because as far as I can see we're on the same page here. Surely, if a command makes it to my message-handler carrying an invalid email-address, then I have no problem letting EmailAddress.Parse() throw an Exception (in fact, this is exactly as I want it).

What I am after is how people are dealing with possible code-duplication in domain-logic and validation-logic - in this case determining what a valid e-mail address actually is or not. I other words: the Parse-method obviously has knowledge of this, but if I design some validation-logic to execute within the UI, parts or the entire logic for this is duplicated: it's present in my domain and in the command-validators. Now I would guess many people will find this acceptable because validation is usually very simple (not-null, not-empty, matches a certain regex, etc), but concerning DRY it's not ideal.

Another example I have in my domain is the concept of a Period - just a simple StartDate and EndDate, but their values must be checked of course. So if a command contains these fields, my domain will throw if they're not valid (Period-VO will do this). On the other hand, this is also a candidate for UI-validation: just check the date-values before you send. The logic to do this is almost trivial (StartDate <= EndDate), and yet you're still duplicating code that might change in more sophisticated scenario's.

So, how would you handle this: just accept some code-duplication or try to encapsulate the logic in shared types?

@yreynhout

unread,
May 19, 2013, 2:36:09 PM5/19/13
to ddd...@googlegroups.com
My 2c ... code duplication is OVER *FUCKING* RATED. DRY is for Martini. Yes, I'm exaggerating, if only to tilt the balance in the other direction. Giving feedback to a user, constraining his input, hinting at the invalidness of his input, is a different concern than prohibiting bad shit happening by somebody/thing abusing the domain model ("what if" kinda questions - risk analysis is probably too big a word).

Slav Ivanyuk

unread,
May 19, 2013, 8:42:29 PM5/19/13
to ddd...@googlegroups.com

In my code EmailAddress is a value object which I pass around in command and store in event. It knows how to validate itself when it's created.

 

So, I can't even send command with invalid EmailAddress because I can't create invalid value object. When I replay events I get value objects too.

 

So I'd have something like:

class RegisterUser

{

             UserName Name;

             EmailAddress Email;

}

 

As much as possible I create value object for any data I pass around. This approach has really helped me to simplify the code, validation, etc. In UI, I can't even create a value object with invalid value. If I need to manipulate value object, it provides convenient methods. It's easy to test, etc.

 

I even almost never use List or Array for collection, but create a value object specifically for the collection I need to pass in the commend. For example instead of having List< ItemCode > I usually create ItemCodes value object specifically for working with ItemCodes.

 

Of course, there's some overhead from this during serialization / deserialization. I decided that benefits in the code outweight this.

 

I think Greg also spoke against using value objects everywhere. Not sure why, my guess would be due to the overhead and potential explosion of value objects (but so far I don't have a problem with this).

 

Slav Ivanyuk

Vytautas Mackonis

unread,
May 19, 2013, 9:15:44 PM5/19/13
to ddd...@googlegroups.com
what happens if you have to change validation logic of your VO and you have events already stored? :)

João Bragança

unread,
May 19, 2013, 9:45:41 PM5/19/13
to ddd...@googlegroups.com
+1 to what Yves said. Your VOs should ensure in their ctor that they are not in an invalid state. Adding these kinds of validations to your UX/UI layer is just icing. And super simple if you do it right. E.g. (assuming you are using the web) if you are databinding your html form right to a command, and use a library like FluentValidation, how hard is that to maintain really?

Wim van Gool

unread,
May 20, 2013, 3:26:17 AM5/20/13
to ddd...@googlegroups.com
+1 to all here I guess. I think it's important to mention that I did you favor or choose any implementation-technique just yet :-). I'm still learning, so I was just curious how people were handling validation. I realize that although some validation-logic in the UI is very similar to the 'business-logic' in your domain, they are two very separate concerns, yet there's always a natural programmer's tendency to try and abstract away these similarities. However, validation is usually so simple that in most cases the only duplication consists of null-checks, regular expressions and such, so I guess you just confirmed that leaving the UI-code separated from your Domain-code is much more important and maintainable than connecting them to reuse a bunch of checks and strings...

@Slav: it's an interesting approach to use VO's in your messages, but how *safe* is it do this in the context of serialization/deserialization? I mean: how would you guarantee that a serialized stream actually represents a valid VO, even though it can be deserialized to your VO-object? Do you simply trust the stream that's coming in?

Wim van Gool

unread,
May 20, 2013, 3:28:03 AM5/20/13
to ddd...@googlegroups.com
....to mention that I did not favor or choose any....

Greg Young

unread,
May 20, 2013, 3:38:56 AM5/20/13
to ddd...@googlegroups.com
Never put value objects in messages. Messages are schema. What happens if you refactor it in your model?
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
Le doute n'est pas une condition agréable, mais la certitude est absurde.

Slav Ivanyuk

unread,
May 20, 2013, 8:33:12 AM5/20/13
to ddd...@googlegroups.com

Even without value objects if I refactor things can break. How can VO makes refactoring worse?

 

And in the very worst case switch to EventV2 or ValueObjectV2?

 

I've never had an issue with this so far. As I use protobuf I can add new members to VO.

Any validation VO happens only on VO creation by the client. It doesn't happen during deserialization, and I try to keep it very simple in VO (e.g. email string is not null and is valid "some...@email.com"). It just checks that VO is in valid format. But it's not the place to check whether the data is valid from the business point of view.

 

If validation rules change, I would still need to be able to handle old, potentially now invalid data. Whatever happened in the past, happened.

 

I trust my event stream, yes. The event with invalid VO wouldn't have been saved simply because command for it with invalid VO cannot be created.

Slav Ivanyuk

João Bragança

unread,
May 20, 2013, 11:14:35 AM5/20/13
to ddd...@googlegroups.com
How do you construct a message then? If your UI is binding directly to public fields / properties then oops you just bypassed your VO's constructor, which should be where you enforce your invariants. If your UI is not binding to the command's fields / properties then you may be writing more boilerplate code :)

Messages are part of the public interface of your application. IMO putting domain objects on the public contract puts an undue burden on the client (not just the UI but other BCs) to know things it probably shouldn't.

Greg Young

unread,
May 20, 2013, 11:17:13 AM5/20/13
to ddd...@googlegroups.com
There is a difference between schema and objects.

In your domain perhaps they are now at the same tier, what if they were not?

Greg
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Greg Young

unread,
May 20, 2013, 11:17:51 AM5/20/13
to ddd...@googlegroups.com
Btw:try a refactor-> rename in one :)
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Slava Ivanyuk

unread,
May 20, 2013, 2:11:11 PM5/20/13
to ddd...@googlegroups.com
I did renames and added properties. It was no problem. Since messages are serialized via protobuf the only thing that matters is that types and order is the same.
I have to be careful when adding properties, in some cases need to provide default value for older messages to make sure the message is still valid.

What do you mean by the same tier or not in the context of CQRS? Could you please give a simple example?

The UI (or any client that sends command) uses constructor (or sometimes static factory method) to create VO.
So, sending command might look like Inventory.Send.SendCommand( new AddLocation( new WarehouseId( 1 ), new LocationCode( "A1" ) );

Now, I have control of the client code and this way of sending commands is used internally.

For external access, such as through webservices API or whatever I don't use VOs.

So, for the command above, through API I could get a call on AddLocation webservices method with json: { warehouseId: 1, locationCode: "A1" }
But, when I'm constructing command to send, if there's an issue (such as empty string - locationCode: "") I'd get exception while trying to create VO for the command.

Slav Ivanyuk

@yreynhout

unread,
May 20, 2013, 6:04:15 PM5/20/13
to ddd...@googlegroups.com
I can see how this would work if you're in a closed system (well, for now at least, ffwd 5+ years when you've moved on #speculative #iknow). But it's somewhat limiting from an evolutionary POV. To me it's about concerns. I don't want to be thinking about catering for clients and serialization when toying with VOs (or any other object) in my model. I might ditch the VO, or split it into multiple, heck, I might even change internal representation. That's the kind of freedom I care about. I'm not saying you can't do it using your approach (because frankly none of those changes are unsurmountable), but I consider the coupling a burden to that freedom at that point in time. Everybody's threshold and choice of trade-offs is different when it comes to that freedom, AFAIK. The same thing goes for messaging related objects. I'll probably care more about the language & semantics of messages and their fields, the schema, and the valuable interactions using those messages. Reusing VO is the least of my concern at that point. Not saying you can't, because obviously that's what you're doing. The choice of "VO reuse" is rooted in having the same tech on both sides. It's a bit schizo as the VOs are more in the realm of the model but due to the reuse of those VOs in the command data structures they get pulled in a different direction as well. Packaging them and keeping sanity in the long run must be a fun project in itself. Especially when you imagine that you're in this multi-BC ecosystem (well, I kinda hope you are, otherwise it's a lotta koolaid to swallow) ... I do not even want to go into what happens if you were todo this for events as well.
My opinion: There's a lot of fruit hanging off of VOs (playing factory, specification, predicate, etc. within the model) you're not getting when you couple them to the messaging bits directly. If you do, sooner or later you'll end up shipping the model (or big chunks of it) itself along with the messaging bits to other BCs. Even within one BC it feels like a slippery slope. The other thing is the freedom within the model. I value that a lot. The mechanics shouldn't get in the way.
I'm pretty sure you'll disagree. But that's allright.

Slav Ivanyuk

unread,
May 21, 2013, 11:40:55 AM5/21/13
to ddd...@googlegroups.com
It's not the question of agree or disagree :) I just chose the path of least
resistance right now and most convenience. Since I don't know what problems
I will encounter in the future I can't predict how to best prepare. Using
VOs, for now, results in simpler, easier to use and understand code. Perhaps
that won't always be the case.

In the worst case I can transform existing event stream to the stream
without VOs. It'll be a lot of work, but doable.

I have 7 BCs. They communicate with each other just fine. Yes, I have to
share contracts and VOs. They don't read each other's stream, only
projections, but even that's very rare. I try to isolate each BC.

I don't see how using VOs in messages would prevent me from having nice
things like factory (which I use), specifications (I have more than 1000
tests, both on aggregate level and BDD Gherkin blackbox tests that confirm
the whole system, all BCs work together as expected), etc.

I plan to keep the system closed :) Any data coming from external world will
come through some custom-built point of connection which transforms data
into correct commands. Nobody but me can read events or put messages in the
queue.

Perhaps I'm misunderstanding VOs. But with messages, I would prefer to group
related data inside the message over having a flat list of all properties.
That's essentially what VOs provide me with. And after the message is loaded
I'm automatically provided with the methods to manipulate that group of
data.

p.s. Sorry for hijacking and derailing the thread.

Thanks,
Slav Ivanyuk

-----Original Message-----
From: ddd...@googlegroups.com [mailto:ddd...@googlegroups.com] On Behalf
Of @yreynhout
Sent: Monday, May 20, 2013 6:04 PM
To: ddd...@googlegroups.com
Subject: Re: [DDD/CQRS] Where should the validation be?

@yreynhout

unread,
May 21, 2013, 4:57:16 PM5/21/13
to ddd...@googlegroups.com
Could you post an example (gist) of a message and a value object it uses and how that value object acts as a factory and/or specification?

Dennis Traub

unread,
May 21, 2013, 5:16:41 PM5/21/13
to ddd...@googlegroups.com
I think OP means a different kind of specification. Not the DDD pattern but the BDD type spec


--
Dennis Traub
Software Development Consultancy

Am Bogen 7
33178 Borchen

Phone:  05293/73942-73
Fax:    05293/73942-74
Mobile: 0170/2842385
Mail:   ma...@dennistraub.de

Slav Ivanyuk

unread,
May 21, 2013, 10:52:40 PM5/21/13
to ddd...@googlegroups.com

I cannot. I use factory methods with VOs, or VOs within. But I cannot see how VO can act as a factory and/or specification?

 

Could you post a sample of what you're talking about?

 

Sample of my aggregate test:

 

[ Test ]

public void when_no_item_in_inventory()

{

             this.CreateContext();

             this.When( new AddItem( Id, Code, ItemLocation, 10, this.TransactionReason ) );

             this.Expect( new ItemAdded( Id, Code, ItemLocation, 10, QuantityDifference.With( 0, 10 ), this.TransactionReason );

}

 

When - setup command

Expect - setup expected event.

 

Slav Ivanyuk

@yreynhout

unread,
May 24, 2013, 6:45:08 AM5/24/13
to ddd...@googlegroups.com
https://gist.github.com/yreynhout/5642583

A rollout period is a period in time, usually expressed as dates only, that needs to be rolled out or was rolled out, depending on how you look at it (I know the context is a little vague, but does it matter). It plays a factory-like role when it comes to telling which dates it encompasses. It can tell if it encompasses a particular date which could be useful when used in conjunction with say a specification. There's more to it from a behavioral POV but I wanted to keep it short. It's not a message data structure. It's a value object. It's not particularly friendly to the serialization fxs out there (no attributes, no public properties, no public ctor or private parameterless ctor). Now I could beat into submission and expose the From/To as properties, and add a public or private ctor to please my serialization needs. But lo and behold, I've just suckered a reference to NodaTime and a static class into my message library (either I put it in the message lib or put a reference to the model lib, whatever). I'm not even sure it will play ball with the serialization fx I might choose. Along comes the next less savy developer, and starts using those public properties for behavior that should've been in that class in the first place, scattering it throughout the code base (I'm deliberately exaggerating). Yet, most of this is besides the point. Afterall, your way of working could be different, more disciplined, etc ...

I set out to create that value object due to conversation & modeling if you will. Not because I wanted to have a data container for two dates so I could transport them over the wire. That's a pretty important distinction if you ask me. It's there for a different purpose (responsibility, whatever). I hope this conveys at least my point of view.

Regards,
Yves.

Slav Ivanyuk

unread,
May 24, 2013, 10:22:51 AM5/24/13
to ddd...@googlegroups.com

Yves, it does, thanks.

 

Yep, you're right. The fact that I use VO in messaging makes VO more complex, such as having extra attributes, or private constructor or whatever.

On the other hand I get a ready to use VO from the message. I don't have to write extra code to convert data in the message to VOs.

 

I guess it's a matter of preference and the project J Still, thank you for taking time to explain.

 

Slav

Alexey Raga

unread,
May 24, 2013, 12:21:31 PM5/24/13
to ddd...@googlegroups.com
I would not use VOs in commands.
One way of doing it:

- your command handlers have reference to the domain AND to messages, as you said.
- your domain talks in the UL, so it accepts the EmailAddress as a parameter of one of one of the aggregate's methods.
- the command handler can do EmailAddress.Parse, then construct the aggregate and pass the valid email in. Or it can "validate" first if you want.

And I don't care if some regex will be the same or similar in JavaScript UI and inside EmailAddress type or in my command handler.

In fact you can even question whether you do need Parse method there or not. Do you _really_ parse it there? Do you really need it to be deconstructed internally? Or is it just another fancy way of doing validation? ;)

If you don't, why not validate the string explicitly in the command handler and then just pass a valid string in a constructor of EmailAddress which will not validate anything just assuming that the parameter is correct? In the email case it will just assign the property and that's it.

Another example can be, say, a projectname. What if you have a validation rule that it must be at least 2 chars and at max 10 chars long. It is NOT a business rule, it is a validation rule.
Do you want to enforce this rule in the VO?
What if in a week they tell you 'no, let's make it 10 to 20'? Not only you will have to change your VO to update the rule. You will have to deal with the existing data which does not comply with the rule. Should you still be able to construct VOs with 'old' data? Sure. Does it look weird then that there is a 'backdoor' somewhere in the VO which allows you to initialize it with invalid data? Sure it does.

I am trying to make a point that _validation_ and _business_ rules are different and are different concerns.
There may even be situations where you will have different _validation_ rules for different scenarios, even for the same VO or whatever.
Say, a command from the UI cannot accept username starting with $, but the 'system' command can do it! And from the Username VO point of view it is a perfectly OK in both cases.

That's one of the reasons I prefer keeping validation outside the domain and let my domain assume that everything passed to it is valid.
That's why I look at validation as of validating _commands_: what is required for one command can be optional for another, what is acceptable for one command can potentially be wrong for another.

And I totally agree with Yves: figuring out some totally reusable-everywhere validation layer not only can complicate your logic, but it also can limit you in some cases.

Cheers,
Alexey.

João Bragança

unread,
May 24, 2013, 1:13:12 PM5/24/13
to ddd...@googlegroups.com
public override int GetHashCode() {
unchecked {
return 666 * _from.GetHashCode() ^ _to.GetHashCode();
}
}
hah!

@yreynhout

unread,
May 24, 2013, 1:55:59 PM5/24/13
to ddd...@googlegroups.com, joao...@braganca.name
I was wondering if someone was going to notice it ...

Kijana Woodard

unread,
May 24, 2013, 2:35:25 PM5/24/13
to ddd...@googlegroups.com
:-)

Wim van Gool

unread,
May 27, 2013, 3:19:41 AM5/27/13
to ddd...@googlegroups.com
...In fact you can even question whether you do need Parse method there or not. Do you _really_ parse it there? Do you really need it to be deconstructed internally? Or is it just another fancy way of doing validation? ;)...

The second. :-) But that's more of a personal habit: whenever I a string has to be throroughly syntax-checked (even if you're just matching a regex internally), I feel a static Parse communicates best what's happening, even if I'm not deconstructing the string internally.

...If you don't, why not validate the string explicitly in the command handler and then just pass a valid string in a constructor of EmailAddress which will not validate anything just assuming that the parameter is correct? In the email case it will just assign the property and that's it....

Assuming you do have policies about the string-values making up a valid EmailAddress-VO, is it not the job of the VO to protect it's own integrity..? What about *other* handlers that may want to create EmailAddress-instances; wouldn't this cause vital validation logic to be spread through your handlers and *heaven forbid* some junior/new teammember forgot one somewhere?

... What if you have a validation rule that it must be at least 2 chars and at max 10 chars long. It is NOT a business rule, it is a validation rule...


An interesting point. To be honest, I did think that such logic would (also) be part of the VO / Business Logic. I agree that validation and business rules are different, but deemed validation rules more like a subset of business rules, implemented for the sake of optimization (don't let invalid commands to be sent if you can help it) and usability (inform the user quickly about any validation errors), but not as a vital part to protect your domain from invalid input per se.

...What if in a week they tell you 'no, let's make it 10 to 20'? Not only you will have to change your VO to update the rule. You will have to deal with the existing data which does not comply with the rule. Should you still be able to construct VOs with 'old' data? Sure. Does it look weird then that there is a 'backdoor' somewhere in the VO which allows you to initialize it with invalid data? Sure it does...

A valid point, but this goes for *all* business rules changes (assuming you would implement these checks into your VO). New business rules can always make 'old data' invalid. It's then up to the business how to handle this: perserve the old data as valid cases, or transform it to the 'new form'. Now I'm not saying I totally disagree, but there's multiple ways to look at this and solve this of course. :) I do think that looking at it your way can help prevent certain migration-problems (unless the business wants to invalidate and transform old data anyway, right?).

Concerning your other example about different validation rules for similar commands: you might also model those as two separate VO's in your domain: UserInterfaceCommand and SystemCommand, both with differing rules on what's considered valid and what not.


Greg Young

unread,
May 27, 2013, 3:38:08 AM5/27/13
to ddd...@googlegroups.com
I want to send you a command from JavaScript how shall we do this? Small talk?

Wim van Gool

unread,
May 27, 2013, 3:43:13 AM5/27/13
to ddd...@googlegroups.com
@Greg: which post/issue are you referring to..?


--

Greg Young

unread,
May 27, 2013, 3:49:05 AM5/27/13
to ddd...@googlegroups.com
Replied to wrong email sorry for yours...

What if the validation has changed...


Well then maybe you support both maybe you change old data but yes you still validate when loading (what would happen if you didn't).

Greg

Alexey Raga

unread,
May 28, 2013, 4:26:24 AM5/28/13
to ddd...@googlegroups.com
>>is it not the job of the VO to protect it's own integrity
Your entities and VOs are indeed protect their invariant. This means that in any behavior called this object will not go to a wrong state. Including creation. Which means that at any time when you have a domain object, whether it is an entity or a VO you assume it is _already_ valid. And you don't have to validate it anymore.

Just like you can _validate_ if you string is a valid Guid and then create a Guid from it, or you can just call new Guid(myString). If it works - you have it, if it was a wrong string - it fails. You never need to _validate_ if you had a valid string in the first place.
But there are may be cases when the same VO may be "valid" for one command and "invalid" for another. For example, in some cases you _must_ have the email address, for others it is optional. So you validate your _command_, construct your VOs and only then call the aggregate. At least that's what I think :)

>> but this goes for *all* business rules changes (assuming you would implement these checks into your VO). New business rules can always make 'old data' invalid.
It really depends. If I don't want to accept project names more than 10 chars anymore, does it make the existing ones invalid? I don't think so. It is just new ones will have at most 10 chars in their names. It ill be perfectly OK with business to keep "old" things as they were. Sometimes it is undesirable or impossible to change existing data. What if that project name was used as a domain name? What if people have emails on this domain? And a lot of correspondence has been sent in and out? You cannot just say "since tomorrow your email address is this and no longer that", people are waiting for replies, etc.
Your just don't want to accept names like "my_super_duper_project_is_the_best_in_the_world_and_in_this_system_as_well" :)
To me this is _validation_ logic, not _business_ logic.

>>you might also model those as two separate VO's in your domain: UserInterfaceCommand and SystemCommand
I will most certainly model those as two separate _commands_, but each of these commands can lead to creating the same type of VO. Say, Price. Or EmailAddress. Or ProjectName.
Both of these commands are about to create a Project so they need to convert some "string projectName" into ProjectName VO. 
It is just that SystemCommand is allowed (but not required) to create projects with names starting with "$", but UserInterfaceCommand can never do it. From my system point of view "$superProject" is a valid project name, so my ProjectName VO can accept this.
But I will _validate_ this string where I handle UserInterfaceCommand, and if the project name starts with "$" then I'll fail this command. Because this value is not valid _for this command_.

Cheers,
Alexey.
Reply all
Reply to author
Forward
0 new messages