Hard Coding Scopes In CFCs Is A No No!
Now Hear This!
This is a public service announcement. If you hard code scopes inside your CFCs (request, application, session), stop today.
I know it might be 'easier' or 'cleaner' or less lines of code, but you are really painting yourself into a corner when you do this.
An object (CFC) should not know or have access to ANYTHING outside of itself, its configuration and its immediate dependent objects.
If you want to question/argue with me on this, go for it. (Just go Read Up On Information Hiding before you do).
That Is All
There are no comments for this entry.Add Comment Subscribe to Comments
What would be the solution to call an application scoped constants structure in any CFC? Do I need to transfer all structure to the CFC? What will happen when my structure is too large?
The proper way to handle that would be to pass the configuration in when you create the CFC. Also you should only pass in what is needed, not the entire structure every time.
Think of your CFC as ingredients, would you dump the entire contents of your spice cabinet into soup? Or just the spices you need to complete the recipe?
I'm not sure what you mean about the structure becoming too large. Explain please?
We are loading our German contents (I am a German :)) from resource bundles to the memory instead of calling all resources from the properties files in every need. Because they are always same for application and all users are using same stuff. This would be for example error messages that we have localized or skinning needs that we need to load into application scope for performance needs etc.
Thanks for your answers.
Like all things though, take this advice with a grain of salt. I've said the same things myself, but have found it useful to access the persistent scopes when building remote CFCs. Yes, I know ColdSpring can help with this, but not every site calls for ColdSpring.
All joking aside, does size even matter? Structures and/or objects are passed by reference as I understand it. So isn't passing in the struct 'application.stuff' just really giving your CFC a pointer to the application structure? If it were creating a separate memory space each time it were doing so, then I guess size/ingredients would matter some...
Please let me know if I am incorrect?
I agree with the exception of Scope Facades and Remote Proxy objects. Those objects can access the application, session or even server scopes directly. Just don't pass a Facade or Proxy into another object as a dependency, pass the individual values to the dependent object instead.
First off, I'm not the Andy who posted above this in case anyone is trying to keep their Andys straight - but I don't know a lot of other programmers named Andy so pleased to meet you.
Now onto my real question which is what is the real harm in using something to the effect of REQUEST.dataSource for functions within my cfcs who only live to grab records and return them to the calling pages? Some are for remote access and some are for public. If this is considered bad form please explain why.
What would be the reasoning behind REQUEST.datasource? I'm not a CF expert, but it seems that you should be using APPLICATION.datasource so that you are not setting this var on every request you make (assuming teh datasource doesnt change, maybe thats the case?)
You're kind of missing the point of my question. At any rate, I will say that using APPLICATION scope variables can sometimes become difficult in a shared hosting environment and I'll leave it at that. If it makes you feel better then we can change the question to...
"Now onto my real question which is what is the real harm in using something to the effect of APPLICATION.dataSource for functions within my cfcs who only live to grab records and return them to the calling pages? Some are for remote access and some are for public. If this is considered bad form please explain why."
... the other Andy here again! I'd still be interested to know if my understanding is correct, that being: passing an app-scoped structure into a CFC is doing little more than setting a pointer to that struct's mem space, thereby making Hans's concerns moot... or not?
@Andy (the original Andy in the thread). You are correct in your statement about passing structs as references. The benefit of providing your CFC everything it needs to do its job vs having the CFC know where things are stored becomes apparent the next time you have to change something.
As an example, consider your Application.stuff structure that you mentioned. If you pass that into the init method and design the CFC so that it takes those arguments and stores them as instance variables internally, you've just protected your CFC when, next week, the "stuff" structure needs to move to another scope (server scope, cluster scope in Railo, etc). All you have to do at that point is change from ObjectName.init(Application.stuff) to ObjectName.init(Server.stuff) and your code still works. If you've hard-coded Application.stuff all through your component, then obviously you'll have to find and update every place where it's referenced directly.
Another advantage comes when you start trying to write automated tests against your components. It's much easier to do when you can create an object, fill its properties with what you want for the test rather than having to depend on going through all the entire application request cycle and hoping you get what you need.
That's a simple example, I know, but I hope it illustrates a couple of the advantages of having your CFCs know as little as possible about the world outside themselves.
Again this is one of those things which I believe must be taken on a case by case basis. Some apps this really doesn't matter, in my opinion. There are definitely many cases where this would matter and these factors should be considered. I think a lot of developers insist on making their projects far more complex than they need to be all too often without really thinking if their projects requires a framework and OO methodologies.
Sure, if you want to be pure and best practices OO this would make sense. But then again, we are talking about CF so there's a lot of things that prevent pure and best practices OO from being implemented anyway.
On larger projects, projects with teams, or projects that will require long-term development and survive many years, I believe this is a very important practice to maintain.
There are exceptions to every rule. ;) And in this case, I think that the Application.cfc would be a big exception.
It also depends on the purpose of the CFC. As someone else said, it may be appropriate for remote proxys or facades.
I might also argue that it may be appropriate in a controller CFC to access the shared scope.
I agree with this in principal but sometimes I feel it's acceptable when encapsulating access to a persistent structure.
E.G. My UserService has a method getCurrentUser() which grabs the user object from session. There is also a setCurrentUser() method which puts the user object into session.
Every time my application needs access to the current user it asks the UserService to provide it.
I like this method as it means there is only one point of access to the persistent object. Therefore if the application requirements change down the line (from session to client for instance) I can quickly update the the getter and setter functions and everything continues to work.
In the above example it makes sense to me that the UserService 'knows' where the current user is stored and how to store it.
This blog post inspired me to refactor a CFC where I was calling Application-scoped singletons within CFC methods. Thanks, Dan.
I have a question regarding what to do with custom tags though. I've got logic with a custom tag that I need to use within a CFC. By calling the custom tag (using cf_ syntax) the method is now tightly coupled and we're back to square one.
often we have to make the best tradeoffs available to us. If you have a custom tag which you need to call within a CFC, the best you can do is encapsulate that specific call somewhere that isn't inside a whole bunch of logic.
Encapsulating the logic of the custom tag allows you to separate out the concerns and helps insulate you from any changes going forward.
I usually use the CFImport syntax for my custom tags because that lets me specify a full path, one that can be searched for when something related to that path changes.
The CF_ syntax uses some built in paths and is less direct.
As in all things, you have to make the right set of tradeoffs for your application which occasionally means you go against the better practices out there in order to meet real world conditions.
Your advice inadvertently helped me fix another issue I was having which had to do with cfscripting. The method that was using the custom tag was all cfscript except for that one part with the custom tag. Not only was there too much logic in this one method, but it was just messy looking.
Moving the custom tag portion into a separate method really helped clean things up. I did have to make some slight modifications to the custom tag, but it was all for the better.
I never considered using the CFImport syntax before. I think I'll be looking into that next.
Thanks for your help!
I ran across this while working on adding some features to an existing application a few months ago. For me it caused some major rewrites to the existing objects when trying to use ColdSpring to manage my objects. That situation inspired a couple of blog posts on the advantages of using ColdSpring (http://dan.skaggsfamily.ws/category/coldspring/).