One of the first things I learned when I was first starting to work with Object Oriented Programming in ColdFusion was the concept of a ScopeFacade. A ScopeFacade is an object that encapsulates access to a given variable scope.
For example, you might have a CFC which, for all intents and purposes, wraps the Application scope. This CFC would have methods such as getValue() and setValue() which would get and set the specified values in the application scope.
This is nice because it condenses all your access to these scopes in to one specific location. It also allows you to swap this CFC out for a different implementation in the case that you’re working in an environment where you do not have access to the particular scope.
For many years now I’ve been using a particular CFC (included with ReactorBlog) as a scope façade. When you instantiate it you tell it what scope it’s wrapping. After that you can get and set values to your heart’s content.
The particular ScopeFacade I use makes a reference to the specific scope in its own variables scope. I do this to avoid having to evaluate each variable each time I use the CFC. For example, it boils down to the difference between:
<cfreturn evaluate("#variables.scopeName#.#arguments.name#") />
<cfreturn variables.scope[arguments.name] />
In the end, neither are pretty. I chose to go with the reference.
The thing is, about once a month, I make the same boneheaded mistake. I put a SessionFacade into the application scope! For example, I might do this by setting a variable-scoped variable in a Model-Glue Controller. I don’t tend to notice the problem until I move the site to production and my users start screaming about seeing other people’s data. (“It says I’m logged in as the CEO!” D’oh!)
That’s when I realize that to have an effective SessionFacade I need to instantiate it each time I need to use it. That way the reference is always to that particular user’s session. (Well, either that or run evaluate each time I want to interact with values.)
Doug’s Note: The other day Jared was trying to sell me on a ScopeFacade he wrote that uses undocumented methods to get and set values of a variable for a given scope. It may work, but, to me it smells funky. I don’t want to use undocumented features in a production app. The fact that I might need to do it indicates that scope facades might not be the right solution to the problem.
The question then is, if there’s no good implementation then why are we implementing at all?
My opinion on this is because of the lemming mentality. If one of the notables in the community says something then it must be the best way to do things! <cough>Duck Typing</cough>
Really, the primary argument is that a given scope might not always exist. However, if you’re using one of these Facades then you know the scope must exist! The argument seems self defeating.
What I’d rather see is people avoiding direct use of the scopes in their model and services layers. However, I think the use of session variables in controllers is perfectly acceptable!
For example, in Model-Glue, the framework already requires the Application scope and requires the Session scope for stateful redirects. Furthermore, if Session or Application variables are disabled you’ll probably know about that ahead of time and you’d need to so that you could change the implementation!
If you need a value to be provided to a CFC then pass it to the CFC. Or, if you need a collection of unknown variables within a CFC then pass the entire scope into the CFC as a struct. This will let you get whatever values you need without breaking encapsulation.
And, as one last point, many highly visible ColdFusion developers have recently been excited by the concept that maybe you really should use all the features provided by the Language. Mixins? Sure, if you can, why not? Duck Typing? If you can, and need to, then gopher it!
It really boils down to pragmatic programming. If you need to, and you can, then do it!
It’s generally agreed that Controller components serve the purpose of ferrying data around. From that perspective, and the fact that ColdFusion provides easy access to different variable scopes, it’s just fine for your controllers to access this data directly and pass it into your model and services. However, don’t let your model and services touch any scope other than Variables, This or Super directly. That would break encapsulation.