Saturday, September 30, 2006

Validation IV

I figured I would write a bit more about validation after my last three already long winded posts on the subject. Basically this is just a brief synopsis with an example and a few minor elaborations. My major conclusion is that all domain-level validation that one would think to put into setting methods or initializers/constructors should instead be done via a single method for each domain object. Let's call that method valid, or isValid, or validate. Ideally, rather than throwing an exception every time it finds an error, this method would add messages as it goes along, and would only throw an exception when it's done. In Java, here's a typical example:
public void validate() throws ValidationException {
Messages messages = new Messages(this);
checkStartDateAndEndDate(messages);
//more validations go here
if (!messages.empty())
throw new ValidationException(messages);
}

private void checkStartDateAndEndDate(Messages messages) {
if (Util.empty(startDate) || Util.empty(endDate)) {
if (Util.empty(startDate))
messages.addError(Messages.ENTER_START_DATE);
if (Util.empty(endDate))
messages.addError(Messages.ENTER_END_DATE);
} else if (Util.before(endDate, startDate)) {
messages.addError(Messages.START_DATE_MUST_PRECEDE_END_DATE,
startDate, endDate)
}
}
I think it's important to avoid performing domain object validation in setting methods, and instead to collect these validations in a single method. The reason, as stated in my earlier posts, is so this method can be called to validate dependencies from different objects, not just when this particular object is being instantiated or modified. However, what of getting methods or methods that calculate or process (the difference between such methods and simple getting methods is not obvious to me. I consider it to be the difference between methods called during basic data entry vs. methods that are called afterwards)? It's not possible to avoid validating while processing, at least I don't think so in most cases. I am not sure, it may be possible in theory, but in practice you really can't validate all the possible results of calculations before actually performing those calculations. Therefore there will always be method calls on objects which can generate meaninful exceptions (i.e. not bugs) even though the validation methods used to save objects entered into the system have all passed. I suggest using a different type of exception when throwing these kinds of errors, maybe something like ProcessingException instead of ValidationException. In a language with compile-time exception checking, that has the added benefit of helping to make sure that you are not calling methods that throw ProcessingException inside of your validation methods.

1 comment:

Jeff Perrin said...

I also like the idea of just having an isValid() method type solution. I did a 1 day spike on our Well class to look at implementing our validation as separate business rule objects. This way, you can easily validate based on a given context, so you could have different rules be applicable during creation vs during an update (as an example).

I was particulary inspired by this post:

http://www.jpboodhoo.com/blog/ValidationInTheDomainLayerTakeOne.aspx