Scripting a ColdFusion Application

With the release of ColdFusion 9 this past week, at MAX, we finally have full parity for cfscript with all of the cf tags. I personally prefer script when writing data access and business logic. For some it might not appear to be the sexiest feature, but I can see it making CFML much more appealing to developers from other languages.

[More]

Request vs Variables - Which is right?

Last week I stirred the pot a bit, stating that we've been improperly using the VARIABLES scope, and it's hurting our applications. Variables placed within the VARIABLES scope do not appear to have proper Garbage Collection performed on them when we're done with them, except in the case of the scope's usage within a CFC or a custom tag. This brought up some interesting discussion, where Ray Camden, Mike Brunt, and others chimed in.

I, with very good success, have been using REQUEST where most people use the VARIABLES scope. Wait! Hold on! You have to let me finish first before you get bent. What I said was that, in the past, we placed variables into the VARIABLES scope within our base request templates, with no way of clearing those variables at the end of the request (if using Application.cfc). My thought is, if VARIABLES have no true (apparent) mechanism for release, in context of variables scoped this way in a base request, then they don't really belong in the VARIABLES scope, but rather in the REQUEST scope.

This was met with some push back. The first argument was that this breaks encapsulation. I want to begin my response here by saying the first obvious thing that comes to mind: ColdFusion is not OO! Sure, your ColdFusion application can be written in an OO fashion, but ultimately it doesn't have to be. There are even some who seem that think that maybe it shouldn't be. All of that being said, I agree with OO principles, and think that proper encapsulation is very important when developing your applications, especially in terms of portability and reuse. Just because the REQUEST scope can be used directly within your custom tags or CFC's doesn't mean that you should. I would never suggest referencing the REQUEST scope directly within a CFC, with the exception of Application.cfc itself.

So another argument was that the REQUEST scope should only be used "when (and only when) the variable must be accessible to all the elements composing the request...", going further to state that the REQUEST scope should be avoided if at all possible. Why? The rest of the argument once again comes back to encapsulation. My point is to use the REQUEST scope within the context of a request, paying attention to maintain encapsulation. Within that context, doesn't it make sense to use the REQUEST scope for variables that should only exist for the length of a request?

