Accessibility
Ray Camden

Raymond Camden

coldfusionjedi.com

Created:
13 March 2006
User Level:
Beginner
Products:
Coldfusion

ColdFusion Coding Contest – Part 2: Intermediate Lessons Learned

In an earlier article, I discussed a contest I was running on my blog (ray.camdenfamily.com) for people who were new to ColdFusion. This contest was a great success, so I decided to run another contest for folks who weren't quite as new to ColdFusion. I dubbed this the Intermediate ColdFusion Coding Contest and it was open to anyone who didn't consider themselves an advanced or expert developer.

Because I'm a big believer in games being a great way to learn, I decided to use another game for the contest: blackjack (the rules were not Las Vegas–style, however). Here is how I defined the game:

  • Every blackjack game should begin by having two cards given to the player and two cards given to the computer. One card should be handed out at a time. One of the computer's cards should be visible.
  • The player goes first. The player has two options: He or she can either hit, which means asking for a new card, or stay, at which point the computer takes over.
  • The point of blackjack is to get as close to 21 points as possible. If a player exceeds 21 points, his or her game is over.
  • The aces card can be either one or 11.
  • If the computer and the player tie, the computer (dealer) wins.
  • The computer must hit if the value of its hand is less than 17. Once the value becomes 17 or higher, the dealer must stay.
  • There is no double down, splitting pairs, or getting five cards for an automatic win.
  • The game must use session management and track the player's progress through multiple hands. It is up to the player to decide how much money to give the player.
  • The player does not need to keep track of cards after a hand. In other words, the player can reshuffle for each hand.

As you can see, this version is not as complex as the real game of blackjack. However, it is certainly enough to provide a challenge and actually be fun to play. Let's take a quick look at some of the entries and discuss what went wrong and what went right.

I think it's beneficial demonstrate multiple solutions to a problem and even discuss flawed solutions. Those of us who write code to help others try our very best to be perfect. But we can also gain a lot by looking at code that has bugs, as long as those bugs are pointed out. This article focuses on some of the mistakes I found in the entries, as well as some of the nice surprises. At the end you will find a list of all the blog entries for the contest. Read these entries to get an in-depth look at my analysis of each example.

Var Scoping

I know folks are getting tired of hearing me complain about this, but I'm not going to stop until I stop seeing code with these mistakes. This time I'll keep it short and simple. You must do your best to var scope each and every variable used inside a ColdFusion component (CFC) method or a user-defined function (UDF). If you do not, the world as you know it will come to an end. (At the same time, it can lead to situations that are extremely difficult to debug.)

