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.