By Peter Bell

Validate What?

Validation. Client side, server side, it's one of these things we all have to deal with on our projects. I finally got a chance to sit down with Bob Silverberg to check out his ValidateThis fromework at cf.Objective() and I liked what I saw. You describe your validation rules in XML, it supports multiple contexts so the same object can have different validation rules depending on (for example) the form being used, security permissions or state of the object. It seems to have a clean interface, it does a great job of handing client and server side validations and it seems to be a pretty elegant solution to a really common problem.

I know we've all got our own little validation libraries and approaches, but I'd strongly recommend anyone to check out what Bob's been working on. I haven't had a chance to work with it on a project yet, but I'm hoping to use it on my next project and to get quite involved with the framework as I think it would be great for us to have a nice, elegant validation library that we could then put into larger frameworks for building full stack solutions more quickly while still being able to use it on its own for projects that don't need the other bells and whistles.

Expect to see more about ValidateThis on my blog as I get a chance to play with it. In the meantime, check it out and join the Google group to become part of the conversation.

Comments
Peter - Admittedly, I have not looked to ValidateThis yet, but one thing you said caught my eye. Should a business object ever contain invalid data and thus need validating? This was one of the things we discussed when building Validat (the Alagad validation framework) and I was never in favor of stuffing potentially erroneous data into a business object, to then validate it. Why not validate the structure of data coming in from the form (or wherever) before creating the business object and populating it?
# Posted By Jeff Chastain | 5/21/09 10:18 AM
I'm a huge fan of a business object being able to contain invalid data. Most of the business logic we encounter in ColdFusion relates to validation, and to me, the business object is the perfect place to encapsulate that. It also often interconnects with other elements of the business logic. For example you might want to run validation rules against the output of a custom getter on the object as opposed to running it against the elements of state used to populate the object (trivial example, you might want to say we only allow users over the age of 13, but you need to call getAge() which calculates it from the DateofBirth which is what was contained in the form field.

I find the whole "an object should never be invalid" a little bogus and I find the practical benefits of putting validations in the object wildly outweigh any other concerns I've heard to date. Have you actually ever heard someone come up with a compelling software engineering reason for an object never being instantiated in an invalid state? When I look at the flow of my applications, I don't just load the form scope into a bean, and then forgetting to validate it try to do something it might fail on if it's invalid. Even if I was drunk I don't think I'd do something that silly. Then when I compare that to the benefits of encapsulated validartion and the risks of an anaemic domain model with service classes containing all of the business logic and dumb VO's running round as what is effectively expensive structs, I am quite happy to put the validation within the beans!
# Posted By Peter Bell | 5/21/09 10:43 AM
I have not necessarily run into issues with having invalid data in a business object, although I could see potential issues if calling a method on the business object expected the internal data to be in a certain statue and thus when it was not (invalid) then that might cause an error.

The bigger issue which I am dealing with now is that many times you cannot validate a single business object on its own. For example, when a new user profile is created - that user profile is made up of a collection of objects and it would be much easier to validate all of the form submitted data as a unit representing a user profile rather than trying to write validation rules that are interdependent between a collection of objects. For example, a validation rule checking to see if the user has at least one address provided and that there are no duplicates has to deal with the user object and multiple address objects which makes validation at the object level much more complex.
# Posted By Jeff Chastain | 5/21/09 10:50 AM
Looks like my rant turned into a posting - thanks for the inspiration Jeff :)

http://www.pbell.com/index.cfm/2009/5/21/The-Impor...
# Posted By Peter Bell | 5/21/09 11:10 AM
Hey Jeff,

I hear you. In my experience the "if a method was called on the object in an invalid state" is a little bogus just because it's not like I'm just sending my bean all round my app. I have the following code:

User = beanFactory.getBean("User").load(form)

If (User.isValid)
. . .
else
. . .

so there isn't a lot of space for that.

As for the related objects, that all comes down to object composition which is a bit of a pain without a tool like Hibernate to handle all of the joining and persisting and the like, but it;s still a fairly solvable problem in the general case - especially when an object only has sub objects - not sub-sub objects - which covers most common use cases in ColdFusion.

In general, your User.isValid() will include a private User.isValidBillingAddress() method that'll call against the composed BillingAddress.IsValid(), so it's fairly straightforward. The only slightly tricky thing is to write generic code that'll create and populate sub objects from form fields in the general case, but once you get your head around it, it isn't too hard to code.
# Posted By Peter Bell | 5/21/09 11:15 AM
If you had the following code:

User = beanFactory.getBean("User").load(form)

rather than calling User.isValid() or some method like that, what if the load() method threw an error or exception that could be caught if the object could not be created with a valid state?
# Posted By Marc | 5/21/09 2:39 PM
@Marc,

That sounds like a really elegant enhancement. Its mixing both a command and query into a single method call which some people disapprove of, but I find it often creates a cleaner API (my ibo's have a next() method that both increments the iterator pointer and returns a boolean for whether there is a next record). I'll have a think through the implications, but I think I might give that a shot for my next project to see how it works out!
# Posted By Peter Bell | 5/21/09 3:28 PM
@Jeff (re validating isolated business objects):

The missing piece here is the notion of the collection object. A business object can be valid in itself, but it may be invalid to add it to a given collection. What you're describing is the validation rules for the collection's "add" method. Those rules may be different for different collections.

To take this a little further, every business object belongs to (at least) the collection of all objects of that type. Thus the idea of instantiating a business object on its own completely disappears. Instead, you ask the "all" collection to create a new object as a member of itself based on some inputs you give it. The collection may, of course, decline. This is exactly analoguous to inserting a record into a table with uniqueness constraints. We don't create a free floating record and then add it to a table.

This approach is kind of hard to do in ColdFusion, and even in Java where the tools definitely exist it's rare. Still, I find it a useful concept to help make sense of the apparent conundrums of validation design.
# Posted By Jaime Metcher | 5/21/09 7:12 PM
@Jaime

Great point! I never thought of it that way but I should now since in Flex I'm always working with collections. Everything is very collection driven. You could say the same for CF but I just never thought of it that way since I just used query objects rather than a collection object.

Do you handle your validation within a collection object (adding a new one) or a service object (requesting a collection or a single object)?
# Posted By Javier Julio | 5/21/09 8:24 PM
@Javier:

Not sure exactly what you mean, but I think the former - collection constraints are handled by the collection. The service is really only used to get a reference to those top-level collections, and maybe for some use-case logic.
# Posted By Jaime Metcher | 5/21/09 9:00 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.