ColdFusion MX Coding Guidelines

Release 3.2 (4/14/2005)

Contents

These Coding Guidelines are structured as follows:

Introduction

This document provides guidelines for developing ColdFusion MX applications within Macromedia's Web Team. The rules and guidelines given here are intended to apply to CFMX 7 specifically and, to a lesser extent, CFMX 6.1. It is a living document, growing over time, incorporating feedback from Macromedia Web Team developers, as well as the larger ColdFusion community, as the guidelines are 'proved' in our live environment.

The first public release of this document (2.0) was made in Summer 2002. Since then, the Macromedia Web Team launched the all-new macromedia.com website, powered by ColdFusion MX, in early 2003 and that experience was factored into Release 3.0 as well as the changes in ColdFusion Components introduced by CFMX 6.1 in Summer 2003. Subsequent releases have incorporated public feedback and this release (3.2) incorporates changes introduced by CFMX 7 as well as more Macromedia Web Team feedback.

Although this document is published as-is for the ColdFusion community, Macromedia's Web Team own the document and decide what goes into it. You may, however, take a copy of this document and modify it as you see fit to create your own coding guidelines as long as you acknowledge this original document.

Conventions

The following conventions are used in this document:

[TBD: some comment in blue]
This indicates an issue which needs discussion and agreement within Macromedia Web Team.
Some comment crossed out in gray
This is a Macromedia-specific issue which can be ignored outside Macromedia. It is provided for the community as an example of how Macromedia Web Team deal with certain issues.

Base Document

These guidelines were originally based on the Spectra Team Coding Standards by Mike Andler and Tom Lane, 12/14/2000.

Style: Naming, Comments & Layout

This section provides guidelines on naming conventions (for files, tags, variables etc), comments and source code layout.

Naming

This section provides guidelines for naming various entities in your ColdFusion code.

General Naming Guidelines

All entities should be named for readability - names should be readable English words or phrases. The primary function or purpose of any entity should be obvious from its name. In general, "verb-noun" and "adjective-noun" phrases are the most natural choice, e.g.,:

course_list_output.cfm - invoked in a URL
calculate_sales_tax.cfm - a custom tag
ProductInformation.cfc - a ColdFusion component
userName, lastName, getBankBalance - a variable, function, attribute, property etc

The singular noun is preferred. In general, .cfm files will be lower case with words optionally separated by underscores and .cfc files will be MixedCase (also known as CamelCase).

Abbreviations

Abbreviations and acronyms should be avoided. Only a few, widely understood acronyms or abbreviations may be used, such as ID, CGI and URL. Such abbreviations and acronyms will be uppercase, unless they are part of a filename that forms part of a URL, in which case they will be lowercase, e.g.,

userID - variable, attribute, property etc
set_user_id.cfm - invoked in a URL

File Naming

Suffixes:

In general, follow our existing file naming conventions for files: all URL-accessible filenames shall be lowercase, with words optionally separated by underscores (determined by readability). Filenames must never contain spaces! Files whose names are not URL-accessible should generally be lowercase for consistency but we allow more leeway in this situation.

Note: Application.cfc, Application.cfm and OnRequestEnd.cfm are the only exceptions to the lowercase filename rule for URL-accessible files and must have exactly the case shown! The Mach II framework files are mixed case (and are not URL-accessible) - when referencing those files (as type names), you must use the same exact case as the filename.

ColdFusion Components

The component name shall be MixedCaseWords (preferred), lowercasewords or lowercase_words; all method names, property names and instance names (variables referring to components) shall be mixedCaseInitLower (also known as headlessCamelCase). Components that are URL-accessible, e.g., that implement Web Services, shall be lowercasewords or lowercase_words. All references to component names in code shall match exactly the case of the implementation filename, i.e., references will be path.to.MixedCaseWords, path.to.lowercasewords or path.to.lowercase_words as appropriate.

If a ColdFusion component contains methods that are accessible as Web Services or via Flash Remoting (i.e., the cffunction tag specifies access="remote"), then the component should be stored under {cfmxroot}/wwwroot/{applicationname}/ (and have lowercase filenames). Otherwise, ColdFusion components should be stored under {cfmxroot}/extensions/components/{applicationname}/.

The directory structure should reflect the logical grouping of the major elements of each application. All the application-specific components should live in application-specific sub-directories. All the utility and common reusable components should live in appropriately named library sub-directories, e.g., Macromedia Web Team has both lib and util sub-directories for these common components (although those names are somewhat arbitrary).

Custom Tags

Custom tag names will be lowercase_words. Their implementation filename should be lowercase_words.cfm, stored somewhere within the {cfmxroot}/extensions/customtags/ hierarchy (so custom tags cannot be invoked directly via a URL). They should be invoked using a tag prefix (defined using cfimport before the first use of any custom tags in each file - cfimport tags should be grouped together near the top of the file) e.g., <pfx:lowercase_words ...> ... </pfx:lowercase_words>. The pfx will usually be the lowest-level directory containing the tags, e.g., mmlf for {cfmxroot}/extensions/customtags/mmlf/ - used like:

<cfimport taglib="/customtags/mmlf" prefix="mmlf" />
...
<mmlf:ssi virtual="/path/to/file.html" />

The expectation is that directories under the Custom Tag Paths will have unique names - the tag prefix must be unique within a page.

Note: The ssi tag currently complains if you invoke it with a closing / but I think that's a bug that should be fixed!

