CFML 101 - Rookie Mistakes Part 1

{ Posted By : Eric Cobb on December 6, 2009 }
1411 Views
Related Categories: CFML, CFML 101

This is the first in what I hope to be a continuing series of CFML 101 articles. My intent is to produce a blog series aimed at the beginning CFML developer, one which helps to explain basic techniques and concepts to those new to the CF world. The topics and examples covered in this series focus on the CFML programming language in general, not a specific application server. So whether you're using ColdFusion, Railo, or Blue Dragon (referred to as CF/R/BD from this point forward) to run your CFML applications, these concepts still apply.

The first post covers rookie mistakes that we've all done at one point or another. These are things that seasoned developers instinctively know to do, but beginners may not realize are better or more efficient. Much of this post is based loosely on Adobe's Coding Best Practices for ColdFusion Performance, with a few of my own personal favorites thrown in there.


1) Drop those pounds!

This is probably the most common rookie mistake out there, the over-use of pound signs ("#", "number sign", "hash symbol", "octothorp", etc...). This is always a tell-tale sign of a n00b CFML developer. Not that there's anything terribly wrong with it, I had been coding this way for about 2 years before I realized that you shouldn't do it. For most beginning developers this an easy one to miss, because your code seems to be running fine and you don't realize that it actually negatively affects performance.

Here are a few examples of the over-use of pound signs:

<cfset #foo# = "#bar()#"> *

<cfset foo = #trim(bar())#>

<cfif "#trim(myName)#" eq "Eric">

While the above examples will work fine, the following examples of the same code are simpler and more efficient:

<cfset foo = bar()> *

<cfset foo = trim(bar())>

<cfif trim(myName) eq "Eric">

One of the few times you need pound signs inside of a CFML tag itself is for a tag's attribute. Here are some examples of when you would use pound signs inside of a tag.

<cfparam name="foo" default="#bar()#">

<cfhttp path="#myPath#">

<cfquery datasource="#DSN#">

Please not that I am talking about the content inside of the tag itself, not the content between the opening and closing CFML tags.


2) Too many cfoutputs!

Another tell-tale sign of a n00b CFML developer is surrounding every variable with cfoutput tags. Take the following example:

<form>
    <input type="hidden" name="val1" value="<cfouput>#val1#</cfoutput>" />
    <input type="hidden" name="val2" value="<cfouput>#val2#</cfoutput>" />
    <input type="hidden" name="val3" value="<cfouput>#val3#</cfoutput>" />
    <input type="hidden" name="val4" value="<cfouput>#val4#</cfoutput>" />
</form>

While the above code will work fine it causes your CF/R/BD server to have to work harder, and let's face, no one likes to work harder than they have to. When your server has to work harder, it negatively affects performance. Using unnecessary cfoutput tags can be equated to turning your car on and off at every traffic light, stop sign, and intersection. There's no point in turning your "output" on and off constantly throughout your page. This example is much simpler and more efficient:

<form>
<cfoutput>
    <input type="hidden" name="val1" value="#val1#" />
    <input type="hidden" name="val2" value="#val2#" />
    <input type="hidden" name="val3" value="#val3#" />
    <input type="hidden" name="val4" value="#val4#" />
</cfoutput>
</form>

As a general rule, you should try to have as few cfoutput tags on your page as possible.


3) Whose variable is this?

You should always, always, always, always scope every variable in your CFML applications. Do it. Every time. Always. No Exceptions. Got it? ESPECIALLY in your CFCs. (For those that don't know, "scoping" a variable means providing a prefix that designates where the variable belongs, I.E. "form", "url", "request".)

The Adobe article mentioned above specifically states in its first item:
"You can improve performance by always qualifying your variables with the proper scope. Wherever possible use fully scoped variables. A variable that has a scope prefix will be evaluated quicker than an unscoped variable."

To elaborate on that, here is the order of precedence that is used to determine a variable's scope.

  1. Query Results
  2. Arguments
  3. Variables
  4. CGI variables
  5. File variables
  6. URL variables
  7. Form variables
  8. Cookie variables
  9. Client variables
What this means is, if you have an unscoped variable, every time you call that variable CF/R/BD will have to start at the top of that list and check each and every one of those scopes until it finds your variable.

For example, if you have the following set statement:

<cfset myName = "Eric">

Every time you reference the variable "myName" CF/R/BD will do the following:

  • I don't know where "myName" came from.
  • Is it in a Query? No.
  • Is it an Argument? No.
  • Is it in the Variables scope? Yep, found it.
  • Process the "variables.myName" variable.

So, that may not seem so bad to start with, CF/R/BD only had to check 3 places before it found where we put "myName". (for those that don't know, a variable created using a cfset tag automatically gets put in the "Variables" scope unless otherwise specified). But what if you referenced "myName" 10 time in your CMFL page? That's 30 checks. What if you have 10 other variables that you set the same way and they each get referenced 10 times? Yeah, the checks start to add up, don't they?

Now, what if you have a form that has an input box named "myName" in it, and when you submit the form you don't specify a scope in your form handler code? Now CF/R/BD has to do the following:

  • I don't know where "myName" came from.
  • Is it in a Query? No.
  • Is it an Argument? No.
  • Is it in the Variables scope? No.
  • Is it in the CGI scope? No.
  • Is it in the File scope? No.
  • Is it in the URL scope? No.
  • Is it in the Form scope? Yep, found it.
  • Process the "form.myName" variable.
That's 7 scope checks before a match is found. Now what if you've got 15 other form variables to process, and you haven't specified a scope for any of them. Again, it starts to add up.

So, yeah, scoping variables is important in CFML. You should do it. Every time. Always.


4) Your Evaluation isn't good!

Don't use the Evaluate() function. It's bad. It also has a negative impact on performance. I wish it would go away. I've been coding in CF since version 4.0, and I really can't recall a single time that I've ever used Evaluate(). Something about it just seems dirty to me. I think it's a cheat that keeps people from learning how to code CFML effectively.

According to Adobe, instead of using:

<cfset value=evaluate("form.field#i#")> *

You should use:

<cfset value=form["field#i#"]> *

Now, I've heard people claim that sometimes you have to use Evaluate() and there's no way around it, but I've yet to come across it. (Now that I've said that I'll probably have to use it tomorrow!). Since ColdFusion MX (which came out in 2003, I think?) all variables scopes can be treated as structures, which means that Evaluate() is pretty much useless, and really just hanging around for backwards compatibility anyway. Ditch it!


And, that's it for this episode. Be sure to tune in next time when we discuss such intriguing topics as, "Where's my Honey-do list?" and "Fun with Functions!"


* This code sample was copied from Adobe's "Coding Best Practices for ColdFusion Performance" article mentioned at the beginning of this post.

Comments
PH's Gravatar I think your approach is ridiculous to call other noobs, you have been one yourself, and you are still making mistakes.
# Posted By PH | 12/7/09 12:46 AM
Russ S.'s Gravatar Ohh the pound signs. I cannot believe they never stopped to ask, "Do I really need these pound signs?". I wouldn't hate rookie code so much if I didn't have to be the one to fix it.
# Posted By Russ S. | 12/7/09 1:34 AM
Gary F's Gravatar I like your evaluate() tip. Didn't realise it could be done without it. Been CF'ing for 13 years, so that tip isn't just for beginners although I am very pleased I don't fall into the other pits you mentioned. (I'd fire myself if I did!)
# Posted By Gary F | 12/7/09 6:20 AM
Eric Cobb's Gravatar @PH - I wasn't using n00b in a derogatory context, this is all just light-hearted fun.

