Are You Running ColdFusion on a Mac?

Yes, Apple is a fantastic company, making really nice products that work very well. If someone gave me one of those nice Macs with the 27" screens today, I'd probably switch. I wouldn't buy one myself. Nice as they are, I can't justify the expense when I can buy a machine twice as powerful for half the money, and actually repair it myself when I need to. But, that's my decision. I choose the imperfections of Windows on a PC architecture as a counter to the affordability and maintainability of the platform. And, it's done really well by me.

I watched Andy Matthews accidentally spill orange juice on to Aaron West's 17" MacBook Pro once, several years ago. Aaron finally got it back from the Mac Store about two weeks later. I can't afford that kind of productivity loss. No thanks.

Again, this is just me. Many others still use a Mac, and love it, and I get it. It's a fantastic operating system, and Apple does make pretty stuff.

But I wouldn't load ColdFusion server on a Mac. Not really. Not on to OS X directly. Yet, I've heard this complaint recently. About how buggy the ColdFusion install is, and what a hassle it is to get up and running.

You're running it on a Mac? On OS X? Why?

The web doesn't run on a Mac. Yes, there are OS X servers, but have you seen that market share? The web runs on *nix and Windows. And, if you're writing code for the web, then your environment needs to match. Load up a VM, and install ColdFusion on the VM, in *nix or Windows. That makes sense.

Is that where you're having trouble? I get CF up in about 20 min on my Windows Server VM, and that includes the download time.

Now, should the ColdFusion server install easily on a Mac? Sure, I think it should. There are way too many developers out there trying to do exactly what I've described, and they're in pain. Go badger the Adobe CF team to get it straight.

But, again, what's your site running on?

You can post comments if you like, but I'm not taking the bait.

What's Wrong With ColdFusion? Round 1 Response

Last week I raised the question, and Wow! Have people responded? Yes. There's some fire in the belly, and a lot of people have a lot of opinions. More importantly, they have a lot of great ideas as well. So, what I'd like to do here for a minute is break down all of that feedback, to get down to the meat. We've attracted some attention, with our little discussion, so I think it's important to focus on all of the core points. From there? Good question. People are listening. Maybe we help to blaze a new trail in the wilderness.

Make It Better

First and foremost, there was an overwhelming call to "get with the times". Among complaints about stability, setup, and pricing, the key take away was that the server needs some retooling. Smarter people than me have talked about the pitfalls of CF running as a servlet, issues with context roots, and (continuing) issues with object instantiation, and all of these things should be addressed. Take that feedback and couple it with the two largest suggestions in the bunch: Modular feature deployment/package bundling and management, and a Command Line Interface (for multiple reasons).

A modular approach can absolutely open a lot of doors, both for developers and Adobe. It can allow someone to deploy a server with only what they require for their application, or upgrade that server's capabilities as required as well. These cut out the cruft, allow the system to be smaller/faster/better, and possibly provides a new (and ultimately more profitable) way for Adobe to handle the licensing of their product. Strip 'er down to her core, then provide deployment packages for things like cfform, orm, office and exchange integration, etc. This modularity also would allow Adobe to laser focus on updates to key areas in a more timely fashion as well (like bringing SharePoint or Exchange support up to the current version in a productive way, etc).

As a broader part of that picture, many asked for the removal of features (UI cruft, cfform, all tags, etc). This isn't really practical, considering the thousands of applications running and supported on ColdFusion today. Adobe needs that licensing revenue. That said, the revenue goes away if they (insert business names here) start switching languages. This modular approach opens new licensing models, better tailored to larger business (and developer) needs, and can address key concerns on the cost of scale. The comparison to the current cloud offerings are a prime example of how this model could truly be a more effective tool for everyone.

The next major suggestions all revolved around core language improvements. The tag model does have it's place, especially with the templating aspects of ColdFusion (generating output), but CFScript, and associated core "functions", require some overhaul. There's a lot of inconsistency in naming conventions, argument order and treatment, lack of member functions, core output, etc., and there's some serious call to correct that. CFScript should be more ECMAScript compliant, and Adobe already has serious experience with this with their development of ActionScript. How they do all of that, and maintain backwards compatibility at the same time, is a question for folks smarter than me, but it absolutely makes sense. Working in ColdFusion should feel native to anyone who writes HTML, CSS, and JavaScript for a living, and right now it's a little off the rails there, especially when it comes to script.

True Issues To Address

