 |

Top Ten ColdFusion Programming Tips
by Rob Brooks-Bilson
07/24/2001
As a member of Team Macromedia (formerly Team Allaire), I spend a lot of
time on the ColdFusion
Support Forum answering technical questions about programming in
ColdFusion. Here are ten programming tips derived from the most frequently
asked questions presented on the forum:
Know the rules for naming variables.
The golden rule concerning naming variables in your ColdFusion applications
is simple:
Variable names must begin with a letter and can contain only letters,
numbers, and the underscore character.
In addition to these two rules, there are several additional guidelines that
you should follow to minimize potential problems in your applications:
Variable names are not case sensitive. In the interest of good style and
readability, however, you should keep the case of your variable names
consistent.
Always try to use descriptive terms for your variables. It might seem
like a pain, but you will be grateful when it comes time to debug or add a new
feature later on down the road.
Avoid using variable names that may be reserved words in SQL. Words such
as Time, Date, and Order may cause errors when querying
databases.
Avoid using variable names that are the same as ColdFusion variable
scopes. Names such as Application, Attribute,
Caller, CGI, Client, Cookie, Form, Variable, Request, Server, Session,
URL, and Query.
Avoid choosing variable names that end in _date,
_eurodate, _float, _integer, _range,
_required, or _time. These are reserved suffixes for
server-side form validation variables and can cause naming conflicts.
Use ColdFusion variable names that match the corresponding fields in the
database. If your application interacts with a database, this makes your
code clearer.
Scope your variable.
ColdFusion supports a number of different variable scopes, where scope
refers to the context in which the variable exists within an application.
The scope encompasses where the variable came from (such as a form field, a
URL, etc.), how it can be used, and how long it persists. When you refer to
a variable in your code, you can refer to it using just the variable's
simple name (MyVar) or by its fully scoped name
(Scope.MyVar).
Visit web.oreilly.com for a
complete list of O'Reilly's books about Web and Internet technologies.
Because ColdFusion supports different variable scopes, the potential exists
for having like-named variables of different scopes within an application.
ColdFusion allows you to deal with this potential conflict in two ways.
One way to handle potential variable conflicts is to always provide the
variable scope when referencing a variable. For example, a URL variable
should be referenced as URL.MyVariable, while a form variable
should be referenced as Form.MyVariable. Using the variable scope
has two additional benefits. First, it makes your code more readable, by
identifying the variable scope right along with the variable. That way,
when you look through your code, you know in exactly what context a
particular variable is used. The second benefit has to do with performance.
When ColdFusion encounters a scoped variable, it is able to process the
code faster because it does not have to take time to determine the
variable's scope.
The second way to deal with potential variable conflicts is to let
ColdFusion handle them. When the ColdFusion server encounters an unscoped
variable, it attempts to evaluate it in a specific order. Because
application, server, session, attribute, caller, and request variables
must always be scoped, they are not included in the order of evaluation,
which is as follows:
- Local variables
- CGI variables
- File variables
- URL variables
- Form variables
- Cookie variables
- Client variables
As you might imagine, allowing ColdFusion to resolve potential conflicts
can lead to unexpected results. For example, you might refer to a variable
thinking that you are getting a URL variable, but ColdFusion resolves it to
a local variable that has the same name. Of course, you can avoid this
problem by choosing your variable names more carefully. But to make things
even clearer, I recommend that you always scope your variables.
Lock all reads/writes of application, session, and server
variables.
Because ColdFusion is a multithreaded application server, it is
possible for multiple threads to attempt to access the same variable at the
same time. For application, session, and server variables, this is an issue.
Because each of these persistent variable types is stored in the ColdFusion
server's RAM, the potential exists for the memory to become corrupted as
multiple threads attempt to access (read or write) the same variable
concurrently and end up colliding.
When a collision occurs, all sorts of problems can result. I've heard of
everything from users receiving other users' data, to server instability,
to crashing the ColdFusion application server. Because memory space is
involved, the results of a collision are, at best, unpredictable.
Fortunately, ColdFusion has a mechanism for managing concurrent access to
specific variables or chunks of code know as locking. Locking can be
broken down into two types, exclusive and read-only. Exclusive locking
means that ColdFusion single-threads access to a particular variable or
chunk of code:
<CFLOCK SCOPE="Session" TYPE="Exclusive"
TIMEOUT="30" THROWONTIMEOUT="Yes">
<CFSET Session.Username="pmoney">
<CFSET Session.AccessLevel=5>
</CFLOCK>
This means only one thread at a time is allowed to access code that has
been exclusively locked. Any other threads that attempt to access an
exclusively locked block of code are queued until the initial request
completes. Exclusive locks must be used (notice I say must, and not should)
when writing to application, session, and server variables. Because
exclusive locks single-thread concurrent requests, they have a negative
impact on performance. For this reason, it is important to use them
sparingly.
The other type of lock you can use is a read-only lock. When you place a
read-only lock around a particular piece of code, ColdFusion does not
automatically single-thread access to that code:
<CFLOCK SCOPE="Session" TYPE="ReadOnly"
TIMEOUT="30" THROWONTIMEOUT="Yes">
<CFOUTPUT>
Username: #Session.Username#<BR>
Access Level: #Session.AccessLevel#
</CFOUTPUT>
</CFLOCK>
What it does do is prevent an exclusive lock from being placed on the code
while it is being read from. In other words, if you have a read-only lock
placed around a chunk of code that reads a shared persistent variable,
multiple threads can read the variable's value, but a concurrent request to
write to the variable will not be processed until the read operations
complete. Conversely, if an exclusive lock is already in effect, a
read-only lock will wait until the exclusive lock is released before
proceeding. Because of this, read-only locks do not generally result in
degraded performance. Read-only locks should be used anytime you read data
from a shared persistent variable.
There is a lot more to locking than presented in this tip. Although I've
covered the basics here, a complete discussion can be found in my book
Programming ColdFusion (O'Reilly).
Alternate row colors in dynamically generated HTML tables.
On of the most frequently asked questions by those new to ColdFusion
development is how to alternate the row colors for dynamically generated
HTML tables. There are several ways to do this, however, the easiest is to
use the IIF() and DE() functions as shown in the
following example:
<CFQUERY NAME="GetEmployeeInfo"
DATASOURCE="ProgrammingCF">
SELECT Name, Title, Department,
Email, PhoneExt
FROM EmployeeDirectory
</CFQUERY>
<TABLE CELLPADDING="3" CELLSPACING="0">
<TR BGCOLOR="#888888">
<TH>Name</TH>
<TH>Title</TH>
<TH>Department</TH>
<TH>E-mail</TH>
<TH>Phone Extension</TH>
</TR>
<CFOUTPUT QUERY="GetEmployeeInfo">
<TR BGCOLOR="###IIF(GetEmployeeInfo.currentrow
MOD 2, DE('E6E6E6'), DE('C0C0C0'))#">
<TD>#Name#</TD>
<TD>#Title#</TD>
<TD>#Department#</TD>
<TD><A HREF="Mailto:#Email#">#Email#</A></TD>
<TD>#PhoneExt#</TD>
</TR>
</CFOUTPUT>
</TABLE>
The row color is alternated by using the IIF() and DE()
functions along with the MOD operator to determine whether or not
the row number for the current record being output is odd or even.
Depending on the outcome of the evaluation, one color or the other (in this
case, two shades of gray) is used as the background color for the current
row. Because hex color codes are supposed to begin with a pound sign (#),
we have to create an escape sequence before we call the IIF()
function. This is done by doubling up on the first pound sign.
Obtaining a list of form fields and their values.
One question I see posted over and over again in the
ColdFusion Support
Forum asks how to obtain a list of all form fields and their associated
values submitted by an HTML form using the POST method. This
technique is often used to work with dynamically created form fields, in
situations where you do not necessarily know the names of the form fields
being passed.
There are two ways to obtain a list of form field names and their
values:
The first method uses a special ColdFusion structure, named Form
(introduced in v4.5) that contains each form field name and its associated
value. To obtain a list of all form variables within the Form
structure, you could use code like this:
<TABLE>
<TR>
<TH>Variable Name</TH>
<TH>Value</TH>
</TR>
<!--- loop over the Form structure and output all
of the variable names and their associated
values --->
<CFLOOP COLLECTION="#Form#" ITEM="VarName">
<CFOUTPUT>
<TR>
<TD>#VarName#</TD>
<TD>#Form[VarName]#</TD>
</TR>
</CFOUTPUT>
</CFLOOP>
</TABLE>
The code uses a collection loop to loop over the Form structure. Each
variable name and its associated value are output in an HTML table.
The second method for obtaining a list of every form variable passed to a
template involves a special form variable called Form.FieldNames.
This variable is automatically available to any ColdFusion template and
contains a comma-delimited list of form field names that have been posted
to the current template.
<CFOUTPUT>
<B>Field Names:</B> #Form.FieldNames#
<P>
<B>Field Values:</B><BR>
<CFLOOP INDEX="TheField" list="#Form.FieldNames#">
#TheField# = #Evaluate(TheField)#<BR>
</CFLOOP>
</CFOUTPUT>
In this example, the list of field names is output on a single line. Next,
a list loop is used to loop over the list of field names and output each
one along with its associated value. The value for each form field is
obtained using the Evaluate() function. Note that the special
validation form fields (i.e., ones that have names that end with
_date, _time, etc.) are not present in the
Form.FieldNames variable. They are, however, present in the
Form structure we discussed in the first method.
Avoid redirection with CFLOCATION when using cookies.
Due to the way ColdFusion assembles dynamic pages, you should not attempt
to use the CFLOCATION tag within a template after a cookie
variable has been set. Setting a cookie variable and using CFLOCATION
afterward results in the cookie not being set. If you need to redirect to a
different template after setting a cookie, consider using the
CFHEADER tag instead, as in:
<CFCOOKIE NAME="MyCookie" VALUE="Hey, look at
me!">
<CFHEADER NAME="Refresh" VALUE="0;
URL=http://www.example.com/mytemplate.cfm">
The CFHEADER tag generates a custom HTTP header with a Refresh element that
contains the number of seconds to wait before refreshing the page as well as
the URL of the page to retrieve when the refresh occurs.
Use stored procedures for database queries whenever possible.
Most enterprise level databases (MS SQL Server, DB2, Oracle, Informix,
Sybase) support creating special programs within the database called
stored procedures.
Stored procedures allow you to encapsulate SQL and other database-specific
functions in a wrapper that can be called from external applications. There
are several reasons why you should use stored procedures whenever possible
in your applications:
Stored procedures execute faster than identical code passed using the
CFQUERY tag because they are precompiled on the database
server.
Stored procedures support code reuse. A single procedure only needs to
be created once and can be accessed by any number of templates--even different
applications and those written in other languages.
Stored procedures allow you to encapsulate complex database manipulation
routines--often utilizing database specific functions.
Security is enhanced by keeping all database operations encapsulated
within the stored procedure. Because ColdFusion only passes parameters to the
stored procedure, there is no way to execute arbitrary SQL commands.
Many enterprise level databases support the return of more than one
record set through stored procedures. This simply isn't possible using the
CFQUERY tag.
Avoid assigning user-defined functions (UDFs) to persistent variable
scopes.
The code for user-defined functions can be written inline, at the beginning
of a template, or more commonly, contained in a separate file that is
included at the beginning of the template via the CFINCLUDE tag.
Advanced developers new to UDFs may be tempted to assign frequently used
functions to one of the persistent scopes (Application,
Session and Server scope) in an attempt to improve
performance. Although this sounds tempting, it should be avoided.
The first problem with this technique has to do with locking. Because reads
and writes to persistent variables must always be locked, any time you want
to reference a UDF in your code, you'll need to include two extra lines of
code to lock the variable. This can get to be a real pain with frequently
used functions.
The second reason to avoid this technique is that it wastes RAM. Each
function you store in a persisitent variable
takes RAM that could probably be put to better use elsewhere in your
application. The Server scope is a particularly bad place to put
UDFs as Server variables persist until the ColdFusion Application
Server is rebooted.
It makes much more sense to keep all of your frequently used UDFs in a
single "function library" template that can be included via CFINCLUDE
only in the templates where the functions are needed. If you find you use
functions from your library throughout your application, you have the
option of placing a single CFINCLUDE in your Application.cfm
template. The minor overhead of having to include the function library
template easily offsets the inconvenience of locking all function calls and
wasted server resources of storing the function in a memory resident
variable.
Detecting WAP- and WML-enabled devices.
ColdFusion is increasingly being used to deliver content to WAP (Wireless
Application Protocol) enabled devices such as cell phones and PDAs. One
question I'm frequently asked is how to detect when a request to the server
is made by a WAP- and WML- (Wireless Markup Language) enabled device, so
that WML content can be delivered to the user instead of HTML. The answer
is to use the CGI variable HTTP_ACCEPT to see if the user's
browser is capable of receiving content with the MIME type
text/vnd.wap.wml. The following code should be placed at the top of
any page you want the check to occur on:
<!--- if the user is using a WAP enabled device,
send them to the WAP version of the
site. --->
<CFIF CGI.HTTP_ACCEPT CONTAINS "text/vnd.wap.wml">
<CFLOCATION URL="/wap/index.cfm">
</CFIF>
If the user's browser does accept the MIME type, we know the user is coming
to the site with a WAP- and WML-enabled device, and he or she is rerouted
to an appropriate page that generates WML content.
Take advantage of the Verity K2 server in ColdFusion 5.0.
Since version 2.0, ColdFusion has included advanced indexing and searching
capabilities using a bundled version of Verity's popular search technology
via the VDK (Verity Developer's Kit). In addition to the VDK,
ColdFusion 5.0 comes with a restricted version of Verity's enterprise level
K2 server. K2 server offers features that appeal to clustered and
large-scale sites, such as simultaneous searching of distributed
collections, concurrent queries, and an overall performance gain over the
VDK engine. Setting up and administering the K2 server takes a bit of work,
but is well worth the results. For more information, consult the Advanced
ColdFusion Administration book that comes with the official ColdFusion
documentation.
Rob Brooks-Bilson is the Web technology manager at Amkor Technology, where he
has worked since 1996. Rob's involvement with ColdFusion goes all the way
back to version 1.5 and includes several large-scale projects, the creation
of numerous open source custom tags, and more recently, the open source
Common Function Library
Project, where he coordinates several libraries of freely available
functions. Rob is a member of Team Macromedia (formerly Team Allaire) and
is a frequent speaker at ColdFusion user groups and conferences. Rob also
has his CF certification as a Macromedia Certified ColdFusion 5.0
Developer. He has written several articles on ColdFusion for Intranet
Design Magazine, CF Advisor, and CNET's
Builder.com.
O'Reilly & Associates will soon release (August 2001) Programming ColdFusion.

|
 |
Sponsored by:
|