Where Should Server-Side Form Validation Go?
One question that I am trying to get a handle on is where is the best place to put server-side form validation. The most common place I have seen recommended by several prominent folks within the community is that validation should live within the bean. Along these lines my generator actually does generate a validate() method. Others have also looked into this topic lately. Jeff Chastain of Alagad wrote several entries on the topic earlier this year. His posts focused on a more generic server-side validation framework. Clearly there is no single answer to this question. However, I am finding the more I think about it, I don't like either of these solutions. Let me explain and then discuss where I have settled, at least for the moment.Server-side Validation in the Bean
Let me start by saying that I do think that a validate() method in your bean is useful, particularly to make sure a bean is valid before sending it off to be persisted. However, my current thinking is that this should not be used as your form validation. First, it assumes that somehow your form, which is obviously part of your UI, is somehow tied to a specific implementation of an object within your model. This clearly isn't always (or perhaps even rarely) the case. For instance, let's take a multi-step form for user information, all or portions of which may make up my user object. In this case, you can't validate the data from step 1 against the validate() method of your user object because it would clearly be incomplete. However, you would want to provide validation feedback to your user at each step. As a second example, let's take the common "confirm password" field in a form. This field actually has absolutely nothing to do with your data within your model. Clearly you aren't going to put validation for the "confirm password" field in your bean. Form validation, in the end, seems like part of the UI to me, even if it is occurring on the server. (for the sake of this discussion, I am not taking client-side validation into account, since, in the end, some combination of both client and server side validation are required).
Server-side Validation via a Generic Validation Framework
The concept of a validation framework that Jeff and others propose (some so already exist) seemed intriguing to me at first. I like the idea of being able to re-use a number of pre-baked rules throughout my applications. However, once you go down this path, you need to configure the framework, which means learning how to configure it, and so on (Jeff's idea seemed to be to create an XML config). In the end, I can't get past how you aren't still building, in one manner or another, a specific validation pattern to match a specific form. To me it seems that the one form to one validation scheme is unavoidable, since you are validating a specific implementation of a specific form in a particular UI (for example, your Flex UI form may differ from your HTML one which may further differ from a mobile version and so on even if the resulting data in your model may be the same).
Conclusion
My conclusion is really just a couple of questions: 1) do you agree with the concerns/criticisms above? 2) regardless of your answer to one, how do you handle server side form validation? Right now I have settled on building server-side form validation in filters within Mach-II. While, in my current implementation, this means that I need a new filter for each form, as I said before, I can't get past that a one form to one validation scheme pattern is, in general, a necessity. Although filters are not technically part of the UI, they seem a better place to put the form validation code than in the model, where, as I said before, it just doesn't seem relevant. So, am I off my rocker or over-thinking the issue? Thoughts?
What irks me is that I usually have to repeat (form field) label names in my validation, which violates DRY. That's one thing I do like about Struts validation--one can have their labels defined in one place.
I think validation isn't Model code. It seems like it's mostly UI and Controller.
The confirm password should not be in there and IMHO should be front-end only as it is just a way to help the user not mess up their password by way of mis-typing.
Food for thought would be to come up with a way to customize the validation by passing a list of the attributes you want to validate (blank for all) and let your validation function check only those attributes you tell it to. That would help solve the problem of multiple part forms to some extent since you could tell it to validate the attributes that were on that part of the form.
In case where there's a special form that needs validation that's focused on its UI elements that don't line up with model elements (and shouldn't permeate the model), I'd like to keep validation in the controller layer. A signup form requiring the user to enter their password twice is a good example.
However, in other situations where I'm writing software that's to be consumed by multiple clients (multiple HTML forms editing parts of the same model entities, Web services, or Flex), I don't want to duplicate the validation and I'd like to make sure values sent by remote entities (like Flex) are valid. In that case, I need something, somewhere in my model / service tier that validates.
I'm also often in situations where whether or not something is "valid" may have multiple definitions, based on workflow or other context.
The compromise I often use is to remove validation from both the model and the controller tiers, isolating it in IValidationRule implementations. It's a really generic interface that takes a struct (or CFC) in its validate() method and returns a ValidationErrorCollection (part of Model-Glue, but easy to rip out and use independently).
My controller can do the equivalent of ruleFactory.createRule("signupFormValid").validate(FORM), and my user can do ruleFactory.createRule("userValidForPersistence").validate(this).
my 2 cents..
I'd like to add another question to the mix. At what stage in a request process do you validate? Knowing that web service calls will bypass the controller layer, I tend to validate within a service.
In the end, I think it's up to the developer to engineer a system that works for them. Building the perfect validation scheme is like building a better mousetrap. A lot of thought has gone into schemes in the past (custom tags, includes, etc.) and lot more will go on in the future...
Robb
Robb
good point about bypass controller layer.. that's why I strongly agree with using Service Layer and let your controller tap into that.. same with your web services.. Doug Hughes had a good write up on this topic (http://www.phillnacelli.net/blog/index.cfm/2007/4/18/Doug-Hughes-on-Service-Layer)...
cheers...
As a general overview though, it is broken up into 3 parts ... a collection of pluggable validators, one or more data transformers and one or more data set configurations.
The validators allow you to build your own custom validation rules. This could be as simple as checking that a given data field (element) contains a value or as complex as running tests based upon multiple data fields, talking to a database or web service, etc. The idea is that no validation framework can imagine every possible test, so this allows you to easily add your own validation routines.
The data transformers abstract out the concept of where the data being validated is coming from. This way, we can have a simple form structure transformer that knows to retrieve data out of the form scope and send it to the validation engine. We also have a basic bean transformer that inspects a bean and grabs its data based upon each getter method. The goal here again is abstracting out where the data is coming from so if you prefer to validate beans vs. form data, you can do whatever you wish.
The last piece to the puzzle is the data set configuration. Basically what this means is a mapping setup between data elements and validation rules. For example, the firstName data element requires the "required" valdiator to be run. Through this mapping your can also setup mappings between groups of fields - for example a validation rule for the firstName, lastName, and emailAddress data elements to determine if they represent a unique user. This mapping can be setup via an XML configuration or via a programmatic API if you want to store and manage the rules via your application (a dynamically built form for example).
That is enough of a preview, but this code should be available in Alpha form very shortly with documentation and a Beta to follow close behind.
<cfset obj = createobject("component", "_model.dao.Users").init()
<cfset obj.setMomento(form)>
<cfset ec = obj.validate()>
<cfif StructIsEmpty(ec)>
<cfset obj.save()>
</cfif>
obj.setMomento() takes a structure and maps it to the set methods in the class.
obj.validate() returns a structure of errors.
2. In the command object. The SaveUserCommand object should be able to say "I have enough data to execute, and the data looks good to me". This is where one would check unique constraints etc. Once again this could throw an exception, but it becomes debatable above this layer whether to use exceptions or return values.
3. In the service object. The service should throw a validation error if it is not able to create the command object.
4. In the controller. The controller should be able to say "this form is valid by whatever rules I want to apply to it". These rules may temporarily be more lax than required by the service/domain, but before the final commit must boil down to essentially the same thing.
5. In the UI. Javascript assistance is a nice touch.
Now, a some points to note about this scheme:
. Each layer may be vanishingly thin. In the simplest case, a CRUD form that maps directly onto a persistable domain object and thence to a table, the service and command layers might disappear and the controller may choose to just catch the domain object's exception.
. Because the controller must ultimately satisfy, the lower layers, it would nice and DRY if the controller could query the lower layers about what rules they intend to apply. The controller can then apply the same rules, but use UI-specific field names and messages. The controller can also then reflect those rules back to the UI in the form of JS routines. I think it's basically this re-use of rules that the various frameworks are trying to achieve.
. With the full stack in place, a single constraint might be checked four or five times. One might want an escape mechanism to prevent expensive checks being repeated, but in general this is a strength. It allows the system to put concurrency management at the appropriate level. For big scary operations, one can put a lock around the whole conversation. For more mundane operations, locking can be right down at the command level.
. How one expresses the rule set - in code, in XML, as a method within the object, as a composed validator etc I think is a matter of preference. I think there's a basic philosophical divide between whether one thinks validation part of a domain object's core concerns and therefore belongs in its interface, or whether it is not and therefore would reduce coherency.
Jaime Metcher