Aside from the suggested improvements, there was a lot of conversation about things that truly are broken, and require attention. I'm not just talking about the list of bugs in the bugbase, but some core process issues. Adobe ColdFusion is a paid product, and that licensing includes "enterprise" support. As such, a common complaint is that the support is unknowing, uncaring, or unresponsive. When I call in for support on install issues with Creative Cloud, I was able to get quick and solid resolution, and follow-up. Why should ColdFusion be any different? And why, when a true issue is brought up (like some of the recent security issues), should it take weeks and months to admit the problem, allocate resources, and write/test/deploy fixes?

I, and everyone else, understand that ColdFusion server development is a closed ecosystem, being that it is a corporate product. It does not have the benefit of rapid development that an Open Source project might have, with a large community behind it. That said, considering the costs involved in licensing the product, the turnaround model on identified issues actually ranks a higher priority. How you interact and respond to your customers is critical. This is just business sense, as the customer you keep happy is the one that you retain and keeps buying your product (and tells others how awesome it is).

The other addressable issue, brought up in the conversation, is marketing and education. ColdFusion isn't being taught (or it is, but very little), and new developers aren't coming in to the fold. Some of this is marketing, some of this is perception, and some of this is ... Well, what is it? Why isn't every high school and college in America (or the world) given licensing for ColdFusion? Not ed licensing to dev on, but actually running their university sites, and student unions and such? Why aren't there coding challenges being sponsored in classrooms, to help create the next round of rockstar open source applications? And why aren't there timely, up-to-date, curriculums being developed for these markets? Materials that help teach the language, with focus not only on the language and the server but also development as a whole and best practice?

OK, so all of these "issues" require resources, in an age when things have been scaling down. We've identified them as issues. We've identified their importance. Now it's up to someone to decide the value of addressing those issues.

Where's Our Community?

ColdFusion has, for me, always been a great community. There are hundreds of developers out there who have worked at this stuff for a long time, tripped over good code and bad, and attempted to provide their own brand of support through blogging and answering StackOverflow questions, and just sharing in general. They've done these things, usually, on their own time, with their own money, and at the sacrifice of other things.

But, it's easy to fall off that wagon when you're trying to help others and someone else just tells you "you're doing it wrong". A great case in point here is the OO debate: should you or shouldn't you. First, I'll say "yes, you should", for a thousand little reasons, but then I'll also say "you don't have to, but you should." Second, I'll say that there's no one way to approach development, and that each approach provides it's own pluses and minuses. The single greatest thing that you can do, as a developer, is to read other peoples' code, and realize that it might not be the best approach, or that it might be a much better approach. Each of us has something to learn from someone else, as each of us has a different perspective. Yes, sometimes that perspective may be wrong, and it's good for us as a community to police one another, in our examples, to help promote better code. It's how we have those conversations that will change us. "This Sucks," is not a productive response. Sure, I hate getting called out on my crap code, and then I learn from it (thanks Ray ;) ) [For the record, go read the code for FW/1. Outstanding! The things I learn from Sean...]

The other side to that coin is the framework debate. We have a lot of "mine's bigger than yours" going on, still. The thing is, these are tools, each of them written differently and from different points of view, and if all of these framework developers were to collaborate, instead of pulling out the yard stick, we could really move mountains. You people are smart, and you're dedicated, and you have great ideas. Please work with each other instead of against one another.

And this comes down to the final area of discussion, in round 1, and that's our community's willingness to share their work. There are many people out there that write thousands upon thousands of lines of fantastic code that never sees the light of day outside of a firewall. One great comment I saw said something like "What if every CF project were out there and you could just drop it in and it almost worked?" How many user management modules have you written? Permissions systems? Rudimentary document management? Can't you put anything on GitHub? RIAForge? Every small bit of code we contribute, as a community, adds to the overall ecosystem. We have to start helping each other solve common problems. These other communities, that so many developers are turning to? That's what they've been doing right. And that's where we, as a community, have been failing. There were a lot of fingers pointed toward Adobe, in the comments to my post, but I'll remind you that every pointing hand has three fingers pointed back. We have brought a good bit of this upon ourselves as well, and only we can change that.

I, for one, do not think the battle is over. I, for one, still think there's a life for ColdFusion and ColdFusion development. Yesterday Matt Gifford and Scott Stroz and I sat down for the CFHour podcast, and Scott said "If JavaScript can have such a resurgence, then why can't ColdFusion?" And he's right.