To learn more about this, see About Scopes in the ColdFusion LiveDocs (ColdFusion MX Developer's Guide > Using ColdFusion Variables > About Scopes).

Debugging: Good for Testing, Bad for Production

Entry 1 does something rather well in the Application.cfc file:

<cfsetting showdebugoutput="NO">

Now why would you include this line of code? It is a bad idea to enable debugging on a production server, but it could happen. Someone with access to the ColdFusion Administrator could turn on debugging and simply forget to turn it off. Or you might set the showdebugoutput attribute to yes, thinking it is protected by IP without actually specifying an IP address to restrict the information. All in all, more than one thing could go wrong.

This one line of code simply specifies that the application should never show debugging information. Period. It is a good idea to put this line in your code before pushing the code live. You can certainly set the attribute to yes when working on your development server. Simply having the line there should remind you to update the setting when going live. You can even write code to check the current host and set the value dynamically.

Using Application.cfc Correctly

Application.cfc was a new feature added to ColdFusion MX 7. You can use it to build much more powerful ColdFusion applications, and you can write code to respond to specific events in your application. For example, you could execute code when a session or application ends. Many of the contest entries used Application.cfc, but some of the entries made some mistakes in how they used this feature.

Entry 3 is a good example of such a mistake. The entry uses the following code in index.cfm:

<cfif isDefined('url.init') OR NOT isDefined('session.dealer')>
   <cfset structClear(session) />
   <cfset session.dealer = createObject('component', '_com.dealer').init() /> <!--- new dealer --->
   <cfset session.player = createObject('component', '_com.player').init(2000) /> <!--- new player with inital $2000 bank --->  
</cfif>

Notice how this code snippet detects a missing session variable? If the variable session.dealer does not exist, the application clears the session and creates new session variables. This is a perfect example of something that you could set inside an onSessionStart method. This would be preferable because you would be able to remove the code that checked for the existence of the session variable.

Entry 6 makes the same mistakes as the previous example—not using the proper event methods of the Application.cfc file. The following is the entire Application.cfc from that entry:

<cfcomponent output="false">
   <!--- New application object, with timeout and sessions --->
   <cfset this.name="blackjack_dness">
   <cfset application.highscore=1000>
   <cfset this.applicationTimeout=createTimeSpan(0,12,0,0)>
   <cfset this.sessionManagement=true>

   <cffunction name="onRequestStart" returntype="void" output="false">
      <!--- If we need a new session, or they want to restart the session, go here --->
      <cfif not isDefined("application.highscore") or isDefined("url.AppRestart")>
         <cfset application.highscore=1000>
      </cfif>
      <cfif not isDefined("session.blackjack") or isDefined("url.restart">
         <!--- We store all the information in the session struct. --->
         <cfset session.blackjack = createObject("component","cfc.blackjack").init()>
         <cfset session.dealer = createObject("component","cfc.blackjackplayer").init()>  
         <cfset session.player = createObject("component","cfc.blackjackplayer").init()>  
      </cfif>
   </cffunction>
</cfcomponent>

Notice that the CFC creates an application variable (highscore) in the constructor area of the CFC. Instead, you should set the application variable in the onApplicationStart method. Also notice that a set of session variables is initialized in the onRequestStart method. Again, it is better to initialize the session variables in the onSessionStart method.

The contestant for Entry 6 did accomplish one cool thing, however. He allowed for a URL variable to reinitialize the application and another one to reset the session. When he revises this code, I would recommend that he keep these lines in but simply have them call the appropriate methods. Here is a simple example:

<cfif isDefined("url.reinit")>
   <cfset onApplicationStart()>
</cfif>

There is one caveat: When you call one of the methods that ColdFusion normally calls by itself, the code is not single-threaded. If you have anything in the onApplicationStart or onSessionStart methods that needs to be single-threaded, you must use the cflock tag instead. Typically, developers use these methods for variable initialization, so this wouldn't be necessary.

Fun with JavaScript

JavaScript can be a powerful tool to enhance your web applications. For example, it can do form error checking before doing a round trip to the server, resulting in a quicker turnaround for the user. This is certainly a good thing. However, you cannot rely on JavaScript to build a secure application.

Two entries demonstrate what happens when you code based on this assumption. Entry 10 allows you to bet more money than you have if you disable JavaScript. Entry 11 has an even more enjoyable bug. If you disable JavaScript, you can bet a negative number, like –999999. Then if you lose intentionally, you "win" by losing the negative of that number. That's one trick I'd love to use in Vegas!

I strongly suggest you test your sites with JavaScript disabled. One simple way of doing this is with the Web Developer extension for Firefox. This toolbar lets you disable/enable JavaScript with a quick click of the mouse. If you use JavaScript in your site now, it is imperative that you test your site with JavaScript disabled as soon as possible to see potential loopholes in your variable validation.

Unit Testing

Speaking of testing, I don't think a single person reading this article tests his or her code enough. I know I don't, either.

One entry in particular demonstrated how the coder tested his application particularly well. Entry 3 uses a CFML file for every CFC file in his entry. The CFML file runs a series of tests on the CFC. What does this mean? It means he can simply run each CFML file to ensure that the application still works. This is very, very handy.

In the blog entry where I discuss this code, I talk a bit more about unit testing and provide URLs to help you learn more about it.

The Winners

So who won the contest? I thought three entries were particularly good so I picked one winner and two runners-up:

Entry 11 (despite its JavaScript issue) was a runner-up for its cool design. While this was certainly not a design contest, I liked what the contestant did with his entry.

The second runner-up was Entry 8, which used Flash Forms in a very cool way. Flash Forms are another new feature in ColdFusion MX 7. You can use them to build simple RIAs (rich Internet applications) using a simple tag-based syntax. Think of it as a super-simple version of Macromedia Flex.

The overall winner was Entry 4. I think the contestant did well with validation in the application (like var scoping—something I get nit-picky about). He also added a great feature—a game history—which allows you to look back at earlier hands to see how you did.

I'm now running the Advanced ColdFusion Coding Contest. This contest will ask folks to employ both Flex 2.0 and ColdFusion.

Contest URLs

You can find the full list of contest entries below:

About the author

Raymond Camden is a software consultant focusing on ColdFusion and RIA development. A long time ColdFusion user, Raymond has worked on numerous ColdFusion books including the ColdFusion Web Application Construction Kit and has contributed to the Fusion Authority Quarterly Update and the ColdFusion Developers Journal. He also presents at conferences and contributes to online webzines. He founded many community web sites including CFLib.org, ColdFusionPortal.org, ColdFusionCookbook.org and is the author of open source applications, including the popular BlogCFC (www.blogcfc.com) blogging application.Raymond can be reached at his blog (www.coldfusionjedi.com) or via email at ray@camdenfamily.com. He is the happily married proud father of three kids and is somewhat of a Star Wars nut.