Coldbox, ColdSpring, Transfer, Refactoring And Me (part 3)
I was trying to come up with a nice way to introduce working with Transfer in Coldbox. At first I wanted to have a service layer to control interactions with my objects. With Transfer, however, the relations became a little fuzzy. Take, for example, an event trying to register a new user. When thinking about submitting a registration form, I normally see at least two steps: validation and saving. Trying to imagine the flow of something like this in an application that's trying to be as close to OOP as possible isn't as easy as I thought, though. Here's what I got so far.
Generally speaking, I normally see the Coldbox controllers as having as little to do as possible. Their job is a little like a traffic operator who doesn't move, but rather tells people where to go.
Some Coldbox Controller
<cfargument name="event" type="any" required="true" />
<!---
Let's suppose we have a userService object in the request collection
(not likely, but that's a problem for another post)
--->
<cfset event.getValue( "userService" ).saveAndValidate( event ) />
</cffunction>
You see that we're basically just passing the event argument (akin to the request scope) over to the service layer for treatment. The way I see it, the userService object is basically another controller, but for the user object rather than for the event requested.
The userService's validateAndSave() method
<cfargument name="event" type="any" required="true" />
<!--- do some validation stuff --->
<!--- tell the object to save itself --->
<cfset variables.instance.user.save( event ) />
</cffunction>
I didn't want to go into too much detail for this post, but we can see that the validateAndSave method takes care of validating the data submitted and then asks the user object to save itself (passing it the event variable so it knows what values to assign itself). The user object then calls Transfer's method to update and save itself.
The user object's save() method
<cfargument name="event" type="any" required="true" />
<cfset var locals = { } />
<!--- get the transfer bean --->
<cfset locals.transfer = event.getValue( "transfer" ) />
<!--- create a new user --->
<cfset locals.user = locals.tranfer.new( "myPackage.User" ) />
<!--- set some columns --->
<cfset locals.user.setMyColumn( event.getValue( "myValue" ) ) />
<!--- etc. --->
<!--- save the user back to the database --->
<cfset locals.transfer.save( locals.user ) />
</cffunction>
Using Transfer's new method, we get a reference to a blank user record. We then use the generated setX methods (one for each column) to update the record, and save, well, saves the record back to the database. Simple enough, right? The question is, however, is it good enough?
Hesitations
I've been avidly following Ben's series on OOP, especially his posts (day 1 and day 2 are up, hopefully more to come) following his courses with Hal Helms. His last post talks about objects having behaviours, and being able to do what is requested from them. He also warns against « massive, procedural "Service" objects and data-driven "Business Objects" that have no true behavior ». After reading through the post a couple of times I can't help but question my structure.
- What good is the user service object for? Shouldn't the user object be able to validate and save itself? Should it be called directly from the Coldbox Controller?
- I seem to be passing the event object around alot... I don't feel confortable doing this and feel I'm repeating myself.
I've got some serious thought to put into this, but I'm glad I put it out there. Any insight is, as always, very much appreciated.


Yes, maintenance is easier than with sloppy procedural code written by a beginner, but not pretty procedural code written in a quality framework which forces a separation of concerns to allow for application expansion.
This is for me and my projects personally. I'm sure the Sean Corfields are on massive enterprise projects where OOP and OOP specific design patterns are mandatory.
I understand where you're coming from. Honestly, I have to agree that this is a major step and that it requires a lot of resources. At work I tend to lack the time to pursue a true OO approach.
However, I'm exploring on some experimental projects on my own time, so it isn't so much an issue. I guess I'm looking for a solution that's easier to scale and manage (and debug by my coworkers!).
Obviously I wouldn't bother with all of this with a comment form, but you still have to ask:
"What is considered small?" ;)
I don't know what small is; it's a good question.
I have been reading the ColdBox docs and its a pretty tough cookie to eat, yet with Wheels you are coding just the same way you did before but better. I dont know why a ColdFusion developer would want to do things harder.
I don't think Coldbox is difficult to learn, or use. It's also conventions-based, using XML only for it's settings file. What got me interested, at first, was the huge amount of documentation available for this framework. This made it much easier to learn than others I had tried. I do admit, however, that I had not seen or heard of cfwheels before. I might save some time after this project to give it a try, if only to compare ;).
The difficulties I'm facing here, though, is integrating all of these frameworks together and trying to create an application that is as OO as possible. It's an experiment, so it's supposed to create challenges.
Now if Model-Glue or ColdBox could work with Transfer to make it so everyone works on a single framework would be the best idea for the community. Its like people forget they chose ColdFusion for its simplicity in the first place, a single all in one framework is very needed, and wheels is heading tht way.
Maybe I am naive but I believe we need an united front and not lots of semi useful thing scatter around, there are some greate examples out there with Django, Rails and Symfony where eveyrthing is baked in and everyone is working out the tweaks everyday.