So, this recaps (very high level) all of the comments on my last post. The discussion has begun, now where do we take it? Can we define a path for ColdFusion's future? Is Adobe part of that discussion? (I hope that they are) I would like to hear from you again, dear reader. What are your thoughts on what's being said today? Throw out the negative, focus on solutions, and tell me what you believe can/could/should be done for us, as a community, to move forward and thrive.

What's Wrong With ColdFusion?

So, today there was a little discussion on Twitter about ColdFusion. ColdFusion lives on top of Java, specifically on top of the JVM, which makes it capable of processing other languages as well. Sean Corfield has put out some things in the past on this. I mentioned that it would be good to rekindle talk of how that is possible, in ways to help promote ColdFusion as a platform.

I was somewhat surprised by Sean's response.

#coldfusion really has no value to those communities - they already have better languages and better tools

Now, I want to go on record now as saying that I love Sean to death, and really and truly respect his work and his opinions. I also love ColdFusion a lot too. So, my question (basically) then became "What's wrong with ColdFusion?"

So, I posed another question to Sean, that I'll pose to the community as a whole: What's wrong with ColdFusion as a language? As a platform for enterprise development? More to the point, how can it be made better?

I'm not looking for a hack fest, or "my crap is better than your crap" stuff, I'm looking for some solid feedback. What does it take to try to make ColdFusion a first class choice among programmers of web enabled applications? More to the point, what does it take to do that and keep it CF simple? ColdFusion has always been a great Rapid Application Development platform, with a very lower barrier of entry, and an ease to learn and maintain. Is it too simple? Too forgiving?

If the direction of the ColdFusion platform development were to drastically change today, with a focus on the language and the core of the system, what would/should that look like? What is truly missing? What should be done differently, and how? (And why?) Gimme the nuts and bolts.

The floodgates are open now. If we never talk about it, nothing will ever change. Please be constructive, and let me know your thoughts.

Legacy Code Part 17: The Rest of The Story

As developers, sometimes it is hard to see beyond the code. We know code. We like code. Some of us occasionally even dream in code (just ask my wife...) Knowing this, it is sometimes difficult, when troubleshooting performance of Legacy Code, to remember that the issue might not be in code.

One great area, that so many developers overlook, is the ColdFusion server itself. The installer makes it fairly easy to get things up and running, but is the environment truly setup optimally for your application? By default, CF only loads allocating 512kb of RAM to the underlying JVM. 512kb is not much, especially in a high traffic, heavy process system. And have you ever adjusted your Request Tuning settings? Checked your Queue Timeout? What sort of template caching are you using?

Another area to look at is your JVM itself. While you can adjust some of the JVM settings in the CFIDE (in ColdFusion 10) properly, it's still a good idea to review things like your Garbage Collection settings, your RAM allocation, and other bits. Are you loading unnecessary libraries? And, are you still using the installed version of the JVM? It might be worth while to download a new JDK, install, and test your app. For one thing, it'll help keep your underlying Tomcat more secure.

Then there's the hardware and network review. What sort of throughput are you getting from your hard drives? Is your file I/O optimal for the ops you're running? Are you storing data and assets on other network connected systems and, if so, what sort of throughput are you getting from those internal connections.

And then we're back to your database. Hopefully it isn't on the same machine, but the same sort of review applies. Do you have enough RAM? What sort of hard drives are you using? Are you getting enough throughput through that old NIC card?

Some of these things are really easy to address, taking a little time and effort and research. Others may require parts and equipment replacement, maintenance windows and downtime. It's really up to you to balance out what makes sense.

Step one: write a plan.

Step two: follow through.

With these last 17 posts I've written down a lot of little things to help anyone take their Legacy Code (outdated and tired ColdFusion applications) and begin to carry them forward into new life. Some changes are farther reaching than others, and all require careful research, planning, management and testing. To let these applications sit, without thought for modern change, is to waste the time originally spent to create them in the first place. Nothing grows without care and feeding and light.

It is my belief that you can still benefit from the hundreds of thousands man hours of previous time and effort spent on these applications, without having to take drastic moves that could prove unnecessary or even disastrous. ColdFusion was the first web application server, outliving many predecessors, and continues to grow with the times. ColdFusion continues to be a fantastic Rapid Application Development platform, allowing many developers to write applications in a fraction of the time it would take on other platforms, and there's a solid roadmap for future versions already on the board. There are thousands upon thousands of active, thriving, scalable and performant ColdFusion based applications on servers in thousands of top ranking companies in countries all around the world, still, to this day, because of the power available here.

This article is the seventeenth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 16: How You Get Data

