ColdFusion ?Best Practices?
Before we delve into these so-called ?Best Practices??I need to issue a caveat.
?Best Practices? are a relative term, at best.
What I might consider a best practice, others might not. Some think that writing
highly, highly optimized code is a best practice. However, this often results in
code that is less readable. Some think that maintaining readable code is a best
practice (makes it easier for you and whoever else may follow you to work with
and debug).
So with that in mind?I should point out that these are *my* best practices.
Others may disagree. That?s fine. The beauty of programming is there?s never
just one way to get from point A to point B. Some prefer a direct route. Some
prefer a scenic route.
A) Scope your variables
What is a scope? Well, ColdFusion has quite a few. There?s the form scope. The
URL scope. Application, session, client, CGI, server, query, caller, cookie, and
more.
Think of each scope as a dresser drawer (trust me on this). One hold the form
variables?one holds URL variables?one holds form variables, and so on.
Now, let?s say you do: <cfoutput>#URL.firstName#</cfoutput>.
ColdFusion knows exactly what to do. It goes to the URL drawer and pulls out the
variable firstName.
Is the prefix URL. Mandatory? No. You can do <cfoutput>#firstName#</cfoutput>,
and it?s just as legitimate. However, notice what happens. ColdFusion is
standing in front of a dresser looking for a specific variable (firstName). It
has no idea what drawer to look in. So it has to hunt through the drawers until
it finds the appropriate variable.
Obviously, it?s going to take longer to find that variable without knowing which
drawer to check. Do this a few hundred times in your Web application?with a few
hundred users on your site?and you can see where that time difference can start
to become significant.
Now that you know why you should scope your variables, learn a little bit more
about the scopes themselves. This
Macromedia Live Doc will teach you a great deal.
B) Use Boolean evaluation
Have you ever needed to check to see if a form field is empty? The most
straightforward way is:
<cfif form.firstName IS ??>
It simply checks to see if the specified form field is an empty string (??).
Another way of writing the same thing would be:
<cfif len(form.firstName) EQ 0>
This checks to see if the length of the form field value is 0 (empty string).
This second method can be shortened a little bit?
<cfif len(form.firstName)>
Assume that form.firstName is empty. This would then become <cfif 0>. In boolean
evaluation, 0 is false. Assuming the value was not empty (let?s say it?s ?charlie?),
it would become <cfif 7>. A non-zero number evaluates to true.
<cfif form.firstName IS ??>
<-- equals --> <cfif len(form.firstName)>
This is a classic example of where a ?best practice? becomes subjective. I
personally prefer the Boolean evaluation (on the right), for it?s performance
increase. Others prefer the method on the left, as it?s much more intuitive to
read, which makes maintaining your code easier.
Either way is acceptable. It?s a matter of preference.
Another example of using Boolean evaluation can be demonstrated in trying to
determine if a particular query returned any records. Traditionally, one would
write:
<cfif queryName.recordCount EQ 0>
Using Boolean evaluation, we can write:
<cfif NOT queryName.recordCount>
<cfif queryName.recordCount EQ 0> <-- equals
--> <cfif NOT queryName.recordCount>
C) Learning to debug
Okay?not necessarily a ?best practice??but a very necessary skill if you want to
be a good programmer.
With the advent of CF 5.0, and continuing in MX, debugging became much easier
with the introduction of the <cfdump> tag. Want to
know exactly what your query returned? <cfdump var=?#myQueryName#?>.
Want to know what?s in that array? <cfdump var=?#myArray#?>.
Previously, to ?see? the contents of an array or structure, you?d have to loop
(and for 2d arrays you?d have to do nested loops). <cfdump>
changes all that. It?s an invaluable tool that I?ve seen too many people forget
about.
If you are getting unexpected results after a form submission, do
<cfdump var=?#form#?>
on the form?s action page, and you?ll see everything that was passed in
the form.
Another debugging technique would be turning debugging on in the ColdFusion
Administrator (assuming you have access). This will output all relevant (and
some irrelevant) variables and values at the bottom of the page. However, not
everybody has access to do this. Since the introduction of
<cfdump>, I?ve never had to resort to CF?s debug output option.
D) Using structure functions to your advantage
Just about all scopes in CFMX are stored in structures. If you are using session
variables, they are stored in a structure (don?t believe me? Try this:
<cfdump var=?#session#?>).
When you submit a form, those form variables are stored in a structure on the
action page. Again, a quick <cfdump var=?#form#?>
will demonstrate this.
(if you?re not familiar with structures, peruse my 3 part tutorial on complex
datatypes in ColdFusion, which teaches arrays and structures).
How to use this to your advantage?
Well, let?s say you have a form action page. You obviously don?t want people to
load that page directly?you want to make sure that they came from your form,
right? (right).
You could put the following code at the top of the page:
<cfif NOT isDefined(?form.firstName?)>
<cflocation URL=?myFormPage.cfm?>
</cfif>
This, of course, works just fine. But it would be a little bit quicker to check
the form structure for a specific key:
<cfif NOT structKeyExists(form, ?firstName?)>
<cflocation URL=?myFormPage.cfm?>
</cfif>
The isDefined() function must parse a string?which is relatively slow compared
to other operations. The second method does not require CF to do any parsing?it
simply checks a given structure (in this case, the form structure) for the
existence of a specific key (in this case, ?firstName?).
The two are functionally identical. Once again, it?s your choice as to which one
to use. While the second one is arguably faster (and how much faster is actually
debatable), the first one is probably easier to read and understand it?s
purpose.
E) Efficient use of <cfoutput> tags
Over the course of any given day, I generally help at least a handful of people
with coding problems. And all too often, I see something like:
<cfloop from=?1?
to=?100? index=?i?>
<cfoutput>
this is iteration #i#<br
/>
</cfoutput>
</cfloop>
This code won?t throw an error?so many people wouldn?t think there?s anything
wrong with it. However, it is quite inefficient.
Think of a <cfoutput> tag as starting a car.
Likewise, a </cfoutput> tag is similar to shutting
a car off. This analogy holds true because with every instance of
<cfoutput>, the CF Server leaps into action (red
tights and all). With every </cfoutput>, it stops.
Now look at the code snippet above again. The ?car? is going to start and stop
100 times. Would you knowingly do that to your car?
A much better way of writing the same code is:
<cfoutput>
<cfloop from=?1?
to=?100? index=?i?>
this is iteration #i#<br
/>
</cfloop>
</cfoutput>
Now the car is started once?the loop iterates as many times as necessary, and
the car is shut off.
F) Those darn pound signs
Ben Forta (Mr. ColdFusion himself) wrote
an article dealing with the overuse of pound signs. It?s that much of an issue.
Of course, the term ?issue? is relative. It?s not earth-shattering?but it
deserves to be mentioned.
Pound signs are most often used to output a variable?s value. For example:
<cfoutput>#myName#</cfoutput>
However, in setting that variable, you need not use pound signs.
<cfset myName = ?Charlie?>
is not only perfectly valid?but generally more acceptable than:
<cfset #myName# = ?Charlie?>
Too many people think every CF variable in every set, condition, loop, etc needs
to be enclosed in pound signs. The fact of the matter is that overuse of pound
signs could conceivably slow up your application?as well as making your code
less readable/manageable.
<cfif #myName# IS ?Charlie?>
Hi, Charlie
<cfelseif #myName# IS ?Pablo?>
Hi, Pablo
</cfif>
<cfif myName IS ?Charlie?>
Hi, Charlie
<cfelseif myName IS ?Pablo?>
Hi, Pablo
</cfif>
While both of these code blocks will function the same, the bottom one is
arguably more readable. Especially if you think about a particularly long page
of code. Reducing the pound sign usage can significantly ?clean up? the look of
your code.
Ben Forta is feared by men and worshipped by women for a reason. I don?t think
for a second that I can say it better than him, so I won?t even try. To hear it
straight from the horse?s mouth, see Ben?s article at
http://www.defusion.com/articles/index.cfm?ArticleID=26
Macromedia has also put out a page trying to clarify when to use pound signs and
when to leave them alone (see
Macromedia Live Doc)
G) Writing Better SQL
Two rules of thumb immediately come to mind in this area:
1) Avoid SELECT * when possible. If you know the columns that you need, specify
them. It may take longer to type, but your queries will execute faster and your
query objects will be smaller and easier to work with.
2) Use <cfqueryparam>. Not only will it
significantly speed up your queries, it will also add an additional level of
security to your database by preventing users from trying to force malicious
queries. <shameless_plug>http://tutorial138.easycfm.com/</shameless_plug>
<--
I should mention that use of <cfqueryparam> is NOT
one of those subjective best practices. It should always, always, always be
used. Always.
H) Write valid markup
This should probably be much higher on the list. But whether it?s CFML or HTML
or XHTML or XML, write valid code (with the latter two, there?s really no other
alternative).
HTML was, by its nature, very forgiving of bad code. However, the current
version of HTML will be the last. There will be no HTML 5.0. XHTML will replace
HTML as the base markup language of the Web.
In a nutshell, XHTML is nothing more than well-formed markup. What does this
mean to you? It means no incorrect nesting of tags (eg
<b><i>FOO</b></i>). It means all tags must
be closed (including <li>, which needs a
</li>, and <option>,
which need an </option>).
A full explanation/tutorial on XHTML is WAY beyond the scope of this tutorial.
However, getting into these good coding habits now will save you a world of
heartache when XHTML becomes ?the- standard (it currently *is* an accepted W3C
standard).
Valid markup also means a page that loads faster, and is more easily portable to
other platforms (such as wireless).
That should be enough for now. Again, I stress that these are not ?official?
best practices. They are endorsed by nobody but me. Obviously, I do prefer these
coding methods. Do I suggest that you spend time ?cleaning up? all of the
previous code you?ve written? No.
I do suggest that you get into good habits from here on in. That means writing
valid markup. That means using cfqueryparam. That means not overusing pound
signs. These are the more universally accepted of the concepts that I?ve
presented. The others are your choice.
As I?ve said, the beautiful thing about programming is that there is no one
right way to do any particular task (this can also be a very frustrating thing
about programming). My point is that if you disagree with my opinions of what
constitutes a ?best practice?, I?d like to hear about it. I?d like to know why.
Your ?best practice? that contradicts mine could very well be a better way to do
something, and I would welcome the opportunity to have another option available
to me.
This tutorial is also not meant to be an all-inclusive reference to best coding
practices. Certainly, there are many more techniques/subjects that I did not
cover here. Error handling techniques, for example, come to mind.
Let?s open up the EasyCFM forums
with some
discussion about this. I?d like to not only hear about whether or not you
agree or disagree with my programming ?styles??but I?d also like to hear yours.
What do you do that you think makes your code better/faster?
We all stand to benefit through the sharing of ideas. I?d love to hear yours.
CJ