Previously, I've talked about doing all data "value" validation in the Save() method of my Service objects and then just returning a collection of error flags. I now have one more reason to think that this is a good tactic - SQL errors. See, data validation happens on so many levels: client validation, data type validation, data value validation, and then lastly, SQL constraint validation. I might have code that says a value is valid, but then the SQL server throws an error because the insert or update fails to meet some constraint (such as duplicate primary keys).
This type of error will only ever be thrown if the Service object has invalid data but thinks that the data it is dealing with is valid. Therefore, this type of data validation flag will have to be handled by the CFTry / CFCatch tags that surround (or will surround) my SQL interaction.
I'm not explaining my thoughts very well, but what I'm trying to say is that if some of the data validation can only happen at the database interaction level, we might as well limit the data validation to only the method that interacts with the database. If we spread our validation out across various API methods, then we might provide false positives (of valid data) to the programmer. Meaning, if the programmer depended on ServiceObject.Validate( Bean ) to test for valid data, there is no way that that validation could be 100% accurate since it does not take into account SQL server level data validation.
Long story-short, the only way to provide fully accurate validation is to do it in the ServiceObject.Save() method.
And, while writing this, I am actually reminded of another excellent point that is quite relevant. A while back, Frank Yang, CTO / CIO of RecycleBank, was discussing duplicate data validation with me; specifically, we were discussing the problem of not allowing duplicate email addresses in a given table. To handle the situation, I would check for duplicates as part of the form validation. If no duplicates were found, I would then proceed to process the form. He argued that this was a gross misuse of processing power - why waste time programmatically checking for duplicates when the SQL server is highly optimized to handle such checks. My counter argument to this was that if we relied on the SQL server to do the duplicate checking, we would have to handle form validation in two places: once before processing and a second time to catch any constraint violation errors that were thrown by the SQL server.
At the time, I felt like it would be a pain to handle multiple bouts of validation (especially since it was not easy within the framework of the existing application); however, now, within the context of object oriented programming and the validation of data at the point of SQL interaction, I can really see where Frank Yank's suggestion would make a lot of sense. Think about it - dealing with duplicate emails is far more the "edge case" than the inserting of unique email addresses. As such, dealing with that validation should also be the "edge case" (ie. catching an exception) and should not be allotted consistent processing time.
That all being said, I think I am going to move ahead with a Richard Kroll style of data validation (as commented on in my previous post). I like the way that his validation flags relate the Service Object to the controller code, but not in so tightly a way that it would break if the internal rules of the Service Object changed (it wouldn't work, of course, but no data would be corrupted and no errors would be thrown).