One of the greatest culprits in poorly performing ColdFusion applications, Legacy Code or modern, is badly written SQL. ColdFusion was originally written as a middle tier between the web server and the database, giving us the ability to output queried data in html format. In fact CFML was originally DBML. One of it's greatest strengths has always been the ease with which one could get data back from a multitude of datasources, from a variety of platforms, and display it to a user. One of it's greatest weaknesses is that it allows you, the developer, to write those queries just as poorly as you want to as well.

How many queries in your system start with SELECT *? Of the 35 columns in that table, are you really using more than five or ten? And, do you have multiple <cfquery> calls, one after another, with each using data from the query before? Can this be translated into a single query using some well thought out joins? By the way, when's the last time you analyzed your query performances? How about rebuilt your table indexes?

In most applications that I've worked on, Legacy and modern, major bottlenecks occurred due to the poor performance of queries. Applying <cfqueryparam>s helped a little, but truly reviewing each query, running it through a query analyzer, rebuilding and creating new indexes.

Some people, especially writing quick small apps and prototypes, have used ORM frameworks for their database interaction, such as Reactor, Transfer, and now ColdFusion's own built-in implementation of Hibernate via ColdFusion ORM. These are very popular, and great for quickly standing up new product, but they are also very object intensive, and don't necessarily give you deep introspection into what those data transactions are truly doing under the covers. Yes, they can allow you to quickly build new applications, but that doesn't necessarily mean that those applications will scale well, or continue to perform three years later the same way they did on day one.

There was a really good article by Chris Travers on DZone, a few weeks back, defending the choice to continue to hand code your SQL. It's not a very long article, but one paragraph really stood out for me, and is something that I already do.

I find that my overall development time is not slowed down by hand-writing SQL. This remains true even as the software matures. The time-savings of automatic query tools is traded for the fact that one doesn't get to spend time thinking about how to best utilize queries in the application. The fact is that, as application developers, we tend to do a lot in application code that could be done better as part of a query. Sitting down and thinking about how the queries fit into the application is one of the single most productive exercises one can do.

This is something that is very easy for me to identify with, and also a good argument for the (occasional and well thought out) use of stored procedures. Many developers stay away from stored procedures because a) they don't know how to write or use them, and/or b) those procedures aren't stored in code, so it's not as easy to introspect or search for things when you're making changes. While both of these may be valid arguments, in some way, there is the performance trade off. Stored procedures due, typically, perform better, having compiled cached execution plans on the SQL server. If you can overcome your other obstacles (and you can), you can gain from placing complex SQL logic inside of stored procs.

Again, this type of change, in a large Legacy Code system, can be long and arduous. Set a goal, with each bit of maintenance that you do, to review the queries you are using in the requests you are adjusting. Tools like FusionReactor can help you identify slow running queries, for you to target your efforts. It may pay well to hire an outside SQL resource to review your databases, monitor query performance, and provide detailed analysis and suggestions on improvement. A good DBA, even a part timer, can save a Legacy Code application from extinction.

In our next post we'll dive into some of the things that you can do at the Application Server level, to help you get the most out of your Legacy Code.

This article is the sixteenth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 15: Continue to Maintain, Sustain, and Innovate

All of the steps we've taken, up to this point, have talked specifically to bringing your code into this century. Chances are, you're still maintaining this application. Maybe you have a new module that marketing wants you to add, or sales needs this other sub-app rewritten to catch up with the times. You aren't really going to do this in Fusebox 3 again?

Let's stop a minute and talk about new code. Most applications who live this long rarely stop growing. They generally started off as prototyping a "neat idea", and became thousands of templates of code serving multiple purposes. Most of these also fell into the Big Ball of Mud Design Pattern, which is probably part of why you ended up here in the first place. Things are starting to fall off.

First of all, make yourself a promise to do any work, going forward, in a manner that benefits both your business, your clients, and your future development staff, without cutting corners. If you aren't going to do it right the first time, when do you think you'll get the opportunity to fix it? Getting to market a month later will cost you far less than pushing early with bugs, poor performance, and missed expectations.

Second, consider a modern framework. I know, some people hate frameworks, but the advantage is a consistent way of doing things that is already documented. I've used Fusebox, Mach II, ModelGlue, ColdSpring and ColdBox, but overall I prefer FW/1 and DI/1. They are lightweight, their flow seems like a natural extension of ColdFusion's existing application framework, and they work well with large, high traffic systems (in my experience). Whatever your preference may be (or become), go with something that enforces a Model View Controller architecture, for a separation of concerns and easier overall maintenance. Choose the ones that are right for your apps, stick with them, and make them your standard for new development moving forward.

