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.

Legacy Code Part 10: Be Persistent

As I said in my last post, scoping all of your variables can be a huge performance improvement for your dated Legacy Code. By explicitly scoping each and every variable reference, within your application, you eliminate the overhead of the system having to ScopeCheck each reference to determine it's scope. Understanding usage of each scope is an important part of this process. In this post, we'll discuss the persistent scopes of an application.

SERVER
- This scope is valuable in environments where you have a dedicated server for your applications. Use carefully, and sparingly, this is a good place to put crafted objects and variables that can be shared across multiple applications in a shared server. Multi-Site One Codebase setups can get significant use of the SERVER scope, for housing things like utility objects that can be used by each application, without duplicating them in each app. The downside is, any change to a SERVER scoped object or variable will require a server restart to take effect. You can set these variables in onServerStart() method of the Server.cfc.
APPLICATION
- This scope is valuable for creating Application wide objects and variables, that can be used regardless of individual user sessions. This is typically a good place for utility objects (if they aren't in the SERVER scope), asset pathing references, logging objects, and more. Typically you initialize these variables in the onApplicationStart() method of your Application.cfc, and only change these variables when making application wide changes, realizing that those changes will affect all current users.
SESSION
- This scope is used for storing variables only used by a single user's browsing session. This is a good place for storing things like a user object, and shopping carts. Things that are only used for and by a single user, within their current visit to your application. You typically create these variables in the onSessionStart() method of your application's Application.cfc, and you can manipulate SESSION variables during a request, remembering that those changes will affect the remainder of the user's session.
REQUEST
- This scope is used for storing variables only used within the current page request. While a REQUEST variable is available to every template called during the course of a request, it is not best practice to directly access REQUEST variables inside of cfc's or custom tags, but rather to pass them in as a method argument or tag attribute, respectively, in order to maintain encapsulation. These variables are great for storing page specific details for use throughout the request, such as setting a page title, and using it at request end to log the page viewed by the user. Requests typically come in three parts: onRequestStart(), which occurs before the templates execute, onRequestEnd(), which occurs after the requested template executes, and either onRequest() or onRequestCFC(), which allow for some additional pre-template processing, but segment it according to what is being requested. To understand these last two a little further, onRequest() might be used to set a variable to tell the system to log the request on completion, whereas onRequestCFC might set the same variable to tell the system to not log the request (because you don't need to log direct CFC execution, maybe). These last two can be powerful, and confusing, so you might have to play with them a bit, if you want to use them at all. You use any, or all, of those methods within your application's Application.cfc.

SERVER, APPLICATION, SESSION, and REQUEST are ColdFusion's persistent scopes, allowing for the creation and use of variables that can be used across very defined measures of time. In our next post, we'll talk about how you should use the other scopes in CF.

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

Legacy Code Part 9: Effort of Scope

We've been discussing the upgrade of Legacy Code. For our purposes, this is outdated ColdFusion code, often written against long retired versions of the ColdFusion server, that is still running out in production today. Often a lot of time, money, and effort went into creating these applications, and they were great, which is why so many still exist today. Unfortunately, they also haven't been given the love and care they've really needed, over the years, and now they're bulky, sluggish, and full of security flaws. We've already discussed several first steps towards updating these outdated applications. These were all big steps, so now it's time to focus on the smaller tasks needed.

Every application requires general maintenance, bug fixes, adjustments, and improvements. Going forward, most of the changes you will make will come in the course of this type of work. You'll make changes as you write a new fix, add some field to a form, or make some layout adjustment. You can make small projects, to address each coming task incrementally and proactively, but some organizations just don't have the time or resources, especially if your's is a large application. So you pay off your code debt in small, digestable chunks, within the confines of ongoing work.

A great example of this is our next task: scoping all of your variables. It was not uncommon for developers to write code as they read it out of the CFWACK, and much of that sample code was largely unscoped. Obviously it still worked, as those applications are still around, but most every ColdFusion developer has run into variable bleedover (two variables of the same name interfering with each other) at one time or another.

With smaller applications the performance improvement, of scoping all of your variables, will not typically have a huge impact. On the other hand, for large, high traffic applications, you can see measurable improvement. When ColdFusion processes each request, and finds an unscoped variable, it runs a background method (ScopeCheck) to walk through a hierarchy of scopes to search for the variable being referenced. Now, imagine a lengthy (and popular) dynamic template with 30 or 40 unscoped variable references. Now imagine that same template getting several thousand concurrent requests. That's a lot of ScopeCheck going on!