@Russ - I hear ya. Even when I pull up some of my old code I think "Aw, man. Now I've got to go fix all of those."

@Gary - yeah, evaluate() is one of those that's easy to miss. Nothing in the livedocs says "there's a better way", even though Adobe recommends not using it.
# Posted By Eric Cobb | 12/7/09 7:49 AM
Paul S.'s Gravatar I have a possible use case for evaluate. maybe you can help me find an alternate solution. we store a formula in a database table that uses cold fusion variables. for example: (var1 * var2) / 3 the variable can change for each individual row in the table. I use evaluate on the for value. evaluate(query.formula) to return the result of the calculation. is there a better way to do something like this?
# Posted By Paul S. | 12/7/09 9:45 AM
Eric Cobb's Gravatar @Paul - That's interesting. So, you actually have the variable names stored in the database? Or do you store the actual values of the variables in the database? (I.E., does the database record actually look like "(var1 * var2)/3" or is it "(2 * 9)/3"?).
# Posted By Eric Cobb | 12/7/09 1:26 PM
Paul S.'s Gravatar the variable names.

since the formula can change depending on what we are trying to do.
but we use the same variables to calculate our result.

we use this for a dashboard application for showing the monthly status of a metric. trends can be upwards(greater than 90, within a range, or way off) or downwards (less than 10 percent, within a range or way off. and the calculation determines whether the trend is in the green, yellow or red. our need was to be able to change the trend ranges for each metric to be being charted.
# Posted By Paul S. | 12/7/09 3:38 PM
felixt's Gravatar Good post - I have seen (and maybe did some of them myself) those mistakes on some of the projects that I worked on.

I do use Evaluate quite a bit though - the only main reason for me using it, is to shorten my code. For example say you have 10 HTML input fields and you need to fill the field values from database. Rather than cutting and pasting 10 times and change the field name etc2 - I create a list of the field names and inside the loop I do Evaluate to get the corresponding value from the database to fill the fields value.

Not sure whether this is a good practice - but it does save me from mind numbing cut and paste.
# Posted By felixt | 12/8/09 7:50 AM
Daniel Garcia's Gravatar You can do the same thing using his example.

<cfset field_list = 'field1,field2,field3'>

<cfloop list="#variables.field_list#" index="x">
<cfset foo = qry_name["#x#"]>
</cfloop>
# Posted By Daniel Garcia | 12/8/09 12:59 PM
Eric Cobb's Gravatar @Paul - well, it looks like you've proven me wrong! I've spend some time trying to figure out how to handle your situation without using evaluate(), and for the life of me I can't find any way around it. It might be possible by tapping into CF's underlying Java capabilities, but even then it would probably be more code than it's worth.

So, it looks like you have actually found a valid use for evaluate()! ;^)
# Posted By Eric Cobb | 12/8/09 9:40 PM
Paul S.'s Gravatar wow. looks like my fame is now assured! :)

thanks, for thinking about possible alternatives to my solution.
# Posted By Paul S. | 12/9/09 9:49 AM
Eric Cobb's Gravatar @Paul - I decided to make this into another blog post, hopefully someone else out there has run across this and knows of a solution. You can view it here: http://www.cfgears.com/index.cfm/2009/12/10/A-vali...
# Posted By Eric Cobb | 12/10/09 1:30 PM
Aaron West's Gravatar Eric, this is a good idea for a blog series. So many bloggers focus on intermediate to advanced level ColdFusion topics; I think there's a strong market for beginning level content. Good on ya!
# Posted By Aaron West | 12/13/09 11:49 AM
Eric Cobb's Gravatar @Aaron - Thanks! That was my main reason for wanting to start this series. I just hope I can fill it with content that people find useful. ;-)
# Posted By Eric Cobb | 12/14/09 8:00 AM