Third, come up with a process. Document your development process, and stick to it. From requirements gathering, to R & D, to source control strategies, to client sign-offs and end-user testing, put together a complete end-to-end methodology for how you vet tasks, write code, test work, and promote projects from local to staging to prod. Eliminate the guesswork, by defining a standard. If the process breaks down, or something just isn't working, then discuss, adjust, and move forward.

The last thing I will say on this is "plan". Take the time to sit down and write it all out. Gather all of your requirements, draw up some mockups of interfaces and detailed diagrams of interactions, and break everything down into small, measurable, digestible sub-tasks. Setup a system like Redmine to help you track assignments and progress, integrating them with your source control system wherever possible.

In our next post we'll get back to the business of upgrading our Legacy Code, to make faster and more responsive applications.

This article is the fifteenth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 14: The Rest of the Scope Story

In our continuing quest, to upgrade Legacy Code to the modern age, we continue our discussion on scoping. As previously noted, you should explicitly scope each and every variable. Aside from the performance gains made, it will also make your code easier to follow, to find where each variable is set and changed. To date we've talked about the primary persistent scopes, the "passalong" scopes, the scopes used with Custom Tags, and those scopes used in CFCs. In this post we're going to talk about a few of the remaining scopes (and in some cases, non-scope scopes).

CLIENT
- This scope is a persistent scope, and the reason that I did not bring it up before is because of the overhead associated with using it. The CLIENT scope stores its data in one of three places: the Registry, Cookies, or a database. All of these methods have their own pros and cons, but ultimately CLIENT storage access can be a significant hit to application performance, especially if managed poorly. The CLIENT scope isn't all bad, being a valuable tool for simple variables in clustered environments (for example), but it does come with a cost, which should factor heavily into any decision making over whether to use it or not.

It isn't very common to use the CLIENT scope today, but I do bring it up because of the amount of Legacy Code that does exist using it. You will want to thoroughly consult the ColdFusion Documentation on its use, and weigh the trade off's involved. There are a lot of caveats around the different types of storage, and you should also review the documentation on the CLIENT settings in the CF Admin.

CGI
- When the browser requests a page, the web server and the browser pass along certain environmental variables back to ColdFusion. It is possible to use these variables for very valuable information, like whether its an HTTPS request, or what the actual domain name is. One important thing to note, when using CGI variables, is that different web servers can (and do) use different keys for the same information. What this means is, if you happen to be using PKI client certificates for authentication to your application Apache will pass those credentials in a completely different key than IIS would, and different versions of IIS may use different keys as well. If your application is portable (designed for deployment on multiple platforms), you'll want to be very careful in determining your use cases.
COOKIE
Just like it sounds, this scope is to get or set browser cookies. It takes simple name/value pairs. Using the COOKIE.somevar = "something" syntax will create the key/value in a cookie for the application's domain in the browser. For a finer level of control (setting expiration, etc) you are still nailed to use <:cfcookie> in its tag form. (I'm hoping this will change in the future.)
THREAD
- Threads are still relatively new to ColdFusion, allowing you to write multi-threaded processes. You won't run into Thread code prior to CF 8. Threads actually have three scopes: THREAD, Thread local, and Thread attributes. I'm not even going to touch on scoping of Threads, referring you instead to the ColdFusion Documentation on Working with Thread Data.
Unscope Scopes - Query, CFFile, CFCatch, etc
- There are several scopes that aren't really scopes, so much as data returned during the process of certain tag processes. You always want to prefix access to these variables. See the ColdFusion Documentation for details on each one individually

This post wraps up our review of the different scopes, and their use cases, so that you may more effectively explicitly scope every reference, and use the right scope in the right scenario. There are exceptions to most use case rules, and you will have to make the determination if it's worth making those exceptions. Scoping an entire application can take a great deal of time, and is generally done in small pieces, testing each change along the way. Source Control branching strategies are invaluable at this stage of development.

During our next post, we'll discuss how you might go about new product development, and existing product maintenance, during the process of upgrading your Legacy Code applications.

This article is the fourteenth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 13: An Object Lesson

When upgrading Legacy Code applications to modern ColdFusion programming, one of the greatest advancement of the past decade was the ability to create CFCs. CFCs allow you to create reusable objects in code, that can have their own properties and custom methods you can define for very specific purposes. The ColdFusion Documentation gives you some great information on writing CFCs, but makes it very difficult to find out how to write scripted CFCs. The Component Tutorial on Learn CF in a Week is much easier to find and understand.

