Reaction’s name has been changed. Mr. Corfield astutely pointed out another ColdFusion framework already named Reaction. So, to both reflect the “tor” in the word “generator”, and to keep just over 62% of the now-defunct name, I have rechristened it “Reactor For ColdFusion.” I like this name because it sounds more proactive than Reaction. Other than that, it was the first name I didn’t dislike in some way or another. Thanks to everyone for their suggestions.
And now, my request for assistance:
I’m getting prepared to begin a more formal process for building Reactor. Over the next few weeks I’m going to be gathering suggestions and feedback on the API’s needed feature set.
To help me understand Reactor a bit better, I’ve begun the process of writing a very simple survey system using it. I’ll use this both as a sample Reactor + Model-Glue application and a means for gathering feedback from interested parties.
The first challenge I’ve run into deals with data validation. My initial plans had been to have a validate() method on bean objects which would check values against database constraints.
I was going to steal the ValidationErrorCollection from the Model-Glue framework. This would be passed into the bean, populated with any errors and then returned.
For instance, if you had a table with a column named “emailAddress” and that column was defined as varchar(50) and not null, then the framework might generate the following chunk of code inside the validate method:
<cffunction access="public" hint="I validate this form bean." name="validate" output="false" returntype="Reactor.util.ValidationErrorCollection"> <cfargument hint="I am the validation error collection to place errrors in." name="ValidationErrorCollection" required="yes" type="Reactor.util.ValidationErrorCollection"/> <cfif Len(getEmailAddress()) NOT> <cfset arguments.ValidationErrorCollection.addError("emailAddress", "The emailAddress field is required.")/> <cfelseif 50 GT Len(getEmailAddress())> <cfset arguments.ValidationErrorCollection.addError("emailAddress", "The emailAddress field must be less than 50 characters.")/> </cfif> <cfreturn arguments.ValidationErrorCollection/> </cffunction>
There are, however, important problems with this example:
The error messages are static and not user friendly. They are in English. There is no obvious way of enforcing custom business logic such as validating the email address.
Frankly, I don’t like the idea that a non-English speaker might get an unfriendly and unintelligible error message simply because Reaction only returns unfriendly error messages in English.
So, what are the solutions to this? Well, one idea that comes to mind is an XML configuration file. Maybe this could be internationalized so that this could be swapped out. That way, the Pig Latin version might be able to return, “Ethay emailAddress ieldfay isay equiredray.”
That still leaves the problem of the unfriendly column name “emailAddress” as opposed to something like “Email Address” .
There might be a couple solutions to this. For example, I could create another XML to map column names to their descriptions. This could be in any language and might be something akin to:
<columnMap> <column name="emailAddress" value="Email Address"/> </columnMap>
However I don’t like this. In particular, I don’t like the combined requirement to have two XML configuration files (or one big one). One of my unspoken goals in the development of Reactor is to require as little configuration as possible. Ideally, I’d like the entire configuration to consist of passing the four current arguments to the ReactorFactory’s init() method.
Why? Well, I think that much of this information already exists (or could) in the database. If you change a column name, remove or add a column, or make any other number of changes you have to make the change in the database as well as remembering to update XML files.
Granted, that’s not as bad as having to update and re-test all your data objects, but I’d like to avoid that. Also, I don’t want to prescribe a specific, singular and unchangeable solution to the problem.
I would strongly prefer to rely on implications and convention (ala Ruby on Rails) before explicit configuration. I may choose to require a specific naming scheme before requiring configuration files.
On a related note, MSSQL allows you to describe a “description” for a column. Actually, this is an extended property, and you can have any number of them. In my current project we a custom property that was the English name of the column. Our code generator (not Reactor) used that to generate more friendly error messages. I’m not sure if there are any equivalents to this in all possibly supported platforms so I’m tempted not to go this route.
Another idea I’ve been pondering is to have static constants error numbers representing speicific errors. For example, I might have a validator object which has a number of static constants defined in it, such as:
<cfcomponent displayname="XXXValidator"> <cfset this.InvalidNumericValue=1/> <cfset this.InvalidDateValue=2/> <cfset this.StringToLong=3/> <cfset this.DogAteHomework=4/> <!--- etc... ---> </cfcomponent>
This object might have a validate method which you pass a bean to (or a TO to). It would inspect the bean and determine if any errors exist. A collection would be populated relating field names to error numbers. Another component or (even the user interface) would know how to translate these numbers and field names into friendly error messages. (How? I’m not 100% sure yet.)
This still doesn’t solve the problem of custom business logic. However, that could potentially be placed in either a custom validator or in custom logic elsewhere.
I’m even tempted just to say that validation must be done manually in the Reaction-generated customizable components. That’s still easier than having to manually create a ton of objects.
Anyhow, do you have any suggestions or feedback? It would be very appreciated.
Comments on: "Reaction Name Change – Also, a Request for Validation Advice" (9)
Both MySQL and PostgreSQL support a comment for every table and column. And if the comment wasn’t there it could try to be smart and break the column name into words emailAddress = email address.
Pete, you make an interesting point with the breaking up of column names. I had at one point considered using a column naming scheme where spaces were replaced with underscores. This emailAddress would be Email_Address. Then, in errors it would show up as Email Address, but the getters/setters would get rid of them for them to get/setEmailAddress().
Hey Doug, I like the new name. It sounds "electrifying" 🙂
As you know, we are building a survey system at South49 that allows surveys to be taken on the Web and on the phone (and possibly by fax, if there is a need). One of the items we had to deal with is similar to your problem: custom names and error messages.
We have base units in our system (Staff.Name) and we need to allow each client to tell us what the label will be on the screen when this data element is presented. The client can also define custom logic rules (greater than 4, less than 9, must start with a 7, etc.) along with corresponding error messages.
We have come up with a solution that involves a standard table in the database (TableX) that holds this information. It has columns for server, database, table, column and label. There is a join table to this (TableY) which will hold all business rules associated with that data element based on context of that element’s use. This info is loaded into the client’s session object for use throughout the system.
Any solution you come up with has to involve the context of the data element’s use, as logic rules and error messages can vary depending on context. This gets very complex quickly.
I think db-based storage is better than XML in that it will grow quite large and as you say, when you make changes to the db, it is easier to make changes to another table in the db at the same time than to remember the config files that need to be updated.
Let me know if you want to chat more about this and I would love to help get the Reactor up and running!
In the Java world they often use properties files to display messages to users. This done primarly for internationalization but could be useful in this case because every message has a key (a name) and then a value in the properties file which is the message to display to the user. You cook up a similar scheme so that your validation method return an array if these keys and each key could be looked up in the messages.properties file and display. Probably doesn’t completely met your requirements but it is a thought.
I was thinking the same way that Kurt was. There are some great internationalization features in BlogCFC. I believe Paul Hastings provided the code for a resource bundle CFC, which could probably be used for this purpose w/o too much trouble.
After a few questions from folks about the "context" thought, I figured out that I should have given some examples.
Two immediate ones are phone number and postal code. Each of these may be char(20) columns, but their required length and format will be dependent on other columns, like country. Hence, the idea of context.
There are other times where these business rules expand beyond simple rules based on the column. I also agree that there has to be some sort of definition space. Whether that is an XML file or a set of standard db tables – I have no real preference. I prefer the db because it is backed up on a regular basis and I don’t have to worry about losing the config file.
okay – I’m schizophrenic…I do have a preference. It’s db storage. That’s what I get for typing faster than I think….
With regards to internationalization, I think you guys have made great points regarding Paul Hastings’ libraries. I’ll give that some serious thought.
However, the more I think about this, the less I think validation really belongs in the "Beans" as I have them defined.
For instance, and this may be where I went wrong, these "Data Beans" shouldn’t be used to back forms. Initially I thought they could be. Problem arise because over http there’s no way to enforce that a user provide the correct data type when posting a form. Thus, if you had a bean which expected a numeric value, but the user provided a string value, youre going to get errors anyhow because the getters/setters on the Data Beans are typed correctly.
So, how I would typically solve this is to create a bean specifically for backing forms where all the getters and setters accept strings. This form bean would have a validate method on it which confirmed that all the provided data was valid. Once I confirmed that, I would manually move the data from the form bean to the data bean and save the data bean.
Given all that, I suspect that I could create a mechanism to automatically create form beans, complete with a default validation mechanism. The validation might actually be stored in another object which could be customized in the same way that other objects allow it, or though a plug-in mechanism. Form beans would contain the same TO used by the data beans to easily move data between the two types of beans.
Lastly, I think Ill edit Joes ValidationErrorCollection and add another field which would hold a specific error number in addition to a default error message. This would allow uses to create processes to customize error messages as need (based on the numbers and field name) as well as allowing for them to use the defaults and/or maybe even adding in internationalization from Paul Hastings stuff.
My only concern? Complexity. It certainly warrants more thought.
I wonder if this is the right place to do validation, but maybe it’s just scope-creep. I’ll leave it to some smarter folks to figure some way to do good field by field validation generation. But don’t additional business rules apply here, things like: "if field A > 50, field B must be > 100" or other which are even more complex? I mean, don’t we want all the validation to occur in the same place?