Hi Barney,

I think I'm starting to see where our differences arise :-)

CFTRY vs CFIF:
--------------

I hadn't thought of the differences in approaches being procedural 
vs event-driven, but that ties in well with the fact that the caller 
of the objects, in our case, is a presentation layer written in 
FuseBox3. When I do something in Mach II I'll have to see how my 
view of things changes.

'store' forces 'validate':
--------------------------

Our differences seem to come from the fact that you want to store in 
your database data which does not conform to the business rules but 
which you regard as valid in some other sense. I haven't hit that 
eventuality yet, and I can't forsee doing it. (I don't think I'd 
handle super-users the way you do for instance). In the event that I 
needed to however, I could do it by other means, and that relates to 
your point about where (in which object) the store method exists. 

The object I was originally talking about, with validate and store 
methods, exists in our business layer. The method that actually 
updates the database would be an update or insert method in a 
parallel object in our data layer. The business layer store method 
would call the data layer insert or update methods as required. Our 
data layer components are actually generated from the database 
itself. So we have the backend abstracted as you do, it's just 
separated in a different way.

So going back to storing valid data (that doesn't conform to 
business rules) I might (perhaps, haven't fully thought this 
through) go about create specific methods for those eventualities in 
the business layer, that call the data layer methods in a different 
fashion, and perhaps bypass validation. So my user object (business 
layer) might have both a store() method and a storeSuperUser() 
method for the special case. 

Your code example is pretty close to what we do, by the way. Our 
return value from validation is a structure, but your use of a 
string keeps the example short.

Cheers,  Andy