Note: CFX tags will not be used - instead write Java tag libraries and <cfimport ...> them (assuming you can't write the tag in CFML for some reason).

Type Names

The names used to reference ColdFusion types (e.g., in type= and returntype= attributes) shall be lowercase for built-in types (e.g., boolean, string). The names used to reference user-defined types (i.e., ColdFusion Components) shall exactly match the case of the implementing filename, e.g., Article, NewsItem, MachII.framework.Listener.

Built-in CFML Tags, Attributes & Operators

Built-in CFML tags shall be lowercase, just like our HTML tags. Attributes for CFML tags shall either be lowercase (mirroring XHTML-compliance) or mixed case, first letter lowercase (mixedCaseInitLower) - this is a stylistic choice but be consistent. Built-in operators shall be mixed case, first letter lowercase, e.g., mixedCaseInitLower.

Note: This means simple built-in operators will be lowercase, e.g., is, and, or, not.

Attributes, Fields, Functions, Methods, Parameters, Properties & Variables

All these entity names will be mixedCaseInitLower. To enhance readability, boolean attributes and variables should generally begin with "is" or "has", e.g., <cfif hasFlash> ... </cfif>.

Function and method names should generally be of the form verb() or verbNoun(), e.g., read(), getName().

Attribute Values

All attribute values to all tags - except cfset, cfif and cfreturn - will be quoted, usually with double quotes ("). Single quotes (') may be used if the attribute value already contains a double quote.

In cfset, the attribute name is always a variable name (possibly evaluated, e.g., arr[i]) and the apparent attribute value is really an expression. In cfif and cfreturn, the 'attribute' is really an expression. String values in expressions will be quoted (with " or ' as appropriate). Numeric values in expressions will not be quoted. Variable names in expressions will not be quoted, so that pound signs (#) are not needed, i.e., variableName instead of "#variableName#". The attribute name in cfset - the variable name - will not be quoted.

Do not use evaluated variable names like "caller.#resultVariable#" or "varname_#index#" - use caller[resultVariable] or variables["varname_" & index] instead.

The only acceptable boolean attribute values are true and false - which may be quoted or unquoted (in cfset, they should always be unquoted).

Examples:

<!--- string requires quotes: --->
<cfset x = "A string" />

<!--- other expressions require no quotes: --->
<cfset y = len(x) />
<cfif z gt y * 2 >

<!--- simple variable requires no quotes: --->
<cfset request.value = z />

<!--- evaluated variable requires no quotes: --->
<cfset caller[result] = z />

Scope Names

Scope name qualifiers should be used with all variables (except var scope variables inside functions), where there is any possibility of a collision with a name in another scope. Since ColdFusion looks 'up' the scope chain if it cannot find a name in the current scope, variables scope should be used for safety, to avoid accidentally picking up the wrong variable in an outer scope, e.g., a cookie. See Creating and using variables in scopes on LiveDocs for more information about scope lookup.

Inside components, variables scope refers to non-public instance data (and this scope refers to public instance data). If you want a local variable in a function, you should use var and then set the variable to 'declare' it (at the top of the function). Within a script function, you introduce local variables as follows:

function foo() {
    var localVar = 0;
    var anotherLocalVar = 0;
    ...
}

Within cffunction, you can use either of the following styles:

<!--- using tag syntax for the function body: --->
<cffunction name="bar">
    <cfset var localVar = 0 />
    <cfset var anotherLocalVar = 0 />
    ...
</cffunction>

<!--- using script syntax for the function body: --->
<cffunction name="bar">
    <cfscript>
        var localVar = 0;
        var anotherLocalVar = 0;
        ...
    </cfscript>
</cffunction>

Inside components, there are two special scopes: this and variables. When variables are qualified with this scope, they become public data members of the component instance and accessible to code outside the component. When variables are qualified with variables scope, or left unqualified - using the unnamed scope, they become non-public data members of the component instance (and, therefore, are not accessible outside the component). This is important since unqualified variables within functions will persist for the lifetime of the instance - which may not be what you intended - hence the need to use var to declare local variables!

Example:

<cfcomponent>
    <cffunction name="example">
        <cfset var localVar = "Just in this function" />
        <cfset variables.nonPublicVar = "Non-public data member" />
        <cfset anotherNonPublicVar = "Not recommended - use 'variables'" />
        <cfset this.publicVar = "Public data member" />
    </cffunction>
    <cffunction name="more">
        <cfset var localVar = "Different to example localVar" />
        <cfset var x = variables.nonPublicVar & " set in 'example' above" />
    </cffunction>
</cfcomponent>

Note: this.member and member denote two distinct variables in distinct scopes (but don't do this: in general, name collisions are bad practice and cause debugging headaches!). variables.member and member denote the same variable (assuming member is not also declared with var) - always use variables.member for clarity.

Scope names should follow the same capitalization rules as variables:

Examples:

form.myFormField
URL.myURLVar - note: URL is an acronym (uppercase)
cfhttp.fileContents - note: cfhttp is a built-in tag name (lowercase)
variables.pageVar
arguments.argName
this.publicVar

Query Naming

Query names follow the same convention as other variable names, using the verbs Update, Insert, Delete, or Select as follows:

Query Type

Pattern

Example

Select Data

querynameSelect

customerSelect

Update Data

querynameUpdate

customerUpdate

Insert Data

querynameInsert

customerInsert

Delete Data

querynameDelete

customerDelete

Comments

This section provides guidelines on commenting your source code. In general, we should comment code to assist other developers work on it in the future. We do not want our comments to be visible to the public so we do not want to generate HTML comments from CFML - we use <!--- ... ---> in CFML which does not get published into the HTML. This means that for file types that can be accessed directly over the web, such as JavaScript include files, XML files and CSS style sheets, we should keep comments to a minimum - documentation for such files must be maintained separately, in the "projects" area of our internal site for example. Comments are there to be read - consider your audience!

General Guidelines

Write CFML style <!--- ... ---> comments, for all important entities, that describe what code does and why - document the how if it is not obvious.

When you make a change, comment it. Identify the change with the date and your user name:

<!--- 2001-11-26 scorfield Expanded the Comments section --->

When you want to leave a note about a bug to be fixed or functionality to be added, put TODO: in front of the actual comment so developers can easily search for them:

<!--- 2001-11-26 scorfield TODO: Incorporate everyone's feedback --->

Additional standard search keywords can be added after TODO: e.g., FIXME:, NOTE: - this is very important as it helps your audience, other developers. Furthermore, standard tags like this can be read by code editors such as Eclipse to create a "task list" whenever you're working on a file.

<!--- 2001-11-26 scorfield TODO: BUG: Fails on Fridays --->

File Comments

Each CFML file should begin with an CFML style <!--- ... ---> comment containing the filename and a standard copyright message followed by an explanation of the file and then, optionally, its modification history:

<!---
    $Id: news.cfm,v 1.7 2003/06/03 21:46:27 scorfield Exp $
    Copyright (c) 2002 Macromedia, Inc.

    Description:
        This page renders information about each product.
    Parameters:
        product - the name of the product family
    Usage:
        product_page.cfm?product="Flash"
    Documentation:
        http://sandbox.macromedia.com/wtg/projects/runtime/product_page.html
    Based on:
        /software/dreamweaver/index.html 1.74
--->

Note: We use $Id: $ so that CVS will insert the filename, version and last modified date and author.

The explanatory comment for the file should contain, roughly in decreasing order of importance:

Component Comments

The cfcomponent, cfproperty, cffunction and cfargument component tags all have displayName and hint attributes which should be completed for every component, every property, every method (function) and every argument. For cffunction, if the function throws any exceptions, the hint attribute should have "<br />Throws: document any exceptions that the function can throw" at the end of the hint.

Note: The displayName and hint 'comments' are in addition to the file comment described above.

Layout

This section provides guidelines on source code layout for ColdFusion (and HTML).

General File Format

Make sure you use Unix Linefeeds - see tool setup tips for information on making Dreamweaver, CF Studio, etc. behave properly. All indentation should be based on 4-space tabs - actual TAB characters are preferable to multiple SPACE characters to reduce file size and make editing easier.

General HTML Guidelines

Use Dreamweaver's validator tools to help you create clean, cross-browser XHTML-compliant HTML. All generated HTML should also pass tidy -errors with no errors, except that tables used purely for presentation do not need the "summary" attribute.

tidy is a free tool from Dave Raggett, one of the HTML people at the W3C. You can find it at http://tidy.sourceforge.net/. http://www.w3.org/People/Raggett/tidy/ says "Tidy is able to fix up a wide range of problems (in HTML documents) and to bring to your attention things that you need to work on yourself."

All generated HTML must pass Section 508 accessibility guidelines. See Accessibility / Section 508 Guidelines for more detail.

All generated HTML must specify a Content-Type, a Content-Language and a character set encoding (which should be UTF-8). See Globalization for more detail.

HTML & XHTML Compliance

All generated HTML should be XHTML-ready:

Generated HTML that is XHTML-compliant should begin with this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Some browsers interpret this as strict XHTML so you also need to add the following to the HTML tag:

<html xmlns="http://www.w3.org/1999/xhtml">

Do not put the above code in generated HTML that is not XHTML-compliant!

CFML & XHTML Compliance

ColdFusion source code cannot quite be written to be purely XHTML-compliant because of certain tags (cfif / cfelse, cfreturn, cfset) but you should make an effort to be as XHTML-compliant as possible. cfelse cannot have a closing tag so it cannot be XHTML-compliant; cfif and cfreturn do not have an attribute="value" syntax so they cannot be XHTML-compliant (but cfif has a closing /cfif tag and cfreturn can and should have a self-closing /); cfset does not in general follow the attribute="value" syntax and these guidelines recommend that for readability you do not quote the value in cfset - but cfset can and should have a self-closing /. This makes the source code more consistent (across CFML and HTML) and will also help you avoid subtle errors such as unterminated nested cfmodule calls.

If a simple custom tag invocation is written as XHTML-compliant, i.e., with a closing />, it will be executed twice as if it were a paired tag with an empty body. This can be surprising at first and cause subtle bugs if your code doesn't expect it! You can guard against this in simple custom tags by enclosing the code with:

<cfif thisTag.executionMode is "start">
    ...
</cfif>

Complex custom tags will probably already use thisTag.hasEndTag and have different code executed for thisTag.executionMode is "start" and thisTag.executionMode is "end".

All built-in CFML tags should be written as XHTML-compliant where possible (cfif, cfelse, cfset and cfreturn are notable exceptions).

Table Indentation

These are the guidelines for the layout of table source code (see also Accessibility / Section 508 Guidelines):

Example:

<table border="0" cellPadding="0" cellSpacing="0">
<tr>
    <td>
        Table data goes here
    </td>
    <td>Short text here</td>
    <td>
        <table>
        <tr>
            <td>
                Nested table data here
            </td>
        </tr>
        </table>
    </td>
</tr>
</table>

If whitespace is a problem (e.g., with very long / deeply nested tables), use your judgment to adjust the layout to improve the readability of the code. Given our use of CSS instead of tables for layout, this should be a rare occurrence!

Tag Layout

When more than one attribute is passed to a custom tag, each attribute should be placed on its own line and indented. The tag closing bracket (>) should be on a line by itself, indented the same as the matching opening bracket. This allows for long, descriptive names for both the custom tag and its attributes. For very short (single attribute) or relatively short but frequently repeated tags (e.g., cfparam), this is optional.

Examples:

<cf_my_custom_tag_two
    attributeOne="ValueOne"
    attributeTwo="ValueTwo"
    attributeN="ValueN"
/>
<cf_my_custom_tag
    attributeTwo="Value Two"
/>
<cf_my_custom_tag attributeOne="Value One" />
<cfparam name="myVar" default="x" type="boolean" />

HTML tags do not need to follow these rules, due to whitespace considerations.

ColdFusion Component Layout

ColdFusion components should follow the same general rules for layout as other tags.

Example:

<cfcomponent hint="..." displayName="...">

    <cffunction name="doSomething" returnType="string">
        <cfargument name="arg" type="string" />

        <cfset variables.thing = arguments.arg />
        <cfreturn arguments.arg />

    </cffunction>

</cfcomponent>

An acceptable alternative, using more vertical space, is as follows:

<cfcomponent hint="..." displayName="...">

    <cffunction
        name="doSomething"
        returnType="string"
    >
        <cfargument
            name="arg"
            type="string"
        />

        <cfset variables.thing = arguments.arg />
        <cfreturn arguments.arg />

    </cffunction>

</cfcomponent>

SQL/cfquery Indentation

The following examples will most effectively describe the preferred SQL indentation standards.

Example 1:


SELECT
    TO.COLUMN_ONE, 
    TT.COLUMN_TWO,
    TO.COLUMN_THREE
FROM
    TABLE_ONE TO,
    TABLE_TWO TT
WHERE
    TO.TABLE_ONE_ID = TT.TABLE_TWO_ID
    AND
    TT.TABLE_TWO_ID = 10
ORDER BY
    TO.TABLE_ONE_ORDER_KEY

Example 2 (Insert type A):


INSERT INTO 
    TABLE_ONE
(
    COLUMN_ONE,
    COLUMN_TWO,
    COLUMN_THREE
)
VALUES
(
    'ValueOne',
    'ValueTwo',
    'ValueThree'
)

Example 3 (Insert type B):


INSERT INTO TABLE_ONE
(
    COLUMN_ONE, COLUMN_TWO, COLUMN_THREE
)
VALUES
(
    'ValueOne', 'ValueTwo', 'ValueThree'
)

Example 4:


UPDATE TABLE_ONE 
SET 
    COLUMN_ONE = 'ValueOne', 
    COLUMN_ONE = 'ValueTwo' 
WHERE 
    TABLE_ONE_ID = 10 
     AND 
    COLUMN_THREE = 'ValueThree'

Structure: Application, Component, Tag etc

This section provides guidelines on how to structure your code and take advantage of the power of ColdFusion Components, to create well-designed, maintainable ColdFusion applications.

In general, MVC - Model-View-Controller - is a good, basic design pattern to use as a guideline for designing your application. It helps you focus on separating logic from presentation as well as refining the logic to separate the pure business model from the application workflow and logic.

Construct as much of the application logic as possible using CFCs so that you can take advantage of the encapsulation and type safety that they offer, as well as providing better options for reuse. Structure the CFCs to be as independent of each other as possible and as self-contained as possible (loose coupling and high coherence respectively). In particular, structure CFCs so that environmental awareness (e.g., use of shared scopes) is minimized, using design patterns such as Session Façade.

Mach II and Fusebox 4.1 are both well-designed frameworks for building MVC-based applications. See the Mach II Development Guide for more information about object-oriented design and best practices.

Basic Modularity

ColdFusion components, custom tags, user-defined functions, tag libraries and included files should be used if their usage will satisfy any of the following three conditions:

  1. Reusability
  2. Readability
  3. Organization

That means that all but the very simplest ColdFusion page should take advantage of CFCs and / or custom tags. Components should be used in preference to custom tags (for encapsulation and type safety reasons) although in certain situations, e.g., where part of a page has a natural start and end that needs to be managed as a single unit, custom tags can be more idiomatic.

A good example is the use of mmlf:renderpage (and mmlf:rnav) to wrap the body (and right navigation module) of a page and render it using standard header, footer and style sheets. Another good example of when it is natural to use a custom tag is the mmlf:ssi tag, used to perform 'server-side includes' of HTML fragments from the web servers. Both of these uses would be harder to achieve with CFCs and would be less intuitive to use.

If performance is critical or external integration requires it, Java classes may be used, or tag libraries with cfimport in preference to CFX tags.

File Structure

Each file should begin with an appropriate comment - see Style: Comments.

Component File Structure

CFCs should be structured as follows:

<!--- prolog comment --->
<cfcomponent ...>
    ...pseudo-constructor initialization (if any)...
    ...public methods (with init() first)...
    ...package methods (if any)...
    ...private methods...
</cfcomponent>

The use of pseudo-constructor initialization should be kept to a minimum and instead an init() method should be used to initialize the component - see Good Practice: Constructors. The public methods are the most important part of the component so they should be the first thing someone reads. The public methods should be followed by any access="package" methods and then any access="private" methods. Users of a component should not have to read as far as the private methods in order to figure out how to use your component - well-chosen names (and good comments) for the public methods should be sufficient.

.cfm File Structure

Even within a single file, separate logic from presentation as much as possible. If logic and presentation code cannot be physically separated (into different files), then try to structure files along the following lines:

<!--- prolog comment --->
<cfsilent>
...CFML logic...
</cfsilent>

<cfoutput>
...HTML generation...
</cfoutput>

Note: cfsilent suppresses all HTML output. This should not be a problem if logic and presentation code are properly separated. An Alternative is to use cfsetting as follows:

<cfsetting enablecfoutputonly="yes" />
<!--- prolog comment --->
...CFML logic...
 
<cfoutput>

...HTML generation...
</cfoutput>
<cfsetting enablecfoutputonly="no" />

Note: You should have both the yes and the no versions of the tag present and in the same file (to avoid creating hard-to-debug problems with unexpected output or missing output).

Directory Structure For Applications

All ColdFusion code should live in a directory tree outside the install area for ColdFusion MX / JRun. On most servers, the root for that directory tree is /data/www/appserver/cfmx/ and we'll refer to that as the {cfmxroot} below:

{cfmxroot}
    wwwroot/           » web-accessible .cfm pages and .cfc Web Services
    extensions/
        components/    » tree for .cfc files
        customtags/    » tree for .cfm custom tags
        includes/      » tree for include files
    config/            » tree for configuration files

This implies that we have two Custom Tag Paths set up in the CFMX Administrator:

{cfmxroot}/extensions/components/
{cfmxroot}/extensions/customtags/

We also have mappings for the root of the includes tree (for cfinclude) and the custom tags tree (for cfimport):

/cfinclude             » {cfmxroot}/extensions/includes/
/customtags            » {cfmxroot}/extensions/customtags/

For Mach II development, we also have a mapping for including the core file:

/MachII                » {cfmxroot}/extensions/components/MachII/

For Fusebox development, you could put the Fusebox core files (for 4.1) in a directory underneath the includes tree, such as:

{cfmxroot}/extensions/includes/fusebox4

and then have a mapping for including the core file:

/fusebox4              » {cfmxroot}/extensions/includes/fusebox4 

See Site-wide Variables for information about a /environment mapping.

The pieces of each logical application live in an application-specific directory in each of the trees above, e.g., code for the Exchange application lives in:

{cfmxroot}/wwwroot/exchange/
{cfmxroot}/extensions/components/exchange/
{cfmxroot}/extensions/customtags/exchange/
{cfmxroot}/extensions/includes/exchange/

Any Java libraries required should live in JRun's servers/lib/ directory (although, perhaps a little confusingly, in our build system we still have ant deploy to WEB-INF/lib/ as if it were part of CFMX and then the build system moves the files to the right place!).

URL Usage

URLs must not hardcode server names such as www-staging, www.macromedia.com, etc. These variables will be different on staging, QA, integration and production and should be handled using Site-wide Variables (in the next section).

URLs form the API to our web site. We have to live with them forever. Take the time to get them right, design your query string parameters carefully, be consistent, etc. Here are some preliminary specs.

Site-wide Variables

Some attributes within web applications depend on the server environment and will differ between development, staging, integration and production. The recommended approach for such attributes is to provide their values as request scope variables that are set as part of Application.cfm or Application.cfc. However, Application.cfm and Application.cfc should be deployable files that are independent of the server environment so the variables should be set in a server-specific include file (i.e., a file that has the same name but different content on every server). This way, Application.cfm and Application.cfc will be standard, deployable source files that are identical in each of the four environments while the included file, or database table contents, are considered part of the server configuration itself.

The server-specific include file will be called sitewideconstants.cfm and will exist in directories for development, staging, integration and production. The root Application.cfm will include the file as follows:

<cfinclude template="/environment/sitewideconstants.cfm" />

In each environment, /environment will be mapped to the appropriate directory, outside the document root. For the most part, this is the target config directory created automatically by the build system ({cfmxroot}/config/target/). Similarly, /cfinclude will be mapped to the include file root ({cfmxroot}/extensions/includes/). The build system automatically creates a serverspecific.cfm configuration file that contains:

The primary Application.cfm or Application.cfc file will also include that server-specific file, as follows:

<cfinclude template="/environment/serverspecific.cfm" />

The CVS source code control tree looks like this:

/source/
    docroot/                Web Server Document Root
        swf/                .swf
    java/                   Java Source Root
        com/
            macromedia/
                eai/        com.macromedia.eai package
                ...
        config/
            development/    Development configuration for Java apps
                application/
                            Specific configuration for application
            staging/
                application/
            integration/
                application/
            production/
                application/
    neo_root/               Application Server Root
        config/
            development/    Development
            staging/        Staging
            integration/    Integration
            production/     Production
            target/         Deployed directory (/environment)
        extensions/         Non-URL accessible CF files
            components/     ColdFusion Components
				MachII/		Mach II framework (/MachII)
            customtags/		Custom Tags (/customtags)
            includes/       Included Files (/cfinclude)
                fusebox4/   Fusebox 4 framewoek (/fusebox4)
        wwwroot/            .cfm Document Root

In addition to the source code tree shown above, the following directories will also exist in the repository, which is documented in full in the Dylan65 CVS Layout.

source/
    database/               DDL and other files
    docs/                   Engineering Document Tree
    infrastructure/         Non-Web Configuration (e.g., messaging)
    orientation/            Orientation Projects
    qa/                     QA (e.g., test harnesses)
    release_eng/            Release Engineering (e.g., scripts)
    scratch/                Scratchpad for anything!

The general assumption is that global include files of all sorts will live outside the document root, in appropriate directory structures, with suitable logical names for mappings.

Application.cfm / Application.cfc

There will be a root Application.cfm or Application.cfc file that provides all the site-wide core services such as application and session settings, site-wide constants, form / URL encoding machinery etc. Values will all be set in request scope rather than variables scope to ensure they are available inside custom tags etc.

If you use a root Application.cfm file, each "application" on the site will also have an Application.cfm file containing application-specific code that starts by including the root Application.cfm. Alternatively, each "application" on the site may have an Application.cfc file instead that includes the root Application.cfm file into onRequestStart().

If you use a root Application.cfc file, each "application" on the site may either have an independent Application.cfm file (containing all the appropriate definitions) or an Application.cfc file that extends the root Application CFC (but you'll need a mapping to reference the root file). Since Application.cfc is such a new feature, expect best practices around it to evolve over time.

Each "application" will also typically have an include file, applicationvariables.cfm, that defines the application-specific variables, again in request scope. This will also be included by the application-specific Application.cfm file (or by the onRequestStart() method of Application.cfc). The variables should be those that might be needed by other applications that need to take advantage of the services of this application, e.g., the membership application might define an include file with LDAP and data source settings, for use by the store and exchange applications.

The applicationvariables.cfm file belongs in:

{cfmxroot}/extensions/includes/{appname}/

/Application.cfm:

/{appname}/Application.cfm:

Exception Strategy

ColdFusion MX allows exceptions to have a pseudo-hierarchy by allowing cfcatch to specify a type= attribute that has a compound dot-separated name, like a component name, that will catch exceptions that have that type or a more specific type, e.g.,

<!--- catches feature.subfeature.item: --->
<cfcatch type="feature.subfeature.item"> .. </cfcatch>
<!--- catches feature.subfeature.{anything}: --->
<cfcatch type="feature.subfeature"> .. </cfcatch>
<!--- catches feature.{anything}: --->
<cfcatch type="feature"> .. </cfcatch>

Each 'application' (or feature) should define and publish its exception hierarchy. Most hierarchies will probably only have feature and item, e.g., Membership.NO_SUCH_ATTRIBUTE. The intent is that the feature.item (or feature.subfeature.item) type should entirely specify what exception has occurred.

Each application should throw fully-qualified exception types (feature.item or feature.subfeature.item) and a descriptive message that says - in English - which component / method threw the exception and a description of the problem, e.g.,

<cfset var msg = "MembershipAdminMgr.setAttributeName() :: " &
        "no attribute could be found with the given attribute name">
<cfthrow type="Membership.NO_SUCH_ATTRIBUTE" message="#msg#">

The code that invokes that application should catch the exceptions using fully-qualified types that it can handle, followed by feature.subfeature or feature for reporting more generic exceptions, e.g.,

<cfcatch type="Membership.NO_SUCH_ATTRIBUTE">
    <!--- handle missing attribute error --->
</cfcatch>
<cfcatch type="Membership">
    <!--- handle general membership failure --->
</cfcatch>
<cfcatch type="application">
    <!--- handle general application failure --->
</cfcatch>
...

Debugging

This section discusses some common debugging techniques.

Explicit Debugging Code

This involves adding specific code to an application to output additional information when a specific debugging mode is enabled. Typically such debug code would output to the HTML stream or write to a log file (using <cflog>). The debugging mode is typically enabled through a URL parameter. At Macromedia we have standardized on debug=yes as a URL parameter and we have a custom tag (getrequestsettings) that is called in the Application.cfm file to create a structure in request scope that includes debugging information (and locale, language etc). The custom tag ensures that debugging cannot be enabled in a production environment.

Debugging output within a page is structured as follows:

if ( request.settings.debug ) {
    // output debugging information
}

Do not use URL.debug directly.

Implicit Debugging

ColdFusion also has powerful built-in debugging features but there are some caveats to be aware of. If you use ColdFusion Components extensively, then you need to ensure that Report Execution Times is disabled in the ColdFusion Administrator since it adds a noticeable performance overhead. If you have the option of using localhost development, it's a good idea to restrict your debugging efforts to that environment rather than inflicting debugging on anyone else sharing your development server!

Shared Scopes, Sessions, Clustering & Locking

This section discusses the considerations behind use of shared scopes (application, server, session etc), how sessions are managed, how we use clustering and what to do about locking.

Clustering & Session Scope

We use hardware load balancing with sticky session between our web servers and our application servers. We use the underlying J2EE Session Variables mechanism (which uses an in-memory, browser-based cookie). We rely on session scope data in many of our applications, including storing CFC instances in session scope.

If a server drops and we lose session, that user will get switched automatically to a new server in the cluster and we will have to recreate their session data. This can impact two things:

  1. Authentication level (see below for more details),
  2. Session-specific data.

If a session is lost, "Level 2" membership applications will require users to verify their login credentials again at that point ("Level 1" membership applications will be unaffected - in terms of authentication - since the "Remember Me" cookie determines that level of authentication).

Session-specific data needs a little more care:

As a general guideline, use session scope sparingly.

Use of Shared Scopes

Do not use client scope. Client scope limits you to text data (so structured data needs to be WDDX-transcoded in and out of client scope); it relies on either persistent cookies or database storage - the former is intrusive for users (and doesn't work well for shared computers), the latter introduces a potential performance hit on every request (and we try to keep database access to a minimum).

You may use session scope for user-specific data but see the caveats and considerations above.

For data caching that is not user-specific, use server scope or application scope. For macromedia.com, we're the only application in town (because we need a single session - single sign-on - across all parts of macromedia.com), so we use server scope instead of application scope (server scope access is marginally faster than application scope).

Locking & Shared Scopes

When accessing and / or updating data in shared scopes, always consider the possibility of race conditions (i.e., where two concurrent requests could access and / or update the same data). If a race condition is possible and might affect the behavior of your code, you need to use cflock to control execution of the code around the shared resource.

If the shared resource is in server or application scope, you should use named locks to control access - and choose a name that uniquely identifies the resource being locked, e.g., use server_varname when locking an update to server.varname.

If the shared resource is in session scope, you should generally use a scoped lock on session itself.

In both cases, remember that you are only trying to prevent race conditions affecting your code: most read operations do not need to be locked; most write operations should be locked (unless the race condition is either unimportant or cannot affect the outcome).

Authentication Levels & Sessions

macromedia.com has three levels of authentication:

  1. guest
  2. known, unauthenticated ("remembered")
  3. known, authenticated

Machinery exists in the root Application.cfm that establishes which state the current session is in and creates a session.membership.user object that can be queried:

For more details, your can read the session authentication spec.

Good Practice

This section provides some hints and tips that are considered "good practice".

Booleans

Booleans are always true or false, conditions are also true or false - do not test a boolean expression against a value, just test the expression:

<cfif boolExpr is "true">     <!--- BAD! --->
<cfif boolExpr is "false">    <!--- BAD! --->

<cfif boolExpr>               <!--- good --->
<cfif not boolExpr>           <!--- good --->

On the other hand, don't rely on implicit conversions from numeric types to boolean. Functions like compareNoCase() and listFind() should be explicitly tested against zero for clarity instead of relying on the "0 is false" conversion:

<cfif compareNoCase(x,y)>           <!--- BAD! --->

<cfif compareNoCase(x,y) neq 0>     <!--- good --->

cfswitch/cfcase

Instead of cascading cfelseif blocks, when you are branching on the value of a single expression, use cfswitch and cfcase instead:

<!--- bad: --->
<cfif expr eq "Value A">
    ...
<cfelseif expr eq "Value B">
    ...
<cfelse>
    ...
</cfif>

<!--- good: --->
<cfswitch expression="expr">
    <cfcase value="Value A">
        ...
    <cfcase>
    <cfcase value="Value B">
        ...
    </cfcase>
    <cfdefaultcase>
        ...
    </cfdefaultcase>
</cfswitch>

Components & cfargument

ColdFusion MX does not require that you use cfargument tags but they provide validation (type safety) and act as additional documentation - always provide a cfargument tag for each named argument your function expects and follow these rules:

<cfargument name="badArg"        type="string" required="false" default="foo" />   <!--- BAD! --->
<cfargument name="veryBadArg"    type="string" required="true"  default="silly" /> <!--- BAD! --->

<cfargument name="iAmRequired"   type="string" required="true" />                  <!--- good --->
<cfargument name="iAmOptional"   type="string" required="false" />                 <!--- good --->
<cfargument name="iHaveADefault" type="string"                  default="foo" />   <!--- good ---> 

Components & cfproperty

Be aware that the cfproperty tag is of limited use - it does only two things:

  1. It provides additional type validation for Web Service return types.
  2. It provides a way to add metadata to components.

In general, cfproperty should not be used - it does not provide type checking for instance data (in general) and it does not provide default values for instance data so its presence can be misleading rather than helpful.

If you really are returning a component type from a Web Service and want the public data members of that component to be type-checked at runtime, then cfproperty can be useful.

If you are creating a metadata-driven system, then cfproperty can be useful (although dynamic systems driven by component metadata tend not to scale well!).

Components & Constructors

All components should define a method called init() that initializes the instance, even if the body of the method is empty, i.e., the initialization doesn't do anything. This makes usage of components consistent since you are guaranteed to be able to call init() on any component instance, just as you can for Java objects created within ColdFusion. The method should have a return type that matches the component and it should return this so that the following construct is always legal:

<cfset obj = createObject("component","util.lib.thing").init() />

This matches the way that createObject().init() behaves for Java objects - init() returns the fully initialized Java object.

The util.lib.thing CFC would have a method that looks like:

<cffunction name="init" access="public" returntype="thing">
    ...
    <cfreturn this />
</cffunction>

If your component extends another component, your init() method should begin with a call to super.init() to initialize the base component.

Note: There is a notable exception to this guideline - when you are extending components in Mach II (listeners, plugins, event filters), instead of defining a method called init(), you define a method called configure() (which does not return anything - configure() has returnType="void"). This is because the framework itself uses init() for its own initialization and provides configure(), which it automatically calls for you once the framework has been initialized, so that you do not have to worry about any initialization arguments that the framework requires.

Cookies

Persistent cookies are intrusive - use them sparingly. Note that by default CFID / CFTOKEN are persistent cookies which is one of the reasons why we enable J2EE Session Variables (in the ColdFusion Administrator): jsessionid is in-memory so it's not as intrusive and it goes away when the browser closes (along with the user session, so it is more secure than using persistent CFID / CFTOKEN cookies for session management).

If your application requires cookies in order to work correctly, such as for session management or login, then handle the situation where a user has cookies disabled and do it gracefully - tell the user they need cookies enabled.

Modifying every link and form in your application to append the appropriate tokens (jsessionid or CFID / CFTOKEN) by using URLSessionFormat() might be an option but that opens up the security risk of users sharing links and inadvertently sharing session data (this is not an option for macromedia.com because the security risks are too high).

Custom Tags

Custom tags should be organized into related groups by using a meaningful directory tree under the Custom Tag Path (defined in the ColdFusion Administrator). This makes it easier to use cfimport to access specific groups of custom tags.

All custom tags should anticipate being executed in both start mode and end mode, i.e., they should be structured as follows:

<cfif thisTag.executionMode is "start">
    ...
<cfelse> <!--- thisTag.executionMode is "end" --->
    ...
</cfif>

If the custom tag is a simple one, i.e., it doesn't process a tag body, then the cfelse section should be empty (and cfelse can be omitted). Do not put spurious complaints in the cfelse section about being called twice!

Do not hardcode a result variable in a custom tag, e.g., caller.result. Instead, use either a result= or a returnVariable= attribute and return results by setting the specified variable, i.e., caller[attributes.returnVariable]. This is more flexible and also reduces coupling between a custom tag and its calling page.

Database Conventions

This section provides guidelines on database table structure and naming.

General Database Naming Issues

  1. Table names should be singular (e.g., CUSTOMER_ADDRESS, ORDER_LINE_ITEM).
  2. Table names may be repeated (as prefixes) in column names only if doing so makes the column names more readable, e.g., CUSTOMER_ADDRESS_ID, ORDER_LINE_ITEM_ID, but in general should be avoided.
  3. Column names should be singular and descriptive (e.g., CUSTOMER_FIRST_NAME, PRODUCT_DESCRIPTION).
  4. Abbreviations should be avoided wherever possible (with the exception of the primary key abbreviation discussed in 7).
  5. Primary key column names should either be the table name followed by _ID or simply ID (or OID for "object ID") and should be the first column of a given table (e.g., CUSTOMER_ID, ORDER_ID). The corresponding constraint name should be the table name followed by _PK (e.g., CUSTOMER_PK, ORDER_PK).
  6. Foreign key column names should match their referenced column names (e.g., foreign customer key in ADDRESS table should be called CUSTOMER_ID, i.e., ADDRESS.CUSTOMER_ID identifies CUSTOMER.CUSTOMER_ID, CUSTOMER.ID or CUSTOMER.OID). The corresponding constraint names should be the table name followed by _FKn where n = 0..9 (e.g., ADDRESS_FK1, ADDRESS_FK2)
  7. Surrogate keys should be used only when there is some added benefit. In other words, many to many join tables do not need primary keys unless some value is added.
  8. Related columns should be grouped together (e.g., [FIRST_NAME, MIDDLE_NAME, LAST_NAME] - [PHONE_NUMBER, FAX_NUMBER, PAGER_NUMBER]).
  9. In general, all tables should contain DATE_CREATED and DATE_LAST_UPDATED columns.

Globalization

Make sure your code takes account of the Globalization Standards listed on the Web Team Internationalization page.

If your source file is UTF-8 (which it should be - DWMX lets you create UTF-8 source files!), then you should include a page processing directive near the top of each and every source file:

<cfprocessingdirective pageEncoding="utf-8" />

All generated HTML must specify a Content-Type, a Content-Language and a character set encoding (which should be UTF-8). See also Accessibility / Section 508 Guidelines.

This will be in the Application.cfm file along with setEncoding() calls for form and URL scope:

<!--- Set encoding to UTF-8. --->
<cfset setEncoding("URL", "UTF-8") />
<cfset setEncoding("Form", "UTF-8") />

<!--- Set the output encoding to UTF-8 --->
<cfcontent type="text/html; charset=UTF-8" /> <!--- Set basic URL values into request scope ---> <cf_getrequestsettings /> <cfheader name="Content-Language" value="#request.language#" />

Any references to URL encoded data needs to use:

#URLEncodedFormat(myvar, "UTF-8")#

Note: the locale will be determined dynamically by code in Application.cfm from a combination of the URL (which will usually include a Macromedia 'region' code) and the query string (which may specify a loc parameter). The general outline of that logic, in pseudo-code would be:

if loc is present in query string then
    request.locale = loc value
else if region is present in the URL then
    request.locale = default locale for that region
else
    request.locale = "en_US"
endif

The language can be derived from the locale mechanically:

<cfset request.language = replace(request.locale,"_","-") />

A 'short locale' would also be needed for content queries - the first two letters of the specified or deduced locale:

<cfset request.loc2 = left(request.locale, 2) />

Here are some examples of the deduction we would do:

URL loc Region request
locale loc2 language
/products/index.cfm n/a n/a en_US en en-US
/products/index.cfm?loc=es es n/a es_ES es es-ES
/products/index.cfm?loc=es_US es_US n/a es_US es es-US
/la/products/index.cfm n/a la es_ES es es-ES
/la/products/index.cfm?loc=pt_BR pt_BR la pt_BR pt pt-BR

Appendix: Performance Techniques

Do not optimize unless you know you have a performance problem! In general, readability is more important than performance.

The biggest performance optimizations come from architectural and algorithmic changes, e.g., caching. Poorly written database queries can kill a server - use a query analyzer to sanity check your SQL and take advantage of cfquery's caching functionality where appropriate.

Performance under load is often very different to 'straight-line' performance - a change that makes a loop run twice as fast when you're testing a single request may not have the same effect when a hundred users are hitting your site. Use load testing tools to identify bottlenecks and then think carefully about how to restructure the code to improve performance under load.

Having said all that, here are some code-level "do's" and "don'ts". These techniques are usually version-specific and most of these have been verified on CFMX. For the most part they are only important for very performance-sensitive code such as frequently called tags.

Performance "Do's"

The following are 'positive' recommendations, e.g., "Do xyz..." or "Do xyz instead of...".

Use compareNoCase() for comparing two strings

Use compareNoCase() or compare() instead of the is not operator to compare two items. They are significantly faster. Remember that these functions return 0 if the values match, so they correspond to is not.

Example: <cfif compareNoCase(x, "a") neq 0>
Not: <cfif x is not "a">

Note: This has been verified for CFMX.

Use listFindNoCase() for OR comparisons

Use listFindNoCase() or listFind() instead of the is and or operators to compare one item to multiple items. They are much much faster (order of magnitude for 5+ options).

Example: <cfif listFindNoCase("a,b,c", x) is not 0>
Not: <cfif x is "a" or x is "b" or x is "c">

Note: This has been verified for CFMX.

Use arrays instead of lists - in general

In CFMX, lists suffer from the generally slow string processing in Java which means that list manipulation can be slower than in CF5. In general, it is better to work with arrays of items instead of lists of items: listGetAt() is not an efficient way to work with individual items in a data set! However, see the list vs array caveat in the Don't section below.

Note: This has been verified for CFMX.

Use cfqueryparam to increase query performance

You can use cfqueryparam to optimize a query that looks something like this:

SELECT
    *
FROM
    TABLE_NAME
WHERE
    COLUMN = #variable#

If this query is executed repeatedly with different values for variable then using a SQL 'bind' variable will be faster. cfqueryparam creates these 'bind' variables:

SELECT
    *
FROM
    TABLE_NAME
WHERE
    COLUMN = <cfqueryparam cfsqltype="cf_sql_xxx" value="#variable#">

This allows the optimizer to compile the query once and reuse it every time the query is executed. It is also more secure since it prevents rogue SQL from being passed into a query (because it validates the type of the data).

Note: This has been verified for CFMX.

Use blockFactor to increase query performance

Adding blockFactor to a query can significantly improve performance. To add blockFactor, examine the data that is being returned. Determine the maximum size (in bytes) of each row. Take that size and determine how many times that number would divide into 32k. That number is your blockFactor, but be aware that the max blockFactor is 100. So, if for example you were getting 200 bytes per row, you could easily fit over 100 rows into the 32k buffer that CF 'grabs' at one time.

If you know at runtime that you will have less then 100 rows returned, for example you're writing a query that either returns 0 or 1 rows, do not bother adding the blockFactor attribute.

Note: This has been verified for CFMX.

Performance "Don'ts"

The following are 'negative' recommendations, e.g., "Don't do xyz...".

Don't use evaluate()

Avoid evaluate() unless there is no other way to write your code (and there is almost always another way to write your code).

Don't use iif()

Always use cfif/cfelse instead of iif(). It is significantly faster and more readable.

Don't use structFind()

Always use struct.key or struct[key] instead of structFind(struct, key). They are significantly faster and more readable.

Don't slavishly convert lists to arrays

Even though manipulating an array is generally faster than manipulating a list in CFMX, if you simply need to iterate over a list of items and process each one in turn the faster construct is <cfloop list="#itemList#" index="x"> ... </cfloop>. Don't convert itemList to an array and then loop over that - it's not worth it because it probably won't be faster.

Don't use cfmodule

It's slower than a CFC method invocation, it's slower and uglier than using a custom tag with a prefix, it's even slightly slower than a regular custom tag invocation. Better options exist: use a CFC (preferred), use cfimport and invoke a custom tag using a prefix (always preferable to invoking a custom tag via cfmodule), or even simply include a file.

Don't use incrementValue()

Always use x = x + 1 instead of x = incrementValue(x). It is more readable and slightly faster.

Note: In some situations where x + 1 is not legal, incrementValue(x) may be more readable than creating a temporary variable to hold x + 1 and then using the temporary variable.

Don't use WDDX for hardcoded data

It is always faster to cfinclude a CFML file that defines a datastructure than it is to deserialize a WDDX packet of that datastructure (somewhat faster if the packet is in memory, and significantly faster if the WDDX packet is read with cffile). Use this technique if the datastructure can be hardcoded (i.e., don't ship .wddx files, ship .cfm files). The Site-wide Variables technique is a good example of this.

Note: Complex or frequently changing configuration data is best implemented using an appropriately designed XML file.

Revision History

Date Author Comment

2/28/2005
-
4/14/2005

Sean A Corfield

Release 3.2: Updated to CFMX 7 and removed references to CFMX 6.0: Contents: changed WTG to Web Team; Style: corrected typo in Type Names section (Jonathan Snyder); expanded the intent of displayName and hint comment in components; Structure: corrected typo in Exception Strategy section (Jonathan Snyder); added suggestion for Fusebox core file setup; add Application.cfc recommendations and clarified some Application.cfm practices; Good Practice: clarified Booleans examples; clarified use of attributes in cfargument tag and added examples; corrected typo in Custom Tags section (Jonathan Snyder); rewrote Debugging section to clarify debug= attribute (Sean Corfield) and add some caveats about the built-in debugging (Jonathan Snyder); added recommendations about cookies (S Page); Database: no change; Globalization: fixed wording on internal internationalization link (Jonathan Snyder); Performance: minor typos and clarifications.

4/2/2004
-
12/25/2004

Sean A Corfield

Release 3.1: Added single-page, printable version (Brian Sisk); Contents: rationale for release 3.1; Style: preferred CamelCase CFC naming, corrected "noun-verb" to "verb-noun", replaced references to jEdit with Eclipse, removed reference to CVS modification history; Structure: added UDFs as modularization option (Rob Brooks-Bilson), added Fusebox as an alternative to Mach II for MVC applications; Good Practice: implicit conversion to boolean should be avoided (Matthew Ross), custom tag result variable attribute should match existing similar CFML attributes; Database: no change; Globalization: no change; Performance: fix typo in example (Philly Cooper); made examples match Good Practice guidelines.

2/16/2004

Sean A Corfield

Release 3.0.2: Changed all references to accessibility guidelines to use the official Macromedia Section 508 Guidelines.

10/12/2003
-
10/17/2003

Sean A Corfield

Release 3.0.2: Incorporated additional public comments: Contents: clarified ownership of document and what you can do with it (Matt Liotta); Style: relaxed many naming conventions, e.g., to allow mixed case component names and all-lowercase attribute names (general feedback); Structure: added additional mappings we now use (WTG); Good Practice: noted that chaining createObject().init() matches Java object constructor behavior (Matt Liotta); clarified use of configure() for Mach II code (WTG); Database: allowed simple ID column as primary key (WTG); clarified foreign key usage (WTG); Globalization: made examples comply with style guide (WTG); Performance: added note about XML configuration files to WDDX recommendation (WTG).

9/18/2003
-
10/8/2003

Sean A Corfield

Release 3.0.1: Incorporated initial public comments: Contents: no change; Style: clarified XHTML-compliance for cfif / cfelse, cfreturn and cfset (Robby L); clarified intent of multi-line custom tag invocation layout (Todd Rafferty); clarified lowercase component names (Scott Keene); Structure: no change; Good Practice: added guidance on cfargument usage (various posters on cfcdev); Database: no change; Globalization: no change; Performance: no change.

8/25/2003
-
9/17/2003

Sean A Corfield

Release 3.0: Contents: no change; Style: clarified "Type Names"; clarified many naming conventions and tightened up wording around scope name usage; clarified XHTML compliance requirements; clarified compound variable name usage; change custom tag invocation to require cfimport; corrected several grammatical errors (thanx S!); highlighted that Mach II is an exception to some of our naming conventions; Structure: rewrote introduction to emphasize design patterns and use of CFCs; added note on Mach II; added explicit CFC file structure guidelines; rewrote entire section on shared scopes and session management; Good Practice: added component constructors & caveat about Mach II configure(); added custom tag guidelines; added cfproperty guidelines; Database: no change; Globalization: no change; Performance: rewrote introduction; banned cfmodule.

8/24/2003

Sean A Corfield

Split the document into managable sections.

7/25/2003

Sean A Corfield

Started work on Release 3.0, bringing the guidelines up to date with Red Sky and incorporating feedback from WTG.

11/12/2002

Sean A Corfield

Added cffunction hint= guideline.

10/21/2002

Sean A Corfield

Added clarification about comment generation in non-CFML files; added guidelines for debugging code; removed len() / is performance recommendation as it is not true on CFMX; added some CFMX-specific performance recommendations; added caveat about $Log: $ causing merge problems; moved Revision History to bottom of document.

6/25/2002

Sean A Corfield

Release 2.0.4: Fixed OnRequestEnd.cfm case; clarified that cfif and cfreturn take an unquoted expression; clarified boolean literal values; clarified custom tag executionMode handling; relaxed rules for shared scope usage; added preference for components over custom tags.

6/19/2002

Sean A Corfield

Release 2.0.3: Removed bogus scope example (thanx S!) and clarified public / private / local scope mechanism inside components.

6/11/2002

Sean A Corfield

Release 2.0.2: Updated var rule for cffunction tags.

6/4/2002

Sean A Corfield

Release 2.0.1: Added applicationvariables.cfm to Application.cfm section; clarified Application.cfm is an exception to lowercase filename rule!

5/7/2002

Sean A Corfield

Release 2.0: Added DOCTYPE and XHTML notes; updated encoding handling (cfcontent, cfheader, cfprocessingdirective); added first cut of Application.cfm machinery; clarified variables / var scope usage; moved Accessibility Coding Guidelines to a separate document; added cfqueryparam.

5/6/2002

Sean A Corfield

Updated Neo to MX; adopted latest naming convention (due to case sensitivity issues); updated file system layout; fixed per-file comment to use CFML style; updated link to Flash Coding Guidelines.

1/28/2002

Sean A Corfield

Release 1.2: Updated CF include mappings.

1/23/2002

Sean A Corfield

Incorporated Josh King's comments about scopes; tidied up CVS structure.

1/17/2002

Sean A Corfield

Release 1.1: Incorporated new CVS structure; incorporated recent relocation of web components; removed web component namespace section (since it no longer requires a tag library) and changed syntax; added web component layout example; removed references to c:documentation.

12/07/2001

Sean A Corfield

Expanded directory structure and include mapping guidelines.

12/03/2001

Sean A Corfield

Added CFX / tag library recommendations.

11/21/2001

Sean A Corfield

Release 1.0.

11/20/2001

Sean A Corfield

Clarified database naming conventions based on feedback from Chris Tuft; updated Globalization section based on discussions with Glen Perkins.

11/13/2001

Sean A Corfield

Clarified environment for Site-wide Variables (based on Chad's feedback); clarified use of scope qualifiers; renamed all cookies to xxxCookie to minimize scope collisions; added initial component hierarchy guideline.

11/12/2001

Sean A Corfield

Added navigation skip in Accessibility guidelines; specified language and Globalization basics; clarified environment for Site-wide Variables; tidied up Session Management code (based on feedback from Matias); tidied up Accessibility (based on feedback from Bob Regan).

11/12/2001

Sean A Corfield

Draft 0.7: Released for review of Site-wide Variables and Accessibility guidelines.

11/10/2001

Sean A Corfield

Added the first cut of the Accessibility guidelines.

11/08/2001

Sean A Corfield

Chose the include file option as the solution for Site-wide Variables.

11/07/2001

Sean A Corfield

Reworked session management code to match membership needs and moved most of it to an Appendix.

11/04/2001

Sean A Corfield

Tidied up session management code (thanx Mike Nimer!); removed question about include file extension; pulled a couple of Performance Techniques into a new section of Good Practices (cfswitch, booleans).

11/02/2001

Sean A Corfield

Draft 0.6: Incorporated comments from Raymond Camden (clarified scope lookup; added note on len(trim(x)); removed comment about duplicate() bug; added note on incrementValue(x)) and Edwin Smith (added question about include file extension; removed some Performance Techniques that no longer apply to Neo: cfscript, cftry, cflock, struct-dot; added some Neo-specific techniques: use components for data acces, avoid evaluate()).

11/01/2001

Sean A Corfield

Incorporated Mike Nimer's comments (fixed cfset rules and clarified example; rewrote File Structure section; rewrote URL Usage section; added new section on Site-wide Variables; rewrote section on Scope, Session & Clustering; clarified that prefixing column names with table names should be avoided; removed "Don't use cfparam..." Performance Technique since it contradicts Ben Forta's recommendation).

10/31/2001

Sean A Corfield

Draft 0.5: Added fledgling Accessiblity section; moved Performance Techniques to an appendix; released for broader review.

10/29/2001

Sean A Corfield

Updated Performance Techniques based on Neo test data from Tim; changed include file naming; clarified numeric value usage in cfset; changed query naming; changed database table names to singular.

10/26/2001

Sean A Corfield

Draft 0.4: The consolidation in Draft 0.3 provoked a suitable resolution whereby mixedCase is used for everything except actual .cfm files invoked in URLs; dropped the Capitalization & Quoting table (redundant); dropped Pounds Signs & Quotes (redundant); clarified quoting rules for cfset; expanded section on Comments (based on feedback from S); indentation now mandates tabs, not spaces.

10/24/2001

Sean A Corfield

Draft 0.3: Removed datatype prefixing; changed SQL guidelines to use ALL_UPPER_CASE naming; standardized booleans; made quoting integer attribute values non-optional; reinforced UTF-8 recommendation; added note about component hints; added Barry's comments about environment configuration; added Barry's recommendation on session scope in a clustered environment; removed '_' prefix rule for included files; consolidated much of the lowercase_words / mixedCase dichotomy - read the Naming section carefully to see what I did!

10/23/2001

Sean A Corfield

Draft 0.2: Restructured to match basic J2EE Coding Guidelines document layout; added some CFML-applicable guidelines from that document; added thoughts on naming conventions; incorporated feedback from S; replaced 'template' with 'file / component'; added WTG Dynamic's HTML, URL and component guidelines.

10/23/2001

Sean A Corfield

Draft 0.1: Initial HTML version; tidied up Word formatting; corrected typos and grammar; added ToC, Revision History, Conventions, Base Document.

 

Send me an e-mail when comments are added to this page | Comment Report

Current page: http://livedocs.adobe.com/wtg/public/coding_standards/printable.html