The ColdFusion Jedi piped in to correct me on my timeline of scope introductions to ColdFusion, and we had some back and forth over declaration of scope to clearing of scope. I contended that onApplicationEnd() cleared the APPLICATION scope, that onSessiondEnd() cleared the SESSION scope, and that onRequestEnd() cleared the REQUEST scope. Ray reminded me that Application.cfc was about application process, and that the server handled when to 'clear' variables 'under the hood.' My point back was that something has to tell the server when to de-reference these variables, and that I had always assumed that was triggered by the execution of these methods. Mike Brunt chimed in on this, saying that the application must de-reference the variables prior to the server knowing it can perform Garbage Collection on them (Side Note: he didn't come out and agree with all of my conclusions here, only seeming to agree with the logic applied.)

Possibly the largest argument overall relates to whether the apparent memory leak, when using the VARIABLES scope within a base request, is really a leak or just a byproduct? I've theorized that the intention of the VARIABLES scope was that it was to be used only within CFC's and custom tags, where it does appear to properly get de-referenced. I put out there that the only reason you were able to use VARIABLES within the base request was because custom tags were created from .cfm files as well, so there really isn't any way to restrict it's usage. Ray says that the VARIABLES scope was introduced to provide access (like StructKeyExists()) to the unscoped variables out there in the wild.I think our thoughts of 'best practice' usage should follow these lines: Using the REQUEST scope within the base request, while maintaining encapsulation.

Ultimately, I just don't know. Maybe there's still an Adobe engineer out there who goes back that far, and can remember exactly what's what and why. I do know that, after migrating several high traffic applications to these guidelines I did get a higher return on application performance. I've gotten notes from others, after reading the original post, who have done similar changes to their systems with the same improvements. What other pluses or minuses do you, dear reader, think of when considering this practice of variable scoping? Is it right? Is it wrong? Is it a sin? What do you say?

(You can follow the original comment thread by referencing the post linked below)

Scope Usage and Application Scaling

Mike Brunt has posted an excellent article called Good Practices For Scaling ColdFusion Applications, in which he speaks about the importance of memory management within ColdFusion applications, and calls out certain avenues of scope usage that every CF developer should pay attention too.

Great post Mike! Another 'scope' issue that I've often seen (and abused myself) is the misuse of the VARIABLES scope. Back in the early days of CF, every example you saw showed an unscoped variable, placing it into the VARIABLES scope by default. This was fine, back then, as your view layers primarily consisted of Custom Tags. Use of the VARIABLES scope, within a custom tag, was permissable as those variables were then only available within that tag (or within a nested tag, if the nested tag used the CALLER scope). Once execution of the tag was completed, the memory space of those variables was cleared.

But, since custom tags were made from .cfm templates, there is no constraint within CFML from placing VARIABLES scoped variables within any .cfm template. This, in itself, is bad, as the VARIABLES scope (in the case of a base template, not a custom tag) is not properly cleared from memory space.

What I find people doing (and I've done it myself) is using the VARIABLES scope in place of the REQUEST scope. Memory allocated to REQUEST variables is properly recovered at the end of a request. Although variables in the VARIABLES scope are no longer available (except within a persistent CFC), their memory isn't properly released at the end of request execution. (For more information on this, see Jason Sheedy's post on the ColdFusion Memory Leak, and the accompanying comment thread and other referenced posts.)

A technique that some used, to get around this issue, was to have a StructClear(VARIABLES) statement as the last line of their onRequestEnd.cfm. This would explicitly clear out the VARIABLES scope at the end of a request. But, with the advent of Application.cfc, this no longer became an option (if you use Application.cfc.) If you tried to use that statement within the onRequestEnd() method of Application.cfc, you would only be clearing the VARIABLES scope of the CFC itself, and not the request.

That's actually a good pointer at the true underlying issue: proper scope usage. Use of the VARIABLES scope within a CFC makes variables within that scope only available directly by all methods of that CFC. Use of the VARIABLES scope within a custom tag makes variables within that scope only available within that tag (or a nested tag using the CALLER scope to access them.) Within a custom tag, you can not access variables of the calling template's VARIABLES scope, unless you use the CALLER scope to do so (which should only be in the case of a nested custom tag). You can, however, access REQUEST variables through out the request, from within a custom tag, an include file, or even within a CFC (though I wouldn't suggest doing that one.) By confining the usage of the VARIABLES scope to within custom tags and CFC's, and properly setting request level variables within the REQUEST scope, you could better manage your memory usage and application performance.

I've personally seen major differences in application performance, both through Mike's advice on persistent scope usage, as well as what I've outlined above. Unlike Jason Sheedy though, I'm not very familiar with Java profiling tools, so I'll have to leave it up to someone else to test all of this for the scientific proof. I only know that it appears my applications are running better as I migrate them to this paradigm. What are your thoughts?

*** Post Revision 080609: 2230 hrs *** More revision to my comments than the post itself, but Ray, the ColdFusion Jedi himself, corrected me. According to Ray, the VARIABLES scope wasn't added until CFMX, so my supposition on the 'intention' of the VARIABLES scope was incorrect. You really have to read the comment thread to see the fun we're having;) Hopefully we'll find an answer. Cutter

Guidelines: Code Readability - Pt1

At work I (with heavy input from the rest of the team) am writing these guidelines for our development practices, so that everyone is working 'on the same page.' I will share this series here for others who may want to know how some folks do it.

In everything there must be balance, two sides to every coin. A debate goes on about code "structure". To indent? Or not indent? One argument persists that unnecessary spaces/tabs within code increase the bandwidth used by our systems, serving up 'empty' content. The other argument is that this cost is minimal, in comparison to the time savings with relation to maintaining 'readable' code.

[More]

Watch What You Write, Someone Is Reading

Today I received the following comment here, on an older post on Variables and Naming Conventions:

...I wish Adobe would publish and adopt some kind of official naming convention. Sometimes reading sample code written in some other convention can make things harder to follow...
It was almost funny that this comment had come in when it had. Recently I was doing a lot of research for a User Group presentation I just did on the new ColdFusion 8 Ajax Components (have to re-record it before public release). In the process, I spent a great deal of time going over documentation all over the internet, from LiveDocs to countless blogs, absorbing the wealth of information that is already out there. It was outstanding that there were so many resources out there for people to learn from. On the other hand, it was a little sad that so much of the sample code was written in ways that can really start new developers off with some bad habits.

I'm not perfect, by any means, but I try to pay careful attention to the code that I place on this blog for readers to use and learn from. One thing that I attempt to do is pay attention to basic Web Standards, like using XHTML (the current standard) instead of HTML, keeping styles in the stylesheet, and having unobtrusive JavaScript. I don't always do it, sometimes it doesn't make sense for a quick example, but I try, especially within code downloads. I also try to adhere to my own Coding Guidelines, so that code appears to be consistent and easy to read and understand.

Probably the one that bothers me the most, and that I see most prevalent in blogs, documentation, and books, is the lack of proper variable scoping. I know that, often, we're just publishing quick examples, but this can be an extremely detrimental practice. I have worked on some very large enterprise applications, with years of code written by half-a-dozen different developers, most of whom learned their ColdFusion (and development) skills through the docs or a book. Many had actually come up with some very creative and effective algorithms to fix some issue, or create some new whiz bang feature, but their code was so poorly scoped that, after time, it could take down the server. Why? How? Enterprise sites may contain several hundred (or thousand) templates, containing dozens of variables on each page, and can potentially be hit by hundreds (or thousands) of users simultaneously. Multiply the number of variables by the number of pages by the number of users, then imagine ColdFusion doing a ScopeCheck on each one, to figure out which scope each variable requested belongs in. Even if the variable is in the VARIABLES scope, it's still that many times ScopeCheck will be called while rendering a page.

Still not convinced? Go download varScoper, and run it on your project root folder, including your subfolders, and see what it comes up with. Yeah, I'm still in shock. Cleanup on that is easier on a small subproject scale, but it's definitely forced me to think better when I'm writing my code, paying attention as I go, to minimize the performance impact of my applications, no matter how small it may be. I learned my bad habits from the docs, various books, sample code slung around on the CF-Talk list. I've continued to realize that there are better ways of doing things (like OOP and frameworks), and adjust my style and methods, and I think it's important to consider these 'best practices' when contributing. A little more code, but the right thing to do in the end, for you, your app, and your systems.

So, if you own a site of documentation, revise it. If you're writing a book, edit it. If you publish a CF blog, live it. The up-and-coming are reading us all of the time to find out how to use this wonderful language. Let's try to show 'em how to do it the right way. You might not follow any guidelines at all, within your development, but this scoping thing is way too important to gloss over, and will only help everyone in the long run.

Call For Input: Document Revision Comments

A little over a year ago we instituted a new policy within our dev team: placing a comment header at the top of every new (or revised) template. This comment header states what the template is, what it is used for, who originally created the file (if known) and a 'revision' listing. Every time a template is revised a notation was added to this header, with initials and date stamp, as to the purpose of the revision. This didn't replace line level comments to explain blocks of code, only augmented the process so that a total document change overview was available in an easy to review location.

[More]

Variables and Naming Conventions

At work I (with heavy input from the rest of the team) am writing these guidelines for our development practices, so that everyone is working 'on the same page.' I will share this series here for others who may want to know how some folks do it.

Variables. They define the data within our applications. Hard to peg down within our system, with thousands of variables over thousands of files. For this reason, it is time to define proper variable declaration.

Variable naming conventions and scoping can be very different in different programming languages. Within ColdFusion variables are case insensitive, whereas in most others proper case is critical. With the wide mix of languages used here (XHTML, CSS, ActionScript, JavaScript, etc.) we will take the stance that all variables, across all platforms, should remain case specific unless explicitly necessary to change. A camel case approach should be used, with the first letter of the first word (or one word) of a variable remaining lower case, while any subsequent word is capitalized. i.e.: oneVariable, anotherVariable, stillAnotherVariable. (Functions should capitalize each word) You may also employ Hungarian Notation to further identify the type of a variable, if you wish, but it won't (at this time) be required.

Another important action with variables is declaring, and referencing them, from their proper scope. In ColdFusion, you could reference most variables without identifying the scope, but to do so would cause unnecessary load on our systems. When a template is processed by ColdFusion, if the scope is not identified then the server will search through each scope separately until the variable is found. Not only does this cause the system to overwork, but you also run the risk of the system discovering a variable of the same name within a higher scope of the search tree. By expressly referencing all variables by their scope you eliminate these possible issues within our system. Also (within ColdFusion) all scope names should be listed in all uppercase. i.e.: FORM.strUserName, SESSION.intUserID, URL.intStartRow.

Flash

Although they've been used in the past, _global and _root scopes should only be used cautiously. As we integrate more of our tools into each other, these scopes can easily cause problems. Local Variables should be used in functions when possible.

Adobe has a detailed document on best practices on using scope in ActionScript.

Use variable/instance names that describe the functionality of the the item being named. Append an underscore then the ActionScript abbreviation for the type or variable or instance when appropriate. This will make code hinting available in the Flash IDE. For example, next_btn, or submitForm_lv

Use anonymous functions when appropriate, so as not to clutter the code with named trivial functions. Example:

view plain print about
1/*Not this way:*/
2function nextButtonPress(){
3 timeline.nextFrame();
4}
5next_btn.onRelease = nextButtonPress;
6
7/*Rather, this way:*/
8next_btn.onRelease = function(){
9 timeline.nextFrame();
10}

Database Architecture

Table Names

Table names should be camel case, but with the first letter capitalized as well. Table names should not be the pluralized form of what it stores. Example: ProductItemDetail

Linking or Lookup tables which serve as a relationship between a Many-to-Many should include the word Map in the name, preferrably at the end. Example: ProductItemCategoryMap

Column Data Types

  • boolean: Boolean values are stored in bit columns, and have historically been named bVerbWhatever, for example bIsCertified.
  • foreign keys: Foreign key column names should be fkTableName, for example fkProductItemDetail.
  • hex color: Hexadecimal colors are stored in char(6) fields.
  • All fields that store numeric data should be of datatype INT(4) except for very special circumstances.

SQL

SQL keywords should appear in ALL CAPS. Tables should be aliased. For example:

view plain print about
1SELECT        PID.displayName,
2                        PID.description
3FROM            ProductItemDetail PID WITH (NOLOCK)
4WHERE        PID.ID = #arguments.itemDetailID#

All Joins should be specified in the FROM clause. For Example:

view plain print about
1SELECT PI.Make, PICM.Price
2FROM ProductItem PI WITH(NOLOCK)
3INNER JOIN ProductItemCategoryMap PICM WITH(NOLOCK) ON PI.fkItem= PICM.fkItem

There are, always, exceptions to the rules. Typically these exceptions are due to the rules of another language. For instance, within XHTML all tag names, attributes, and attribute values are always lower case. The exception to that rule is anything calling a script function (like the event actions) where case is defined by the JavaScript itself (which is case sensative).

Examples:

view plain print about
1<!--- ColdFusion variables --->
2<cfset VARIABLES.strNextPage = "myNextPage.cfm" />
3<cfparam name="URL.intRowStart" default="1" />
4
5<cffunction name="GetNextPage" access="public" output="false" returntype="string">
6    <cfreturn VARIABLES.strNextPage />
7</cffunction>
8
9/*Flash variables*/
10
11selectedElements = {};
12
13propCount = function(obj){
14    var count = 0;
15    for (var i in obj){
16        count++;
17    }
18    return count;
19}
20
21delete_btn.onRelease = function(){
22    if (propCount(selectedElements) == 0){
23        this._parent.error_mc._visible = true;
24    } else {
25        this._parent.error_mc._visible = false;
26        deleteElements(selectedElements);
27    }
28}

Comments

At work I (with heavy input from the rest of the team) am writing these guidelines for our development practices, so that everyone is working 'on the same page.' I will share this series here for others who may want to know how some folks do it.

First and foremost is documentation. We have an extremely large system, currently made up of nearly 7,000 ColdFusion, XML, Javascript, Cascading Style Sheet, ActionScript, and Flash templates. The original authors of these templates were spread fairly thin, working a variety of tasks while attempting to produce a usable product base to build our company upon. Because of this a large majority of our system is completely un-documented. Now, as a matter of standard practice, every template touched by a developer is given, at minimum, a document header comment to create some form of initial documentation.

[More]