But we're still talking about scoping your code, and you might already have CFCs, or just starting to convert some things over, so we're going to discuss the various scopes you have available within a CFC and their usage.

THIS
- This scope is a reference to the object itself. The THIS scope is unique to a specific instance of the object. It is a public global variable scope of the object. What that means is, any data that you create in the THIS scope can be seen, and even modified from both within and without the object itself. To illustrate, we'll create this very basic component.

test.cfc

view plain print about
1component {
2    THIS.name = "";
3    /**
4     * @access public
5     * @output false
6     * returntype any
7     */

8    function init () {
9        return THIS;
10    }
11    /**
12     * @access public
13     * @output false
14     * returntype void
15     */

16    function setName (required string name) {
17        THIS.name = ARGUMENTS.name;
18    }
19}
We can then create an instance of this object, set the "name", and then access the property.

index.cfm

view plain print about
1<cfscript>
2    REQUEST.testObj = CreateObject("component", "test").init();
3    REQUEST.testObj.setName("Cutter");
4    WriteOutput(REQUEST.testObj.name);
5
</cfscript>
When you execute this code, you see that the "name" that you set is available as a public property of the object. But, as I said, the variables are public. This can have some unintended negative effects as well. Add these lines after that last WriteOutput statement:
view plain print about
1REQUEST.testObj.name = "Blades";
2    WriteOutput("<br>" & REQUEST.testObj.name);
When you execute the code now, you can see that you were able to directly change the property of the object from outside of the object. This can be bad, as it exposes your variables and breaks encapsulation. Many developers never use the THIS scope because of this.
VARIABLES
- And here we are back to the confusing VARIABLES scope. Use of this scope, within CFCs, is one of the two documented use cases for this scope (see our last post for the other). The VARIABLES scope is a protected CFC global local scope, meaning that the variables in this scope are only available within the instance of the object, and globally available by any method of the object, or any object that inherits the object by extension.

Let's change our test.cfc trading out the THIS scope for the VARIABLES scope, and try executing our code:

view plain print about
1component {
2    VARIABLES.name = "";
3    /**
4     * @access public
5     * @output false
6     * returntype any
7     */

8    function init () {
9        return THIS;
10    }
11    /**
12     * @access public
13     * @output false
14     * returntype void
15     */

16    function setName (required string name) {
17        VARIABLES.name = ARGUMENTS.name;
18    }
19}
When you attempt to execute the code, you immediately get an error, because "name" is no longer publicly available. Let's add a "getter" method to our test.cfc, to get the value of "name":
view plain print about
1/**
2     * @access public
3     * @output false
4     * returntype void
5     */

6    function getName () {
7        return VARIABLES.name;
8    }
We can then change our index.cfm to use this method for access this instance variable.
view plain print about
1<cfscript>
2    REQUEST.testObj = CreateObject("component", "test").init();
3    REQUEST.testObj.setName("Cutter");
4    WriteOutput(REQUEST.testObj.getName());
5
</cfscript>
Since the variable is local to the instance of the object, and globally available to all methods, you can "set" the variable with one method, and "get" the variable with another. Let's add a bit more to our process script, to illustrate how the variables are instance specific.
view plain print about
1<cfscript>
2    REQUEST.testObj = CreateObject("component", "test").init();
3    REQUEST.testObj.setName("Cutter");
4    WriteOutput(REQUEST.testObj.getName());
5    WriteOutput("<br>");
6    REQUEST.testObj2 = CreateObject("component", "test").init();
7    REQUEST.testObj2.setName("Blades");
8    WriteOutput(REQUEST.testObj2.getName());
9
</cfscript>
Try that out, and you'll see that each instance retains it's own, private, instance specific variables
ARGUMENTS
- Discussed previously, this "passalong" scope is available within a specific function. In reviewing the setName() method in our test.cfc, you see that we access the arguments passed into the function via this scope. The ARGUMENTS of one function are not directly available to another, without passing them along as well.
LOCAL
- A cornerstone of writing threadsafe objects, the LOCAL scope is a function local scope, meaning that any variable created in this scope are only directly available to the function they are created in. To give you an idea of how this works, add the following to test.cfc:
view plain print about
1/**
2     * @access public
3     * @output true
4     * returntype void
5     */

