ColdFusion with Style
by
"The best laid plans of mice and men often go astray." (John Steinbeck, Of Mice and Men)
No other phrase can fit the reason for this article. I had planned to write a style guide for ColdFusion over time. It would have a number of solid articles covering pieces of ColdFusion such as The Laws of CFSET and how to do fast Text Comparisons in ColdFusion. It would have taken a long time to finish, but would have been solid as a rock. That plan is still in existence, but has changed slightly. The reason has to do with a misunderstanding of terminology.
Methodology - A set of rules that define how an application is to be developed.
Style - A set of suggestions on how to write a template 'correctly.'
Every month or so, someone posts to the CF-Talk list asking about a ColdFusion style guide. Every time it's asked, a discussion starts up, people put in their two cents and there's plans to make an 'official' guide that never gets out of the planning stage. This month it was different. Rather than post ideas and suggestions, most of the people suggested that the poster go and look at the FuseBox methodology. So many people posted the same thing that I just had to respond ahead of schedule. I posted a number of style suggestions I use.
The good thing is that I got some feedback. People had questions and suggestions. The bad thing is that there were very few. A good style guide, even a short one like I posted should elicit controversy. People should be saying that I'm wrong or that they program differently. I must have done something wrong, but I'm going to change that. Below is an extension to the style guide I posted to the CF-Talk list with a few more suggestions and explanations for everything. This time, I expect to hear some feedback.
- Pre-Template influences - These are things that you should take into account before the code of a template is even written.
- Segment your files - Don't have all of your files in a single directory. Place them in sub-directories that describe what the files are. Images should go in an images sub-directory, files you expect to include should go in an include sub-directory and included queries should go in a queries sub-directory. Additionally, take logical pieces of your application and place them in sub-directories with names that fit the general function. Templates controlling email should go in email and templates that are part of a calendar should go under calendar. This will make it easy to debug sections of code and lead to a cleaner directory structure.
- Always use .cfm extensions - ColdFusion uses .cfm files. There is no reason for .inc, .qry or any other 'strange' file extensions. This will only lead to confusion in debugging and problems in editing.
- Have meaningful file names - T.cfm just doesn't say anything. Testset.cfm does. Use filenames that have something to do with what the file is actually doing.
- Always have an application.cfm and a onrequestend.cfm - ColdFusion assumes that these files exist. It will search for them all the way down to the root on EVERY page request. Even if they're going to be blank, add them to your directory. This saves the server from having to read the drive more than once and prevents a file in an upper directory 'sneaking in' on your templates.
- Always save your files as lower case - This is only really important when your dealing with files that will be moved to a Unix system in the future.
- Documentation - The programmers bane, until they need to debug or rewrite the code.
- Use a standard information header - All ColdFusion templates should have some basic information on the first line. The name of the application the template is part of (or that it's a custom tag), the author and a description of what the template does. This will help you and others in the future when all memory of the application is gone.
- Segment your code - A template may do one thing, but that one thing may still have parts. Place double spaces between each of these parts. For example, an importer template would have one segment that uploads a file and saves it. Another segment would read it and loop over the content to place it into a database. A third piece would give you a readout of what happened. These three pieces should be separated if possible (in the same template, not into modules).
- Comment each segment - Once you segment your code, have a line of comment to say what the segment does. Any special variables, code or changes should be noted for future reference.
- If you comment out code, tell why - Many applications have pieces of code that's commented out because it was wrong, was updated or was just a good idea. If you don't explain why you commented the code out, you WILL forget.
- Map your resources - Have a separate document that maps all the resources for an application. Moving an application in a single directory is easy, until you realize you forgot the custom tags. Having a map will tell you all the resources and directories that go into the application.
- Code - There are a number of code issues that should be examined. Most of them have to be written up in separate articles due to the depth of information. Until these articles are out, here's the basics.
- Every app should have a CFAPPLICATION tag - Even if you're not using state management, you should have a CFAPPLICATION tag going. Most applications have default values and storing them in application variables allows them to be set for the entire app.
- Run application defaults ONCE - Most people place CFSETs for application defaults inside their application.cfm files. They expect that the variables will be set once, but in reality they are set on EACH template. A better idea is to use the following code:
|
<CFIF NOT IsDefined('Application.DSN')>
<CFSET Application.DSN = "datasource">
<CFSET Application.Root = "/htdocs/testbed/">
</CFIF>
|
This will cause the CFSETs to be used ONCE and only ONCE.
- Scope your variables - By scoping your variables, you make you applications run faster and easier to understand. If I see Form.UserName, I know that it came from a form.
- Never use pounds (#) in an evaluation zone - There are four places in ColdFusion where a variable, function or expression will AUTOMATICALLY be evaluated. These are the CFSET tag, CFIF/CFELSEIF tags, inside ColdFusion functions and inside a CFSCRIPT block. You should never use pounds (#) in these places. Pounds (#) are only needed within a CFOUTPUT block, CFQUERY block or inside any CFTAG (other than CFSET or CFIF/CFELSEIF).
- Use functions when doing TEXT comparisons in CFIF - Any time you're doing a comparison between a TEXT value and anything else in a CFIF/CFELSEIF statement, you should use a function. If you're checking to see if a variable is blank (""), then use Not LEN(). If comparing two text strings, use Not CompareNoCase(). If doing a contains, use a FindNoCase(). This was covered in .
- Remember Short Circuited Boolean Evaluation - This feature was introduced in ColdFusion 4.01 and was a fantastic addition. It basically says that when a comparison statement (CFIF, CFELSEIF, IIF()) has more than one clause, the result of the first clause can effect if the second is run at all.
- If the joiner is AND and the first clause is false, the entire statement is false and the second clause will never run.
- If the joiner is OR and the first clause is true, then the entire statement is true and the second will never run.
- If the joiner is IMP and the first clause is false, the entire statement is true and the second will never run.
In all cases, placing your clauses to take advantage of these rules can speed them up.
- Never use IIF - If you can help it, don't use the IIF function. It is half as fast as a normal CFIF.
- Use CFSWITCH when you can - When you have multiple CFELSEIFs and the variable your comparing is always the same, a CFSWITCH will run much faster and look better.
- Use CFSCRIPT - When doing 3 or more CFSETs in a row, placing them within a CFSCRIPT block will speed them up.
- Lock network protocols - When working with network tags like CFHTTP and CFFTP, use the CFLOCK tag around them. The network tags are not multi-threaded and if you run them without any locking, you may get PCode errors.
- Lock memory-based state management variables - In CF 4.0 and 4.01, you have to lock the setting of memory based state management variables (Server, Application, Session). If you don't, you may find a situation where a value is being written to memory at the same time as it's being read. This will result in a PCode error. This has been slightly fixed in 4.5 (thanks to Seth Petry-Johnson for reminding me).
- Restrict your query returns - If you're expecting a single row back from a CFQUERY, set the maxrows attribute to 1. This gives you more information about what you're doing when it comes time to debug or rewrite. Additionally, it may result in a slightly faster query, as you're restricting what you should get back.
- Never nest loops deeper than 3 levels - Doing so will result in major slowdowns.
- Indent your code - Any code that is inside a 'block tag' (i.e. a tag with an ending tag) should be indented by 1 tab.
- Lowercase all paths and files - All file calls and paths should be in lower case. This will save you problems if/when you move an app to Unix.
- Modules - ColdFusion Modules are great, but not totally understood.
- Use CFMODULE over CF_ - The CFMODULE syntax allows you finer control over the location of your module than the CF_ syntax.
- Be careful what you pass - Every call to a ColdFusion module will pass the Url, Form, CGI, Server, Application, Session, Client and Request variables on to the module. This means that there's really no reason to pass these values as attributes for the module.
- Use CFINCLUDE over CFMODULE - whenever possible, use CFINCLUDE rather than CFMODULE. Because of the extra information passed to each module, there is more overhead. CFINCLUDEs usually take half as long as CFMODULEs.
- Never nest deeper than 3 levels - This is one for both CFMODULEs and CFINCLUDEs. Nesting too deep can slow down your processing and can also lead to problems with debugging.
These suggestions are just the tip of the iceberg. Many more have been written into articles on Fusion Authority and other sites and many more will be written in the future. One important thing you must realize is that the many more to be written must be written by YOU! A style should take into account feedback from the community, practices that are actually being used and ideas of what should be done. It's not for one person, no matter how much they know, to dictate styles. Speak up, make yourself heard.