I use services:
* As remote API ­ can¹t send smart beans over the wire, so I have methods
like UserService.save(). Of course, all they do is user = THIS.new(),
user.load() and user.save(), so they delegate to the bean, but they provide
the remote API. 
* To handle aggregates ­ I find it more intuitive to UserList =
UserService.getByFilter(³Subscribed = 1²) rather than asking a User for a
list of users. Also, ColdFusion doesn¹t support class methods, so I¹d have
to create a Singleton User which just doesn¹t seem to be the best approach
in CF. 
* As a factory ­ user = UserService.new() returns a user with any
dependencies injected. It¹s really just a one line call to LightWire which
does the DI, but it gives me a place to add more intelligence to my factory
if I want to override new() for a given business object.

I don¹t currently have the use case for different validations, but I¹ve had
it in the past (although back then I just solved it procedurally). I¹d be
tempted to EITHER have different isValid() methods, or more likely to have a
OrderState control which would allow me to set the state (and hence
validations and the like) for different states, so I might do:

Order.set(³State², ³Situation1²);
If (Order.isValid())
 . . .

Although I¹d have to play with it to see if it worked out.

Best Wishes,
Peter


On 1/14/08 3:51 PM, "Baz" <[EMAIL PROTECTED]> wrote:

> Peter I like what you are saying.
> 
> When do you use a service by the way? You seem to be interacting directly with
> beans a lot. 
> 
> Second, if you had varying levels of validation complexity for orders such as:
> 
> * Situation 1: Validate Order, User, Billing, Statistics (the previous
> example) 
> * Situation 2: Validate Order, Shipping
> * Situation 3: Validation Order
> Would you then have different aggregate validations? I.e.
> Order.isValidSituation1(), Order.isValidSituation2(),
> Order.isValidSituation3()
> 
> Cheers,
> Baz
> 
> 
> On Jan 14, 2008 12:34 PM, Peter Bell < [EMAIL PROTECTED]
> <mailto:[EMAIL PROTECTED]> > wrote:
>> How about:
>> 
>> If (Order.isValid())
>> {
>>    Order.save();
>> }
>> Else
>> {
>>   Screen = OrderForm;
>>   Data = Order;
>> };
>> 
>> First method could both return a boolean as to whether the order is valid
>> (which would only be true if all of the composed objects were also valid) and
>> would also set all of the necessary error messages within the Order (and the
>> composed beans) so you could just pass the error (containing both the data
>> and the associated error messages) back to (say) a form for displaying the
>> issues. 
>> 
>> I think it'd be straightforward to have a generalizable solution to this
>> which would use relationship metadata and introspection to get the order to
>> automatically ask all composed beans and properties whether they were valid.
>> I see something along the lines of:
>> 
>> Valid = 1
>> For each property:
>>   If NOT THIS.isValid(PropertyName)
>>     Valid = 0
>> 
>> And the isValid() method would call the appropriate type of validation
>> depending on the data type of the property. If the property was a composed
>> bean, it'd just call that beans general isValid() method. Then you just need
>> a errorMessage(PropertyName) method which would display the error message for
>> each property (it'd be null unless the property was invalid). Details beyond
>> that would depend on relationship between validations and properties and
>> whether you just look for one error per property or catch them all ( i.e.
>> could a single property have multiple error messages at any one time).
>> 
>> I don't see any need for either service or controller to do anything here ­
>> that seems a little procedural to me.
>> 
>> Best Wishes,
>> Peter
>> 
>> 
>> On 1/14/08 3:21 PM, "Baz" <[EMAIL PROTECTED]> wrote:
>> 
>>> Hey Peter, so you are doing the equivalent of a separate validate() and
>>> save() right on the bean itself, which, in this example, doesn't make too
>>> big a difference. But some problems can arise if we look at a more complex
>>> yet realistic use-case.
>>> 
>>> Let's say a user submits an order and we need to:
>>> * partially update the user (perhaps they changed a communication preference
>>> during the order process)
>>> * create an order
>>> * create a billing address
>>> * 
>>> * update an independent statistics table that executive management uses
>>> There are several objects involved here - possible composed, possibly not,
>>> it doesn't really matter - and each would probably have a layer of
>>> validation. One way of performing the save is to have one main function
>>> saveOrder() (located in some service) that goes about creating, validating
>>> and saving each object then aggregating the error messages into one final
>>> ErrorCollection. This provides a nice, clean, simple interface for a complex
>>> process. But then what do you return from that function - just the
>>> ErrorCollection? What about the objects at hand, such as the newly created
>>> billing address, how do we get references to those? Perhaps we can reload
>>> everything on a subsequent broadcast, but using which OrderID?
>>> 
>>> On the flip side we can break apart the jumbo method and start calling
>>> smaller methods independently each of them returning appropriate data that
>>> we need back to the controller. But of course, the more you do that, the
>>> smarter your controller is getting and the less re-usable your code.
>>> 
>>> So the tighter and cleaner you make your service functions, the more awkward
>>> or problematic the returntypes. And the more flexible or atomic you make the
>>> service the more intelligence your controller has to hold. In the
>>> aformentioned case it seems that there is no level of real cleanliness.
>>> 
>>> Thoughts?
>>> Baz
>>> 
>>> 
>>>  
>>> 
>>> On Jan 13, 2008 6:20 PM, Peter Bell <[EMAIL PROTECTED]> wrote:
>>>> Hi Baz,
>>>> 
>>>> I can't think of a case where I'd be saving 10 independent objects. In my
>>>> experience, I'm either saving one object, I'm saving a collection of
>>>> objects of the same type (e.g. To update the price on 8 different products
>>>> using a single form or grid) or I'm saving an object which may have
>>>> composed or associated objects that also require saving.
>>>> 
>>>> My real code assumes a collection of n-objects of the same type, and a
>>>> single object is just a special case where n=1, so imagine the code I sent
>>>> you within a cfloop and you'll get the idea. For composed objects I let my
>>>> ORM do the lifting. If I really had a use case where I had to save multiple
>>>> completely independent objects (that don't have any association or
>>>> composition relationships) , I'd probably create an appropriate service
>>>> class for handling that and would write a method within it that would
>>>> orchestrate the independent method calls to the various object services. To
>>>> date that use case has never arisen in the projects I've built.
>>>> 
>>>> As for returning errors, I've been playing with a number of different
>>>> approaches since obviously you want both the bean data and the error
>>>> messages. I'm moving towards something like:
>>>> 
>>>> If User.isValid()
>>>>   User.save()
>>>> /If
>>>> 
>>>> And with a User.getInvalidFieldList() and/or a User.isValid(PropertyName)
>>>> and User.errorMessage(PropertyName). Also, as this is an IBO, it can
>>>> contain a collection of users, so I can loop through them and store
>>>> validation status and error messages for each, making this equally easy to
>>>> work with for one object or for a collection of objects as the single is
>>>> just the special case of n-objects where n=1. With this approach, I just
>>>> pass the bean around and it contains both the data the user tried to enter
>>>> and the associated errors.
>>>> 
>>>> Right now I do something a little different each time I touch validation so
>>>> I can get a feel for the different approaches and decide what to
>>>> standardize on.
>>>> 
>>>> Best Wishes,
>>>> Peter
>>>> 
>>>> 
>>>> 
>>>> On 1/13/08 8:40 PM, "Baz" <[EMAIL PROTECTED]> wrote:
>>>> 
>>>>> If the form submission was a lot more complex and required the saving of,
>>>>> say, 10 different objects. Would you still interact with each object
>>>>> individually in the controller, or move all of that to a service function
>>>>> that orchestrates the interactions? If you would choose the latter, and
>>>>> given that in the another post you said that you would handle the creation
>>>>> of objects in the service rather than the controller, you are then faced
>>>>> with the issue of how to return the bean(s) and/or errorcollection from
>>>>> the save() method...
>>>>> 
>>>>> You know?
>>>>> 
>>>>> Baz
>>>>> 
>>>>> 
>>>>> On Jan 13, 2008 5:15 PM, Baz <[EMAIL PROTECTED]> wrote:
>>>>>> Hey Peter,
>>>>>> 
>>>>>> Looks very tidy! So I guess the validation occurs in the save() method.
>>>>>> What would that method return, True/False? And then later on you would
>>>>>> evaluate the result to see whether to retrieve the error collection?
>>>>>> 
>>>>>> Cheers,
>>>>>> Baz
>>>>>> 
>>>>>> 
>>>>>> On Jan 13, 2008 5:08 PM, Peter Bell <[EMAIL PROTECTED]
>>>>>> <mailto:[EMAIL PROTECTED]>  > wrote:
>>>>>>> Hi Baz,
>>>>>>> 
>>>>>>> Why not just:
>>>>>>> 
>>>>>>> var Result = ";
>>>>>>> var User = UserService.new(User);
>>>>>>> User.LoadStruct(form);
>>>>>>> Result = User.save();
>>>>>>> AddResult(Result);
>>>>>>> 
>>>>>>> I have some generic code so I don't have to type this for every
>>>>>>> controller that handles a form, but this is generally what I do.
>>>>>>> 
>>>>>>> Best Wishes,
>>>>>>> Peter
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> On 1/13/08 8:00 PM, "Baz" <[EMAIL PROTECTED]> wrote:
>>>>>>> 
Another design choice I see go both ways is whether to perform validation in
the save() method or to call each method separately. Example controller
functions could be (pseudo code):

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - 

SEPARATE SAVE & VALIDATE
var UserService=getBean('UserService');
var FormVariables=getAllValues();

var ValidationResult='';
var SaveResult='';

set ValidationResult=UserService.validate(FormVariables); // returns an
error collection object

if ValidationResult.hasErrors()
     setValue('ReturnObject', ValidationResult);
     addResult('Fail');
else
     set SaveResult=UserService.save (FormVariables); // returns a populated
user bean object
     setValue('ReturnObject', SaveResult);
     addResult('Success');
end

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - 

COMBINED SAVE & VALIDATE V1.0
var UserService=getBean('UserService');
var FormVariables=getAllValues();

var UserBean=UserService.newUser();
var SaveResult='';

set UserBean.setMemento(FormValues);
set SaveResult=UserService.save(UserBean); // returns true if saved
successfully, or false if validation errors exist (the error collection
would be saved in the bean itself for retrieval later)

setValue('ReturnObject', UserBean);

if SaveResult is True
     addResult('Success');
else
     addResult('Fail');
end

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - 

COMBINED SAVE & VALIDATE V2.0
var UserService=getBean('UserService');
var FormVariables=getAllValues();

var SaveResult=UserService.save(FormVariables); // returns a complex result
object with properties: STATUS ('Success', ValidationError') and PAYLOAD
(that contains either a UserBean or ErrorCollection depending on the STATUS)

setValue('ReturnObject ', SaveResult.getPayload() );

if SaveResult.getStatus() is 'Success'
     addResult('Success');

else SaveResult.getStatus() is 'Validation'
     addResult('Fail');
end

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - 

CONS OF KEEPING THEM SEPARATE:
* Controller has to be smarter, which is bad, because there will be more
code duplication if you change the presentation layer to flex, for example.
* Function coupling: Coders have to "remember" to always validate() before
saving() - an unnecessary additional complexity (unless, of course, there
are times in your app where you save() by defining all values yourself
(thereby knowing the values are correct) rather than from user input)
CONS OF COMBINING THEM COMBINED
* Requires complex and unnatural result handling (either by affecting the
bean by reference, or using a special RESULT object)

Cheers,
Baz



>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>> 
>>>> 
>>>> 
>>> 
>>> 
>>> 
>>> 
>> 
>> 
>> 
> 
> 
> > 
> 



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"CFCDev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/cfcdev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to