By explicitly declaring each and every variable with it's scope prefix, you eliminate all of this background process from occurring. The server doesn't have to search through the scopes to "find" the variable in question, because you've told the server exactly where it's located.

In my next post we'll talk more about proper scoping, but to get started it's important to know that A) you need to, and B) that you scope every variable. Even those in the VARIABLES and LOCAL scopes should be prefixed. It will prevent the server from unnecessarily searching for the variables, and reduce overall code complexity, because a variable's scope will never again be in question.

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

Legacy Code Part 8: Protect Your App Now

There's been a lot of publicity, recently, about the loss of sensitive PII (Personally Identifiable Information) on the web, and legacy ColdFusion applications have been hit especially hard. Hopefully, by now, you've upgraded to the latest version of the server, but that isn't enough. You've got to start actively protecting your system. One area of this is code, specifically in protecting your database from form and url hacking. (Remember Little Bobby Tables?)

Just like everything else we've discussed about upgrading your Legacy Code, the rest of your progress is handled mostly in baby steps. With one, notable exception. You have to lock things down, and prevent these security breaches.

Some time ago, ColdFusion introduced the <cfqueryparam> tag, as a way of creating bind variables in your queries. Aside from providing sql type checking to each param, it creates some inherent security by converting these arguments in to bind variables, in the SQL request. This is a double bonus, in converting Legacy Code, as you get both the security, and performance enhancements, by using bind variables. (Use <cfprocparam> with the <cfstoredproc> tag, for making stored procedure calls.)

This can be one of the single most important things that you do, in securing your application from outside attack. Make a project today of converting every single query call, in your Legacy Code, to utilizing <cfqueryparam>. It might take you days, or even weeks, but it will be your very first line of defense. Don't just do those that are form inserts, or those that reference URL. Do all of them.

Now, there are other things that you can do to protect your app as well. Review the ColdFusion Lockdown Guide, and implement those changes relevant to your system. Run the FuseGuard Application Firewall, as an added layer of security. And, run your site through HackMyCF. The free report can give you some valuable insight on things you can do right now, and a paid subscription can give you even more information.

Don't forget: fix every query. Calling a stored proc from a <cfquery> tag? Convert it to <cfstoredproc>. Leave no stone unturned. And get in the habit of writing them this way going forward. Data breaches are bad for business, so don't become the next news article.

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

Legacy Code Part 7: How To Map Your App

So, in our last post we talked about Mapping Your App being your next step, but then a question came to me, "How?"

Well, that's a very valid question. When I took on this exercise, several years ago, with one very large (6000+ template) application, I began by making a basic flow diagram of the existing Application.cfm and OnRequestEnd.cfm. What this ultimately did was A) show me all of the small bits of process flow occurring in these templates, and B) gave me a true understanding of exactly what was happening when. This all allowed me to evaluate each of these small bits of functionality, and determine how they each translated into the new ColdFusion application framework, as it is laid out by Application.cfc.

You can typically break your application down into a few sets of events: Application Start and End, Session Start and End, and Request Start and End. On top of this you have a few edge case events you can cover, like if a request is made of a template that doesn't exist (onMissingTemplate), or it an error is thrown but not caught otherwise (onError).

OK, so saying all of that kinda makes sense. But, what does it mean from an application standpoint? Well, then you have to evaluate the variables you're creating and make sure that you're placing them in the proper persistent scope. You have a utility object that you use everywhere in your application? Then you put it into the Application scope during onApplicationStart. Have a single user object that you use to model each user during their visit? Then you put it into the Session scope during onSessionStart. Want to track each page request by logging specifics to your db? Set some variables at the beginning (onRequestStart), or during your request, then execute your sql inserts when the request is done (onRequestEnd).

You'll start with your initial flow diagrams, and then create some new ones with headings to match the new application framework of Application.cfc. Create a diagram titled "onApplicationStart", and bring in the corresponding flow bits from your other diagram. Move flows around until they're in the order necessary, and in their proper place in event execution flow. Once you moved all of the small sub-flows from the old to one of the new, then you have a roadmap for writing your new Application.cfc.

Need cheap software for making basic flow diagrams? I use the draw.io app from the Google Chrome Web Store.

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

