I\'m writing a VB.NET Winforms project based on MVVM (using Winforms binding). My instinct is to never allow a domain entity be in an invalid state. This requires that I d
No, in my opinion domain entities should never be allowed to be invalid, even temporarily. The problem is that it if you allow the domain to be invalid, just like you described in your question, it gets difficult to introduce new rules as complexity grows. For example you allow entity to be invalid due to some attribute, assuming that it will be validated later. But before that happens someone adds another rule, that varies its result in accordance to the same attribute - how do you know if the rule behaves correctly? You don't. Believe me, it happens quite often in non trivial domains.
The other reason for nor allowing state to be invalid is that in certain scenarios it can introduce problems with ORMs - I have personally seen an issue involving NHibernate cache and sub-entities that were invalid but somehow still remained in cache, I can't recall any specific details though.
The technique I tend to use bases on validation rules and validation results. In short, most of the methods on entities is implemented in the following way (C#, if you don't mind):
public virtual void ChangeClaimEventDate(DateTimeOffset newDate)
{
var operationResult = ValidatorOf<Claim>
.Validate()
.WithCriticalRuleOf<EventDateFallsIntoPolicyCoverage>().WithParam(newDate)
.WithCriticalRuleOf<EventDateFallsIntoInsuredCoverage>().WithParam(newDate)
.WithCriticalRuleOf<PerformedServicesAreAvailableOnEventDate>().WithParam(newDate)
.WithCriticalRuleOf<EventDateCannotBeChangedForBilledClaim>().WithParam(newDate)
.ForOperation(this);
if (operationResult.OperationFailed)
{
throw new InvalidBusinessOperation(operationResult);
}
SomeDate = newDate;
}
The most important thing about this code, is that certain validation rules are checked even before the entity is changed. This example shows usage of result sets, as very often I need to provide information about validation even if it succeeds (in other words, I have validations that fail and information about it has to be shown to user; however the domain entities are still valid.
The OperationResultSet
and ValidatorOf
are pretty simple infrastructure classes that allow adding new validators easily with fluent interface. The validators are implemented as classes implementing IValidator
interface, which allows implementation of pretty complex validation rules and it is easier to test them individually as well.
My point is, that validation should be performed before the changes to domain entities are performed - with the right convention and some infrastructure it even simplifies the code structure.
Edit note: due to some critical voices for this answer, I've decided to change the sample code to one that throws an Exception instead of returning results. Although I still believe that it is the way to go for my kind of scenarios, I agree that without specifying full context this might be misleading - the Exceptions should be indeed the first option and additional factors should exist to choose alternatives.
Firstly, no, domain objects should never exist in an invalid state.
I think the confusion you are having stems from the fact you are trying to power your UI screens from domain objects (and you are definitely not the only one), i.e. binding to your domain objects properties. You shouldn't. Your UI should get it's data from the properties of a view model; a purpose built UI object, which is allowed to be in an invalid state, and can make use of any cool UI validation frameworks.
Domain objects should only come into play in the context of a command/transaction. i.e. the user has selected a view model object from a list on the screen and wishes to perform an action on it. Typically the UI will then call an application/command service method for the action they wish to perform, passing the ID from the view model the user has selected. This will then retrieve the domain object from it's repository and invoke the appropriate method.
In terms of where the view model object comes from: I have a separate query service that the UI calls. This provides 'flat' (de-normalised aggregated data) DTO's which can be used to populate view model objects or act as the view models themselves. This service is unaware of any domain model and simply returns projections from the data that the domain objects conduct transactions over.
I can't recommend enough reading up on CQRS, even if you only take up certain aspects of it. Not only does it help make practical sense of DDD, but if implemented well it can really help with the performance aspect of getting the data to your UI screens.
Your instinct is right. In DDD objects should never be allowed to enter a state that is not valid from domain perspective. Even temporarily. Objects should protect their internal invariants, this is pretty basic OOP. Otherwise it would not be an object but just a dumb data container. Often times people get confused by the UI frameworks or they overgeneralize the term 'validation'.
For example every Product in your system should have SKU. Or every Customer should have social security number. Enforcing these rules is the direct responsibility of Product and Customer entities. Good old ArgumentNullException will let client code realize that it broke some invariant. Enforcing this rule is not a responsibility of UI or some abstract 'Validator'. If you let this rule be enforced outside your entity you will:
eventually end up with invalid state which can result in crash or will require you to write some compensation code to avoid this crash
more importantly, you will not be able to reason about the Product by just reading Product code
Furthermore business rules are usually more complex than that so it would be even harder to enforce them outside of the entity without breaking its encapsulation. There is another group of rules that can be easily enforced by using DDD Value Object. In the above example you would create class 'SKU' and 'SocialSecurityNumber'. These classes will be immutable and will enforce all the formatting rules. They can also have static methods like:
SocialSecurityNumber.TryParse(String untrustedString, out SocialSecurityNumber)
or
SocialSecurityNumber.IsStringValid(String untrustedString)
UI can use these methods to validate user input. There is no reason for UI to 'break' objects even temporarily. If you let this happen you will end up with Anemic Domain Model. Unfortunately a lot of sample code on the internet promotes this approach. The bottom line is that your validation rules are coming from your domain and they should be enforced by domain objects.