Release 3.2 (4/14/2005)
« Structure: Application, Component, Tag etc | Contents | Database Conventions »
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.
« Structure: Application, Component, Tag etc | Contents | Database Conventions »
RSS feed | Send me an e-mail when comments are added to this page | Comment Report
Current page: http://livedocs.adobe.com/wtg/public/coding_standards/goodpractice.html
Comments
grantmr said on May 30, 2004 at 5:34 PM : SeanCorfield said on Jun 21, 2004 at 5:22 PM : yitian said on Aug 4, 2004 at 7:16 PM : SeanCorfield said on Aug 6, 2004 at 6:54 PM :