Legacy Code Part 6: Map Your App

You've picked up some new hardware, setup a new local dev environment, and started learning the ins and outs of the modern web age. Your Legacy Code is getting more out of touch every day that goes by. Now what?

Let's get started. The first thing you need to do? Map your App. One of the best things to happen to ColdFusion (many, many moons ago) was the introduction of Applications.cfc. Application.cfc replaces Application.cfm and OnRequestEnd.cfm, allowing you a much finer level of control of your application flow. Here's where a solid understanding of how your application works is most important, as you now have the ability to truly target the creation (and destruction) of variables in different persistent scopes.

Remember when I said it was time to learn the latest ColdFusion? Well, this isn't really "new", but it might be new to you, or to this app. A solid understanding of what happens at each stage of process is important, as well as truly understanding proper scoping. I've already blogged about the different stages of application flow in my MSOC series, and you can download my scripted Application.cfc as a template.

Understanding how and when certain variables are added to your application will help you to identify where things might be sloppy or slow. By making your own diagram, you can write out how your app begins, then a session, then an actual request, and then those ends again. You begin to ask yourself "Does this really belong in the Session scope? Or would it be better served in the Application scope?" If your app is on it's own on a system, you may even decide that there are things you could place in the Server scope, and begin to explore using a Server.cfc for onServerStart().

Diagramming your application flow can be very enlightening, and liberating. You really begin to see where some of your app's inefficiencies lie, and how you can regain control. With such fine grained control, it's much easier to write in "reinit" functionality for "resetting" your application. You find that audit logging is much simpler (or just possible) when attaching to every request at onRequestEnd(). You begin to realize that you're hanging on to some data for much longer than you need to, or that you're requesting data entirely too frequently when you really only need it occasionally.

After you've completely diagrammed your application flow, you might begin writing your Application.cfc. Keep in mind that some of your findings may take hours, days, or even months to correct. Yes, that variable really needs to be in the Application scope, but that also means you have to change every reference to that variable across your entire application. Now might not be the time to do that yet. Chances are you will begin with writing your Application.cfc as a direct replacement for your Application.cfm and OnRequestEnd.cfm, and then gradually, over time, correct your past errors. You've got it all diagrammed out now, and having it in writing will assist you in your future patchwork.

What you're doing here is beginning to make a plan. Over time you are going to systematically refactor small pieces of code across an entire application. Migration to Application.cfc is the first of many steps, and probably one of the largest, overall. It's also one of your most important steps, as it really gives you a blueprint for the future.

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

Legacy Code Part 5: Crossroads

So, you're committed to bringing your legacy ColdFusion app into this century. You've been following along with these posts, and maybe even started to study some of the latest technologies. Now comes the big question. Are you sure?

Hopefully, you know your app. Is it big? Is it small? Are there a large number of sub-applications? I'm not gonna lie to you, there's a lot of work ahead. A lot of it is very tedious and repititive too. Right now, you are at a crossroads. (How fitting that you're here...) You've got a decision to make.

It's time to look at the ROI. How much time, money and effort do you already have in this application? You have to weight the pros and cons of your actions, in relation to the bigger picture. You have a couple of different directions that you can go from here.

You can just rewrite your app from the ground up. If your app isn't that big, this might be a really good opportunity to go ahead and start from scratch. You might decide, at this point, that you want to work on an entirely different tech stack. OK, I can see that there might be real, viable reasons to go that way. That said, I also know the true Rapid Application Development capable with ColdFusion, in the hands of a talented developer, so for me the reasoning to move to something else would have to be overwhelmingly compelling.

You can scrap your app, and replace it with a COTS alternative. This only works if there is a COTS alternative, and even then you have to find a way to handle data migration.

The final option is to refactor. This will typically be slow, requiring you to pick apart your applications, document process and workflow, and truly think about what's going on under the covers. There will be trial and error. Version control branching strategies will become critical. The big advantage here is, you have code, so you have a blueprint for how it was all supposed to work.

So know, going in to this decision, that if you choose this last option you will have a lot of work ahead of you. But, in the end, you should also end up with a well documented application, for which you will know every in-and-out.

So, time to decide. Are you up for the game? Or bowing out? If you're coming back to the table, in my next post we'll really start digging in on "how" to upgrade that legacy app.

This article is the fifth 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