The ModelGlue list had an interesting question come up this week. “Interesting questions” on lists are the primary source of blog fodder for me, mostly because I find myself writing responses that are worth reformatting a bit and posting to the blog… and such, honestly, is the case here. The individual in question was asking whether using the new beans=”” attribute in ModelGlue:Gesture controllers would couple your application too tightly to the framework and therefore shouldn’t be used. Before I get into the answer, however, a brief aside:
For those not-in-the-know, adding the beans=”” attribute to the cfcomponent tag of an application controller in MG:G, and providing a comma-delimited list of bean IDs from the ColdSpring file (you are using ColdSpring, right?) will automatically pull those beans from ColdSpring and compose them at variables.beans.beanName.
<cfcomponent extends="modelglue.gesture.controller.Controller" beans="UserService"> <cffunction name="getUser"> <cfargument name="event" /> <cfset event.setValue("User",variables.beans.UserService.getUser(event.getValue("UserID"),0)> </cffunction> <cfcomponent>
So the question was basically, “Does using the beans injection functionality in MG 3 couple your application to the framework?” and by extension, “Does using a framework’s features inextricably marry your application to the framework?” and applies to about any application framework out there. The short answer is, well, really… yes and no.
The use of anything that extends modelglue.gesture.controller.Controller definitively binds your application to the framework in question. However, since you’re only going to be extending the MG core controller class when you’re building your own controller in a ModelGlue app, it’s a moot point… using the built-in bean injection is just using a feature of the framework when you’re building an application that uses the framework.
In other words, yes because you’re building a ModelGlue application at all, and no because using bean injection doesn’t couple you to the framework any more than the rest of the application does. Where you wouldn’t want any reference to the framework is actually one tier below the controller layer… your service layer. At least in theory, your controller talks to services and services talk to everything else.
Let’s look at a psuedo-codish method you might find in an MG controller:
<cffunction name="saveUser"> <cfargument name="event" /></p> <cfset var UserID = event.getValue("UserID",0)> <cfset var userName = event.getValue("userName","")> <cfset var emailAddress = event.getValue("emailAddress","")> <cfset var password = event.getValue("password,"")> <cfset var result = variables.instance.userService.saveUserProfile(UserID,userName,emailAddress,password)> <cfif result> <cfset event.addResult("saveSucceeded")> <cfelse> <cfset event.addResult("saveFailed")> </cfif> </cffunction>
From this we can extract a few observations and parse them into a couple rules of thumb that I use to keep my own mind pointed in the right direction as I develop applications (not counting laziness, client expectations, and/or anything else that may cause me to randomly break my own thumbs):
- What goes on in the service layer is effectively hidden from the controller and therefore the service methods can be used to very simply service a Flex application, an application using a different framework, or ad-hoc code. Using ColdSpring to manage your service-layer allows you to use AOP and provide your service layer to Flex, AIR and AJAX applications very easily and passing discrete arguments into service methods keeps things nice an speedy and prevents things like “infinite composition” in objects… an ugly thing that I’ve seen cripple Flex development.
- Controller methods accept an event object as their sole argument. It contains all the data from the form and URL scopes as well as anything injected into it via onRequestStart events (often application constants get stuck in the event object for convenience).
- Service-layer functions take discrete arguments relevant to whatever objects they’re dealing with… so while in this example, saveUserProfile(userId,username,emailAddress,password) is called with discrete arguments extracted from the event object you could (were you to be lazy and like to take chances with your apps) call saveUserProfile(argumentCollection=event.getAllValues()) and have done with it.
On the other hand, though, passing Transfer (or Reactor, or your own Model) objects from the service thru the controller into the view makes a good many things a great deal easier. So having userService.getUser(userID) return a User object that’s then stuffed into the event object is fine… so your controllers can then use things like makeEventBean() and stuff which simplifies somethings and makes others more difficult.
In the end, though, the goal is to make your service layer be totally independent of any other facility, and as long as you’re doing that then using specific features of the application framework of your choice when you’re creating the application does nothing to couple the service and persistence layers (or the model) to the framework. Do that and you’ve truly achieved a decoupled service layer and model and when you get around to releasing the full-featured Flex version of the application you’ve already done at least 75% of the work!