Release 3.2 (4/14/2005)
These Coding Guidelines are structured as follows:
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.
The following conventions are used in this document:
These guidelines were originally based on the Spectra Team Coding Standards by Mike Andler and Tom Lane, 12/14/2000.
This section provides guidelines on naming conventions (for files, tags, variables etc), comments and source code layout.
This section provides guidelines for naming various entities in your ColdFusion code.
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 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
Suffixes:
.html
;.cfm
;.cfc
;.xml
. 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.
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 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).
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 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
.
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()
.
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 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 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 |
|
|
Update Data |
|
|
Insert Data |
|
|
Delete Data |
|
|
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!
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 --->
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:
Description:
of the file, including some
kind of classification for components and custom tags,
Attributes:
/ method or URL Parameters:
/ Result:
variables with brief descriptions,Dependencies:
, both outward (this file depends on other things)
and inward (things known to depend on, or use, this file - preferably with
URLs),Usage:
example,Documentation:
for this file,Based on:
),Basis
for:
).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.
displayName
(if the display name and the actual name are the same, you can omit displayName=
). hint
attribute. A good, readable style is to use first person narrative to describe things, e.g., a User
cfcomponent
tag might have hint="I represent a user who is browing the members-only part of the site"
, a getName()
method in that component might have hint="I return the full name of this user as 'Firstname Lastname'"
and the argument for the read()
method of a UserDAO
component might have hint="I am a UUID that uniquely identifies a user within the membership database"
.Note: The displayName
and hint
'comments' are in addition to the file comment
described above.
This section provides guidelines on source code layout for ColdFusion (and HTML).
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.
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.
All generated HTML should be XHTML-ready:
<p>
with </p>
and <li>
with </li>
,/>
breaks some old browsers, it is still recommended to do this, e.g., <br
/>
(note the space before the /
),
<img src="..." ... />
. Set Dreamweaver to generate
XHTML instead of HTML.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!
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).
These are the guidelines for the layout of table source code (see also Accessibility / Section 508 Guidelines):
<tr>
tags are placed at the same indentation level as their
parent <table>
.<td>
tags are indented.<td>
tags may be placed on a separate line
and indented, or if they are short they may be placed on the same line as
the <td>
.<table>
attributes should be explicitly specified.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!
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 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>
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'
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.
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:
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.
Each file should begin with an appropriate comment - see Style: Comments.
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 StructureEven 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).
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!).
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.
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:
request.buildTag
- string identifying the build on this serverrequest.buildWebServer
- string identifying
the web server name for this back end system, e.g., "www.macromedia.com"request.buildAppServer
- string identifying
this application server name, e.g., "d65app1.macromedia.com";request.buildAppCluster
- string list identifying all the application server
names in this cluster, e.g.,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.
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:
<cfapplication name="macromedia_com" sessionmanagement="true"
.../>
session.membership.user
etc).loc=
to create request scope language / locale values - see Globalization.<!--- Set encoding to UTF-8. --->
<cfprocessingdirective pageencoding="utf-8"/>
<cfcontent
type="text/html; charset=UTF-8"/>
<cfset setEncoding("URL", "UTF-8")/>
<cfset setEncoding("Form", "UTF-8")/>
<!--- Site-wide constants --->
<cfinclude template="/environment/sitewideconstants.cfm"/>
<!--- server-specific variables --->
<cfinclude template="/environment/serverspecific.cfm"/>
/{appname}/Application.cfm:
<cfinclude template="/Application.cfm"/>
<cfinclude template="/cfinclude/{appname}/applicationvariables.cfm"/>
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> ...
This section discusses some common debugging techniques.
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.
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!
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.
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:
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:
session
scope). As a general guideline, use session
scope sparingly.
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).
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).
macromedia.com has three levels of authentication:
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:
getAuthLevel()
- string - GUEST_USER
, REMEMBERED_USER
,
AUTHENTICATED_USER
getAuthLevelID()
- numeric - 0, 1, 2 respectivelyisLoggedIn()
- boolean - true if level 2 else false getUserID()
- numeric - internal user ID if level 1 or 2 else
-1For more details, your can read the session authentication spec.
This section provides some hints and tips that are considered "good practice".
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 --->
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>
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:
type=
attribute in your cfargument
tags. Try to avoid
using type="any"
.required="true"
but do not specify a default=
attribute.default=
attribute if appropriate or specify required="false"
but do not provide both.default=
but
instead use structKeyExists(arguments,"argName")
in
the function body (remember that when you specify default=
, you cannot tell the difference between the caller omitting that argument and the caller providing that same default value as an argument).<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 --->
cfproperty
Be aware that the cfproperty
tag is of limited use - it does
only two things:
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!).
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.
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 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.
This section provides guidelines on database table structure and naming.
CUSTOMER_ADDRESS
, ORDER_LINE_ITEM
).CUSTOMER_ADDRESS_ID
,
ORDER_LINE_ITEM_ID
, but in general should be avoided.CUSTOMER_FIRST_NAME
,
PRODUCT_DESCRIPTION
)._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
).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
)FIRST_NAME
,
MIDDLE_NAME
, LAST_NAME
] - [PHONE_NUMBER
,
FAX_NUMBER
, PAGER_NUMBER
]).DATE_CREATED
and DATE_LAST_UPDATED
columns.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 |
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.
The following are 'positive' recommendations, e.g., "Do xyz..." or "Do xyz instead of...".
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()
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.
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.
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.
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.
The following are 'negative' recommendations, e.g., "Don't do xyz...".
Avoid evaluate()
unless there is no other way to write your code (and there is almost always another way to write your code).
Always use cfif
/cfelse
instead of iif()
. It is significantly
faster and more readable.
Always use struct.key
or struct[key]
instead of structFind(struct,
key)
. They are significantly faster and more readable.
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.
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.
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.
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.
Date | Author | Comment |
---|---|---|
2/28/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 |
4/2/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 |
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 |
9/18/2003 |
Sean A Corfield |
Release 3.0.1: Incorporated initial public comments: Contents:
no change;
Style: clarified XHTML-compliance for |
8/25/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 |
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 |
10/21/2002 |
Sean A Corfield |
Added clarification about comment generation in non-CFML files; added
guidelines for debugging code; removed |
6/25/2002 |
Sean A Corfield |
Release 2.0.4: Fixed |
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 |
6/4/2002 |
Sean A Corfield |
Release 2.0.1: Added |
5/7/2002 |
Sean A Corfield |
Release 2.0: Added DOCTYPE and XHTML notes; updated encoding handling
( |
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