6    function localTest () {
7        var var1 = true;
8        local.var2 = 42;
9        var3 = "whoops";
10        WriteDump(var=local, label="localTest local scope");
11        WriteDump(var=variables, label="instance variables scope");
12    }
And add this to your index.cfm:
view plain print about
1REQUEST.testObj.localTest();
When you execute the code, you'll see the basic <cfdump> output of the LOCAL scope of the function, as well as the VARIABLES scope of the object. Notice that both var1 and var2 are both in the function LOCAL scope, whereas var3 is in the object's VARIABLES scope. If you do not explicitly scope your variable, then it will be applied to the CFC global VARIABLES scope. (Just more validation for explicitly declaring each variable's scope.) While use of the var declaration is no longer necessary, as of ColdFusion 10, it is good practice to continue to use it when declaring new function local variables. User var to declare (which you can now do anywhere in your function), then prefix the variable whenever you reference it later in your function.

And that wraps up the basic scope usage within a CFC. Remember that when you need to use an outside variable within a CFC, you want to pass that variable in as a function argument, rather than directly accessing a persistent scope from within the CFC. You can access a persistent variable, but that doesn't mean that you should.

There are a few other scopes that we haven't yet addressed in this series. In our next post, we'll quickly discuss some of these, and their general usage.

This article is the thirteenth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 12: The Scope of Tags

When upgrading Legacy Code, part of the fun is moving from a much older procedural process of coding to a more Object Oriented way of coding. For those who have little experience with OO development, it can be confusing, and even daunting. ColdFusion doesn't require an application to be OO, but it is a smart idea to reuse code whenever possible. With the invention of CFCs, many versions ago, ColdFusion came into a new age of reusability.

But ColdFusion has allowed reusable code for some time. Aside from the ability to <cfinclude> a file as often in page flow as you might want, it has also had Custom Tags for quite a while now. In this post, let's explore the usage of the scopes available within Custom Tags.

ATTRIBUTES

In our last post we talked about this "passalong" scope. To enforce encapsulation, and manage dependencies, it is best to "pass in" any outside variables that your Custom Tag might need, rather than directly accessing that scope from inside the Custom Tag. A tag's ATTRIBUTES are only available within the tag, or within any nested tag of the tag as part of it's CALLER scope (yes, you can nest tags, and more on the CALLER scope in a moment), though it is again best to "pass" attributes to a nested tag as part of its attributes. Best practice is to <cfparam> each attribute at the beginning of your custom tag, declaring it's type and a default value. This allows your code to be somewhat self documenting, and helps to identify any inherited dependencies.

VARIABLES

This is where I will undoubtedly confuse a lot of people, because usage of the VARIABLES scope is confusing. Many examples exist out there showing the use of VARIABLES just about anywhere and everywhere, but I will tell you that the only places you should use the VARIABLES scope (IMO) is within Custom Tags and CFCs. While possible to use the VARIABLES scope within a standard CFM, it is better to have those VARIABLES converted to the REQUEST scope, because there is a documented use and reasoning for the VARIABLES scope, and that's not it.

The VARIABLES scope, within Custom Tag usage, is a protected "local"scope of that Custom Tag. Within a Custom Tag, the VARIABLES scope is often used for internal business logic, such as looping iterators or temporary variables. Once tag execution is complete, any variables used by the tag's VARIABLES scope are gone, being cleared from memory. You can not access a tag's VARIABLES scope outside of that tag, excepting a nested tag's CALLER scope (more in a minute), because those variables will no longer exist.

CALLER

Custom Tags contain a unique scope in the CALLER scope. This scope is used to access certain variables of the template that requested the Custom Tag. If, within a nested tag, you were to <cfdump> the tag's CALLER scope, you would see the following items in the output:

  • ATTRIBUTES - the ATTRIBUTES scope of the tag that called the nested tag
  • CALLER - the VARIABLES scope of the template that called the tag that called your nested tag (yeah, that's not confusing)
  • variables - individual name/value pairs of any variables assigned to the calling tag's local VARIABLES scope
  • THISTAG - the THISTAG scope of the tag that called the nested tag
If you are passing in all of the variables you need to utilize in your tag (as you should) then the only time you would reference the CALLER scope is to set some value to a variable in the template that called the tag. In a nested tag, this is a way of changing a value in the calling tag's VARIABLES scope.

Now, I told you a moment ago that you shouldn't use the VARIABLES scope in a standard CFM. So how would you change a variable value in that standard template from within a base tag? I proposed that you change those variables to the REQUEST scope, but I also said you should not access the persistent scope directly. You can use the tag's CALLER scope, using the following notation, to change that request's variables.

view plain print about
1CALLER["REQUEST.myVar"] = "foo";

You can use the same notation to address any of the persistent scopes, remembering that, outside of REQUEST, you will need to use <cflock> to avoid race conditions for any concurrent sessions.

THISTAG

This is another scope completely unique to Custom Tags. You will never set variables to this scope, as any variable held here are generated by ColdFusion for your use. They give you details on the current ExecutionMode of the tag, whether an end tag exists (HasEndTag), and others.

Conclusion

Custom Tags are confusing, yet extremely powerful, constructs of the CFML programming framework. They are a way for you, the developer, to create your own CFML tags. You can even <cfimport> a library of Custom Tags into your pages for simpler access.

view plain print about
1<cfimport prefix="ui" taglib="/CustomTags/ui">
2<ui:siteHeader><!--- opening html, header, meta, css, and opening body tags --->
3<p>My page content here</p>
4<ui:siteFooter><!--- javascript and closing body and html tags --->

This post only scratches the surface of Custom Tag development, trying to demystify the usage of the scopes that they use. For a full explanation of their usage, you should review the ColdFusion Documentation on creating and using Custom Tags. As I've said in the past, Custom Tags are ideal for creating reusable bits of display code. CFCs are intended for reusable components of data access and business logic, and very-rarely-almost-never for display. We'll discuss scope usage of CFC's in our next post.

As a side note, my usage of the VARIABLES scope stems from some evidence that, in the past, usage of the VARIABLES scope within standard CFM templates did not always properly get cleared out of memory. This may or may not have been corrected by now, but the use cases for the VARIABLES scope hasn't changed any, and I've found that the changes in how I've used it have always improved my applications' overall memory utilization. So, I've continued to code in this way, and it's always proved effective.

This article is the twelfth in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Legacy Code Part 11: Pass It Along

One thing that affects application performance, in your Legacy Code, could be a lack of (or misuse of) variable scoping. In our last post we discussed the usage of the various persistent scopes. Now, we'll talk about some of the other scopes that your application might be using.

In this post, we'll get the easy one's out of the way. It's really all in the name, for many of these, which I like to call the passalong variables.

URL
- These are the variables from the url query string. Not the most secure way to pass around information, but some variables don't always require protection. It is typically good practice to <cfparam> url variables, on the off chance that the link was truncated.
view plain print about
1<script>
2    param name="URL.debug" type="boolean" default=false;
3</script>
FORM
- These variables are available to a template that is the target of a form post. It is made up of all of the form field names and values passed in a post, and includes a special "fieldnames" key as well, that contains a comma delimited list of all of the passed form fields. It is important to note that browsers do not pass checkbox fields that are unchecked, so it is always a good idea to <cfparam> any checkbox fields.
view plain print about
1<script>
2    param name="FORM.categoryid" type="numeric" default=0;
3</script>
ARGUMENTS
- These are variables that are passed into a function method, for use within the function. When you need a variable in a function, from outside of that function (for instance, a persistent scope variable), you want to pass the variable into the function as an argument. This will help to prevent memory leaks, maintain encapsulation, and manage dependencies. A bonus is that you can use the argument definition in the method signature in a way similar to <cfparam>, by providing a default value.
view plain print about
1<script>
2/**
3 * @access public
4 * @output false
5 * @returntype void
6 */

7function setUser (required string firstName, required string lastName, boolean isActive=true) {
8 // Your code goes here
9}
10</script>
It is always important to declare the argument's type in the method signature (as in <cfparam>), as it will assist in the overall security of your application by ensuring that methods receive the proper variable type.
ATTRIBUTES
- The attributes scope is the arguments scope of custom tags. Similar rules should apply, in that if you require data from another scope, within your custom tag, then best practice is to pass the variable in as an attribute of the tag. Just like <cfargument> and <cfparam> you can (and should) define a type for the variable, as well as a default value if necessary.

Quick author's note here: You'll notice, in my code examples, that I use the <cfscript> form of code, while referencing the <tag> form in my dialog. Most Legacy Code is tag based, but you will find more and more core business logic is written in scripted form. Each scripted block can be done in tag form, but I personally stay away from tag based code for anything other than view templates and any inline looping or conditionals of that view code.

In our next post we'll discuss the remaining scopes. These include some of the more tricky scopes used within CFCs and Custom Tags, as well as a few others.

This article is the eleventh in a series of articles on bringing life back to your legacy ColdFusion applications. Follow along in the Legacy Code category.

Previous Entries / More Entries