---  "Barney Boisvert" <[EMAIL PROTECTED]> wrote:
> CFTRY vs CFIF:
> --------------
> Lets say I want to store some data.  I run it through a filter to 
make sure
> it's all correct (even though the source of the data might be 
competent and
> have provided valid date).  If it's correct, then I try and store 
it, and
> everyone is happy.  If it's not correct, I'll display an error 
message.
> 
> Lets say I want to store some data.  I know something might go 
wrong, so I
> say "hey, if problem 'x' happens, I want to know".  If nothing 
goes wrong,
> everyone's happy.  If something goes wrong, and it's exactly 
the 'x' that I
> want to know about it, then I'll deal with it.
> 
> I see the route as "store the data", and if something out of the 
ordinary,
> I'll address that when the time comes.  In other words, I don't 
see a fork
> in the road, I see a single path that might be blocked, and I need 
to be
> able to handle that potential eventuality.  The fork is a very 
procedurally
> minded view on things, while the exception handler is more passing 
messages,
> which is what OO is about.  Not to say that one is better, when 
I'm doing
> Fusebox (procedural), everything is the fork in the road 
mentality, but when
> it's Mach-II (OO), it's all exception handling.
> 
> 'store' forces 'validate':
> --------------------------
> I think 'store' should throw an exception if it has invalid data, 
but it
> shouldn't force the user to validate that data in a specific way.  
And the
> checks it should perform are likely different as well.  'validate' 
deals
> with handing business rules.  'store' should pretty much just do 
type
> validation for the persistance layer beneath it, and perhaps some
> interpreting of any errors that occur at the persistance layer.  
They might
> not be independantly implemented, but they should be independant 
in terms of
> the public interface of the object.  I shouldn't have to 
call 'validate' in
> order to call 'store', in other words.
> 
> Here's a grossly simplified version of what I understand to be 
your mechansm
> (correct me if i'm wrong), using the empty string as an "it's all 
good"
> value to return from 'validate':
> 
> function validate() {
>   this.validateCalled = true;
>   if (len(name) lt 5)
>       return "name must be 5 chars";
>   if (age LT 18)
>       return "you must be 18";
>   return ""
> }
> function store() {
>   if (NOT this.validateCalled)
>       throw ValidateNotCalledException
>   if (validate() NEQ "") {
>       this.validateCalled = false;
>       throw InvalidStateException
>   }
>   // do my store
> }
> 
> The same methods would look like this in my CFC:
> 
> function validate() {
>   if (len(name) lt 5)
>       return "name must be 5 chars";
>   if (age LT 18)
>       return "you must be 18";
>   return ""
> }
> function store() {
>   if (NOT isNumeric(age))
>       throw InvalidStateException
>   // do my store
> }
> 
> Both perform exactly the same, but my methods are rather more 
flexible with
> regard to how the calling code can use the object.  Perhaps we 
have certain
> circumstances that we want to store values taht violate business 
rules, but
> are valid for some reason (I occasionally use negative userIDs to 
represent
> superusers, for example).  Or we might want some objects to have 
tigher
> restrictions on their data than what 'validate' enforces 
(superusers must
> have longer passwords).  In the former case, I'm SOL with your 
methods, and
> in the later, I'm doubling the work I have to do (validate the 
tight rules
> and then validate the CFC so I can store).
> 
> I'm also finding that 'store' is often within a totally different 
object.
> Take an app that's designed to run on several persistance 
backends, and it
> will dynamically switch based on an config parameter.  
The 'validate' method
> will never change (business rules are business rules), but the 
persistance
> mechanism might (Access, MySQL, Oracle, SQL Server, XML file).  
For this
> type of architecture, I need to have an easy way to swap out 
the 'store'
> method, without affecting the rest of the object.  There are many 
solutions,
> but my preference is to have a single object for each persistance 
layer type
> with methods such as persistPage, persistUser, etc., each of which 
takes an
> object of the specified type and persists it.  So I have an 
AccessPersister,
> a MySQLPersister and so on.  In this case, 'store' and 'validate' 
aren't in
> the same object.  They'll be called like MySQLPersister.persistPage
(myPage),
> rather than myPage.persist().  That keeps the backend totally 
abstracted
> from everything else.  Just instantiate a persister on application 
startup,
> and then all my code can call that persister whenever they need 
anything.
> 
> Well, that got really long, really fast.
> 
> 
> 
> > -----Original Message-----
> > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> > Behalf Of cf_nut
> > Sent: Monday, October 06, 2003 4:50 PM
> > To: [EMAIL PROTECTED]
> > Subject: Re: [CFCDev] Data validation
> >
> > I'm genuinely interested in why you prefer to handle validation
> > errors by exception, as in your original reply to my message.
> > Although we're both achieving the same thing, to my mind
> > it's 'cleaner' somehow to say 'which route am I going down, 
doing a
> > store, or showing an error message to the user ?' as distinct 
from
> > your approach where you seem to have the possibility of 'right, 
I'm
> > going to store ... whoops, no, shouldn't be here (got a 
validation
> > error) I'll have to go display an error message'.
> >
> > I'm interested, too, in why you prefer store() not to throw an
> > exception as I suggested. To my mind it's the reponsibility of 
the
> > application to ensure valid data is stored. And there's no better
> > place to enforce the validation for an object than in the 
component
> > code for that object. If, as you seem to be suggesting, you 
separate
> > validate() and store() completely, then that makes it the
> > responsibility of the calling code to call validate() and gives 
that
> > code the option of storing invalid data by omitting (through 
design
> > or programmer error) the validation step. By making a linkage as 
I
> > suggested (store can't proceed till validate is done, enforced by
> > throw) data integrity is preserved no matter what, and the 
writer of
> > the calling code is forced to call validate() (and cope with any
> > resulting errors) to get store() to succeed.
> >
> > As you say, it's amazing how many different approaches people 
find to
> > the same problem. :-)
> >
> > Andy.
> >
> > --- "Barney Boisvert" <[EMAIL PROTECTED]> wrote:
> > >
> > > How did you handle multi-datum validation?  Like ensuring a
> > password doesn't
> > > contain a username, for example.  I gone down the road of
> > validating in the
> > > setters a couple times, and always ran into that wall at some
> > point.  You
> > > need to be able to have the object in an invalid state between 
the
> > setter
> > > calls, but you need to first error to be cleared after 
validating
> > the second
> > > datum.  That's the primary reason I've always opted for a
> > centralized
> > > validation method.
> > >
> > > It's amazing how everyone has totally different ideas for 
solving
> > the same
> > > problem.
> > >
> > > barneyb
> > >


----------------------------------------------------------
You are subscribed to cfcdev. To unsubscribe, send an email
to [EMAIL PROTECTED] with the word 'unsubscribe cfcdev' 
in the message of the email.

CFCDev is run by CFCZone (www.cfczone.org) and supported
by Mindtool, Corporation (www.mindtool.com).

An archive of the CFCDev list is available at www.mail-archive.com/[EMAIL PROTECTED]

Reply via email to