Despite the fact that I've written a lot of DDD code, I'm frankly still unsure of the terminology and I'm not sure there's a community consensus. I've largely stopped using the jargon of DDD and found I had a lot less gnawing questions like the one you're posing.
So another way to state the problem using practical terms is...
Getting outbid by someone with a lower bid would really piss off your users, as would placing a bid on a closed auction. So we need to make sure that doesn't happen.
Validation when reading data
When you display the screen for the user to enter a bid, you're of course going to have some validation for the user that the bid must be larger than the previous bid (e.g via jQuery) and that a bid can only be accepted when in the CallForBids
stage (e.g. by only displaying the form.
You have to do this validation or you'd be giving the user an awfully crappy experience - allowing them to enter a bid only to be told the auction is closed. So we know you have to express those rules in some way when reading data. However, the key thing is this:
You cannot guarantee that whatever you display on the screen based off the information at the time A will be true by the time the user performs an action which writes data at time B.
So the validation here does not have to be airtight. Don't sweat it that much. Even if you screw up by duplicating the logic, we can't 100% guarantee a write will go through anyway.
Validation when writing data
Data on the screen gets stale as we observed above: The user may have entered a bid after the auction has closed or the minimum bid may have gone up since the data was displayed on the screen. Therefore, in order to avoid a system whose state is in violation of the business rules (and therefore is unreliable and has no integrity)...
You have to check against the business rules when writing data and you have to do this within the same transaction or you can't guarantee consistency.
(There's also eventual consistency, but that's a whole other ball of wax that's outside the scope of this answer.)
So what's that mean for you?
- Your command handler is the aggregate/transactional boundary/whatever the hell people are calling it this week.
- That command cannot succeed (should throw an exception) if either of those 2 rules are broken. No state should be changed.
- That command should be assumed to succeed. That is, from your MVC controller do not add any special error handling for a failed command. Command failure is pretty rare, but it will happen from time to time.
- Any internal implementation doesn't really matter: If you want to have 2 classes, one to enforce each rule, go right ahead. It doesn't really matter to the business as long as the rules are enforced within a single transaction. And that's what you should focus on.
- And thats what you should be testing as well - only that the exception is thrown when the command's parameters are invalid with respect to the state of the system. (You would test success only if it publishes an event that will trigger other handlers.)
Hope that clears it up.