Validat: Why it doesn't meet my needs
Posted by Joe Rinehart at 12:36 PM
7 comments - Categories:
ColdFusion MX
Validat is a new open-source framework from the Alagadians focused on simplifying data validation. At present, I'm not sure what advantages it provides me over my current architecture, and that's why I'm writing this post. It's not a flame. It started as an e-mail to Doug and Jeff, but turned into a post when I wanted to outline how I accomplish the same architectural goals as Validat without a framework.
Disclaimer: I told both Doug (Alagad owner) and Jeff Chastain (Validat author) both that I was writing this post. It's definitely a "cause thought" post for both ColdFusion developers and Validat's authors/owners. Validat's purpose is to provide a reusable set of validation components that can be arranged and configured to create reusable validation rules. It provides a series of simple validation classes ("validateDate") that all implement a validator interface. By arranging these validators into rules (using xml) and defining data sets (also using xml), you can request for a data structure (a ColdFusion structure) or a CFC to bean validated against the associated rules. When you ask Validat to validate something as a data set, it extracts your data to a ColdFusion structure then applies the validation for the associated data set to the structure.
Points where I'm stuck with Validat include:
1. Validation involving domain logic doesn't seem to be supported.
I worked with an event scheduler a while ago. My validation went a good ways beyond "Is event name filled out, simple, and 50 characters or less?" My domain model was rich, and part of its validation routines were questions into the domain model (e.g. event.hasConflicts() ), where an event knew how to check itself for conflicts with other events.
Because Validat extracts all of my data to raw ColdFusion structures, I'm not sure how I'd be able to build a validation rule that'd check this.
Basically, I need to create validation rules that can use business logic in my domain model, and I don't see any way to do it. Maybe I'm just missing something?
2. I don't see an advantage of Validat over a simplish factory setup that I already use.
I've long been an advocate of separating validation logic of domain objects in decent-sized applications to classes outside the objects. It's quite often that you'll have different sets of validation rules for different contexts. A Contact may only need a first name to save, but may need a valid e-mail address to be sent an e-mail message: that'd require two different validation rules.
Validat seems to be of the same opinion, but that's where our implementations start to differ.
Validat uses a combination of extensible simple validator CFCs (defined in code), validation rules (configured in XML) and data sets (configured in XML) to create what's basically a factory for validation rules.
I've accomplished the same architectural end for a while, using no framework. I'm not sure what I'm missing that Validat provides. Instead of a scheme that necessarily requires XML configuration, I use a series of CFCs that may or may not be externally configured (I use ColdSpring when needed).
Aside: Borrowing from Simon Horwith's playbook, this isn't a "framework" or anything easily releasable. It's just a set of CFCs that I copy then modify on a per-project basis.
Basically, I'll typically have a ValidationRuleFactory that has two methods:
createRule(thingToValidate:any, ruleName:String=null) invokeRule(thingToValidate:any, ruleName:String=null)
CreateRule just creates something implementing an interface (IValidationRule, for the sake of argument). If ruleName is defined, it'll explicit create a rule from an internal dictionary of ruleName:IValidationRule mappings (often passed into the factory's constructor via ColdSpring). If there's no rulename, I assert that I'm validating a component, and I'll look up a default validator for the component (by component metadata name) in a similar dictionary. Rules are cached, and therefore are stateless singletons.
InvokeRule just does createRule and calls IValidationRule.validate(thingToValidate:any, errorCollection:ErrorCollection):ErrorCollection. I normally use the validation error collection that's part of Model-Glue as the return type of validate().
I have a number of small IValidationRule implementations, similar to Validat's, such as DateRule. They normally require bits for their constructures, but I try to set defaults for all. DateRule needs things like isRequired, minDate, maxDate, etc.
If I want to validate a contact for persistence, I'll probably write a rule called ContactValidForPersistence, and I'll compose it of a bunch of other little rules: it'll probably have a firstNameRule that's an instance of StringRule checking for requiredness, length, etc.
As a summary of my approach:
I use composition of smaller IValidationRule instances to build big, domain-specific IValidationRule instances, which is functionality Validat seems to spread across its <validationRules> (small rules) and <dataSets> (domain-specific rules) configuration blocks.
Then, I use a ValidationRuleFactory that first allows me to map both components to default IValidationRule implementations and to create rules-on-demand by name.
It's simple and lets me build very complex rules that can be changed elegantly.
I do see one thing that Validat buys me that my bits have an issue with: Validat could validate both FORM contents and a CFC instance against the same dataSet definition because it extracts data to raw structures. My rules would be looking for either beans (getting data via Getter functions) or a struct. If I've got a struct and a bean whose data structure are so identical where I could use the same dataSet, though, why wouldn't I just validate either the bean or the structure?
Summary
I'm not sure what Validat buys me other than being able to validate a bean and a like-structure structure as the same data set, a situation in which I've never found myself. I also don't see how to perform validation that involves my domain model.
That's not to say I think the framework isn't without a use or potential: being able to abstract rules from their implementation could have great use, and it's something I can't get out of my validation rule factory / composed rule setup.
If there was a way to transform the rules defined in Validat's XML (not just the rules but the datasets) into Javascript validation or SQL constraints, letting me define all this validation in one place and generate it across all sorts of application tiers, I'd be very inclined to start using it!
Further, having a domain-specific language for defining validation (Validat's XML file) makes it handy for non-programmers to express their validation needs.
Update
Anyone want me to commit ValidationRuleFactory to RIAForge? I'd be happy to work with some others on fleshing out a good library of simple rules and some examples of building large rules.
Robb wrote on 11/07/07 3:08 PM
Please go ahead and commit ValidationRuleFactory to RIAForge, as I think it would very helpful for us MG'ers. I have noticed that the validation topic and how/where it fits into the various patterns has stirred some difference of opinion in other blog posts. It seems that your ValidationRuleFactory is in a utils/validation layer??