Exercise List: Error Collection ColdFusion Component

Posted November 15, 2007 at 2:23 PM by Ben Nadel

Tags: ColdFusion, Exercise List

Click here to view the current Online Demo

Click here to view / download the current Code Base

Based on my updated plan for domain data validation in my Exercise List object oriented programming project, I have designed the ColdFusion component that will collect errors and facilitate messages delivery. It is the ErrorCollection.cfc. Right now, I am not 100% confident as to where all the validation will be going; I have had some good suggestions as well as some constructive criticism, but I feel that that kind of a decision is separate enough from the ErrorCollections.cfc that this object can be designed without a full understanding of the data validation plan.

The ErrorCollections.cfc ColdFusion component has two basic roles: collecting errors and collecting error messages. These two things are relevant to two different layers of the application, and therefore are done in two different places. The service layer handles the business logic and therefore it handles the data validation. It's job is to collect the errors. The service layer can provide some error "hinting", but it cannot really be responsible for defining the related error message as this is more of a view-related decision.

The view / display layer is what communicates with the end user, and therefore, it is the view's responsibility to translate the errors into useful user messages. The thing that ties these two layers together is the "error flag". This error flag is a unique key such as "NameLength" or "EmailValid" that both the service layer and the display layer must agree on in order for the error handling to be effective. The trick, as Rich Kroll pointed out, is that by using this handshake, the view and the service layer are not so tightly coupled together. One can change without the other one bombing out.

Now, let's take a look at the methods within the ErrorCollections.cfc. Instead of looking at all of them at once, let's look at which methods will be used by the service layer and then which will be used by the display layer. First, the Service layer:

AddError( Flag, Hint ) :: Void

The primary job of the service layer it to validate the data and add errors to the error collection object which will be passed back to the display layer. The first argument, Flag, is the unique key (unique to the object being validated) that defines what type of error this is. The second argument, Hint, is merely some additional information that the Service layer can provide as to why the validation error occurred. The hint is not really meant to be used anywhere unless necessary.

HasErrors() :: Boolean

This just returns true if the ErrorCollection.cfc instance has any errors added to it. This will be used prior to the database interaction - we don't want to insert or update to the database if the passed in data is not valid. This will also be used by the display layer to determine the page flow.

...

So, that's really all that the service layer needs to do in terms of validation. Now, let's take a look at the display layer related functions:

AddMessageIfError( [Flag ,] Message ) :: Void

This is basically where the hand shaking between the display layer and the service layer takes place. This method has two ways to be invoked. The first way, in which both arguments are defined, checks to see if the given error flag is in the errors collection, and IF SO, the given message is added to the message collection (also stored within the ErrorCollection.cfc).

If this method is invoked with only a single argument, Message, it will add the given message if the number of errors is not equal to the number of messages. Ideally, this method signature would only be utilized once to see if there are any errors that we don't know about. So, for example, let's say we had a form that had name and email, we might have something like this:

  • <cfset objErrors = ServiceObject.Save( bean ) />
  •  
  • <!--- Set error messages if necessary. --->
  • <cfset objErrors.AddMessageIfError(
  • "NameLength",
  • "Please enter the name"
  • ) />
  •  
  • <cfset objErrors.AddMessageIfError(
  • "EmailValid",
  • "Please enter a valid email address"
  • ) />
  •  
  • <!---
  • Add a message to see if there are any errors that we
  • didn't intend to handle (ie. SQL exception errors that
  • we don't agree on).
  • --->
  • <cfset objErrors.AddMessageIfError(
  • "There was an internal error - no data was committed"
  • ) />

Here, we are adding error messages for the two expected (possible) errors, NameLength and EmailValid, and then we are adding an additional message, not tied to any flag, that will indicate to the user that some error took place.

GetErrors() :: Struct

This returns the struct of error flag / hints.

GetMessages() :: Array

This returns the array of messages set by calls to AddMessageIfError().

HasError( Flag ) :: Boolean

This checks to see if the error collection contains the given error flag.

So that's all there is to it. I am sure that as I begin to implement this, I will find things that need to be added; but, I am making the method set for this object purposefully small so as to confine myself to the expected usage. For example, the ErrorCollection.cfc is not intended to have random messages added to it, and therefore, it does not have a generic AddMessage() method.

Like I said before, I am really just feeling this out. Domain data validation who-what-where-when is in no way fully codified in my head. But, again, this is an iterative process, so I am sure it will need to be tweaked in future passes. The single argument method of invoking AddMessageIfError() needs to be thought out better; as German Buela previously pointed out to me, there ARE SQL exceptions that are not meant to be caught as part of validation - they are meant to be caught as application errors. I will have to be very careful about how I catch Database errors with my CFCatch tags. More to come.




Reader Comments

Nov 15, 2007 at 5:43 PM // reply »
3 Comments

It doesn't feel right for me that a save method in service returns an error object. So almost every service return error object? What if the method in the service already needs to return something else?

I would much prefer the validation takes place in a seperated method, and method like save() in the service layer only throws save-related exceptions...

Maybe validate before saving in save(), and throw InvalidBean exception? view caught the exception and call validate() on bean to get the error struct for more details? Maybe error struct can be somehow cached so the view doesn't call validate() but somehow through a method to get the error struct?

I have no problem with validate() being called twice. Althought it violates DRY, can we justify it as "defensive programming"? Sacrafices performance for robustness?


Nov 16, 2007 at 7:11 AM // reply »
11,238 Comments

@Henry,

I thought about some sort of caching mechanism, but we can't really go that way since there is no way for the Service layer to know it is working with consecutive calls... what if we had 5 domain objects we were validating and then we were gonna call Save() on those 5 as well. This has to be considered an asynchronous process and we cannot depend on the user to do anything useful.

I guess, it's not the end of the world to call the Validate() method twice. It feels wrong, but as I have said elsewhere, I am new to this stuff, so it all feels a little wrong.


Nov 16, 2007 at 7:44 AM // reply »
11,238 Comments

@Henry,

Just one more thought. If you look at a lot of functions, they do return some sort of success / failure flag. For example, in ColdFusion, the StructAppend() method returns a boolean indicating success. Is this not some sort of validation on the action?

Although, I guess this doesn't return a given error, it just returns the existence of any errors. Just thinking.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools