CFObjective Session: Build a ColdFusion powered AIR application

I'm putting the finishing touches on my upcoming presentation, Build a ColdFusion powered AIR application, for CF.Objective() and wanted to pass on some interesting news.

A couple of weeks ago, Terry Ryan, invited me to expand my presentation to cover AIR+ColdFusion functionality to be released in CF 9 Centaur. I'm totally thrilled to present a few CF9 features and am busy redoing the presentation so we can all get a better look at what CF9 brings to Rich Internet Applications. The illustrious Dan 'Big Pipes' Vega was also tapped to present some CF9 content at CF.Objective() so I'm pretty interested to see what he's going to show.

The upcoming CF9 brings many game-changing features to the table and adds a lot to the ColdFusion+RIA equasion. CF.objective() 09 is turning out to be the first public discussion on CF9 Centaur features and you don't want to miss these sessions, do you?

What? You've not registered for CF.Objective() yet? You can still take advantage of historically low airfare and the extended Early Bird Special, just do it before March 31st, ok? Check the sessions if you still need more convincing!

I present You Got Your ColdFusion In My Adobe Air! to TACFUG March 18th

You Got Your ColdFusion In My Adobe Air!

Meeting: 3/19/09 6:00 PM SRA International

Come see how to use ColdFusion to power an Adobe AIR desktop application.

Adobe AIR is quickly gaining momentum as a pioneer of the Rich Desktop. ColdFusion is a rapid development platform providing rich services and timely functionality for business applications.

When the two come together, it is the greatest combination since Reeses Peanut Butter Cups...

More info at TACFUG

I Present Making Bad Code Good To The CFMeetup March 5th @ 6:00 EST

At 6:00 EST this Thursday, March 5th, I present Making Bad Code, Good to the Online ColdFusion Meetup. You can attend this presentation virtually, by visiting the Online ColdFusion Meeting Room at 6:00 EST.

If you work on a legacy application, or on code built by lots of developers over the years, you likely laugh your way through this presentation. I promise to be thought provoking and challenge the way you write code. In this session, we'll look at lots of code samples and walk through making incremental changes to speed development, reduce errors and make life easier for everyone involved.

Ideas and concepts in this presentation will help you improve your existing applications and write more maintainable code.

The recorded presentation can be watched now!

CFQueryparam and Lists

A word on SQL Injection

SQL Injection is a pervasive problem in the Web Application World. A quick search for URLS that use raw SQL brings up hundreds of thousands of dangerously formed URLS. Any developer worth his salt knows to clean user input before using it.

Defend Against SQL Injection in ColdFusion

CFQueryparam is a recommended tag that helps to keep your queries safe from SQL Injection. Any ColdFusion worth his salt uses CFQueryparam to help keep malicious parameters from being executed by the database engine. I ran across some code today that used CFQueryparam in most cases, but there was a particular, recurring use case that used raw parameters.

Example 1

view plain print about
1<cfquery name="getProductsByList" datasource="ILikeTwinkies">
2SELECT productName,
3FROM product
4WHERE productID IN ( #productIDList# )
5</cfquery>

Note the use of the list. It is a common paradigm to pass a delimited list of data to an SQL statement. In this case, the developer chose not to use CFQueryparam because he/she was under the impression that the result would be a single parameter, not a chain of parameters.

However, CFQueryparam can be used successfully in this case by setting the optional attribute 'list' to true. This is a supported attribute on all database engines.

Example 2

view plain print about
1<cfquery name="getProductsByList" datasource="ILikeTwinkies">
2SELECT productName,
3FROM product
4WHERE productID IN (<cfqueryparam value="#productIDList#" list="true" cfsqltype="cf_sql_numeric">" )
5</cfquery>

The resulting query will be parametrized in such a way as to render the list as a list and the results of the second query are equal to the first. Except for the case of an SQL Injection attack.

In the case of an SQL Injection attack, the developer of the first code sample would have a lot of explaining to do...

OO Camp comes to RTP, NC

We work fairly hard at TACFUG to keep our members informed and engaged in key information about programming and ColdFusion. Recently, Jim and I, put out a request for topics and we found some challenges in meeting the need. Some of our members have a long history of programming in ColdFusion and want to branch out into Object Oriented programming, but for one reason or another just haven't. Jim and I came up with an OO Code Camp concept and floated it out to our group to gauge interest.

Here was our announcement:

The fine folks at TACFUG (me and Jim) are seriously considering doing an OO camp starting in January. OO Camp will be a crash course on OO in ColdFusion. Ideally, we'd cover the topic in 3 or 4 evenings spread over a couple of months. This crash course will be designed to teach OO concepts and how to efficiently work with ColdFusion components. If you are new to OO or do not think you are using OO effectively, this crash course is for you. There will be no cost for this event though we may take up a donation for Pizza. Who would be ready to commit to coming to 3 or 4 evenings of OO camp? Please use this email thread for comments, questions and such about the proposed OO Camp. Feel free to extend this offer to others in your company, organization, Facebook Network, etc that would find this helpful as well.

We got a good bit of interest, certainly more than enough to justify running OO Code Camp in RTP.

Jim and I will be teaching the class and while we are pretty darned good at what we do, we've never run an organized class on this topic before. To make sure we cover all the bases and deliver appropriate, encompassing training, I thought it would be a good idea to ask the multitude of talented readers of this blog for their advice. We want to deliver the core concepts of Object Oriented Programming in a practical, hands-on fashion. Please offer, by commenting below, any constructive advice, suggestions, key topics that you feel we should cover.

Thanks in advance!

Cruising

I've recently signed up to go on RIA Adventure. By now, everyone knows RIA Adventure is a fun filled cruise containing all of your favorite Adobe Geeks. I totally dig the networking at conferences so I'll really like hanging out with a bunch of fun people that know the difference between coldfusion and ColdFusion. Can Ya Dig?

I don't mind getting away to the tropics in February. In February, I'm usually ready for a little sun anyways. I also don't mind my girlfriend Shannon getting to know some of the people I'm prattling on about. She's heard enough stories, that's for sure.

Last I heard, this RIA Adventure cruise was filling up pretty fast. If you've been on the fence about participating, time to whip out the visa and book some February Fun in the Sun.

I searched and found CFSearching

I've been working on The Health Challenge over the last month and ran into a usability issue using my CFChart implementation. Apparently with enough data points, the labels would all jam into each other and become an unreadable mess. Have a look...

CFChart is actually a wrapped up implementation of WebCharts 3D, a full featured charting engine. ColdFusion ships with a Chart Stylizer that adds significant functionality to the generated charts. I've been using this Chart Stylizer for years now. However, I couldn't find an option to help me out with this X Axis Traffic Jam. Through a bit of google magic, I ended up on a blog I'd not seen before called CFSearching which addressed this issue for the Y Axis and after digging around the stylizer, I found a similar option for the X Axis.

view plain print about
1<xAxis>
2 <groupStyle skipLabels="{SkipLabels}"/>
3</xAxis>
Problem solved! See:

CFSearching has a number of very nicely written articles about CFChart, iText, Coldfusion and other important topics. For example, have you ever wanted to Create a Gantt Chart with CFChart or what about Calling ColdFusion functions from PDFPageEvents in iText? There are some very good articles up at CFSearching, go take a look!

Practical Refactoring In ColdFusion - Live Example

Practical Refactoring

I've done a few presentations on refactoring in ColdFusion and in those presentations, I show a lot of code samples towards the end. No matter how eloquent I am in the first part of the presentation, the light always goes on for the audience when I show code. If you think about it, it makes sense, why try to explain concrete principles in abstract terms?

I do my refactoring in sweeps. A sweep is a cycle through the code in which I make incremental improvements. At the end of a sweep, the code should (it better) still function as well as it did pre-sweep. By breaking up the refactoring up into small sweeps, we can stay focused and keep out of the weeds.

In this article, we are going to look at some code that could use a refactor. Then we'll make a few sweeps through the code to tidy it up a bit. Along the way, I'll explain why I am refactoring out a certain piece. Keep in mind, we are all still learning. None of this is meant as Final Law of Software Design. I'm always refining my viewpoints and learning new things so I'll probably disagree with something I've done here at some point in the future. In the end, as long as this article is thought provoking for you, we've both won. Can Ya Dig?

First, here is the code sample. Scan the code and fix in your mind the general idea of what is going on. We'll pick back up on the other side.

The Original Code

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        <cfif compareNoCase(trim(arguments.eventName),"onSessionEnd") And compareNoCase(trim(arguments.eventName),"onApplicationEnd")>
5            <cfif compareNoCase( arguments.Exception.RootCause.Type, "coldfusion.runtime.AbortException") >
6                <cfoutput>
7                <CFIF isDebugMode() is false>
8                <cfinclude template="/errortemplate.htm"/>
9                <CFELSE>
10                <h2>An unexpected error has occurred.</h2>
11                <p>Error event: #arguments.eventName#</p>
12                <p>Error details:</p>
13                <cfdump var="#arguments.exception#"/>
14                </CFIF>
15                <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
16                <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
17                </cfoutput>
18            </cfif>
19        <cfelseif not compareNoCase(arguments.eventName,"onApplicationEnd")>
20            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
21            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
22            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
23        </cfif>
24</cffunction>

Summary

Ok, answer to yourself the following questions:

  • Is the code right?
  • Do you know the purpose of the code?
  • Is it easy to understand?

The first question is a bit of a slippery slope. In my book 'Right' and 'Wrong' are determined by whether or not the code works. The code above actually works just fine. Compiled down to Java Bytecode, it happily processes errors with no defects, so it is 'Right'. When dealing with fuzzy subjects like code-cleanliness and proper organization, you'll find many more opinions than hard/fast rules. Clean Code is like Good Art, you know what you like when you see it. So stay away from calling other developers' code 'Wrong'. It only makes people defensive and defensive minds are not in learning mode.

Now that we've gotten past that, did you understand the purpose of the code? If you said "this code handles errors", give yourself 2 points. (The function name helped, didn't it?)

Was the code easy to understand? Can you verbalize what the code is doing? Try... no seriously, read this code from top to bottom. Can you do it? Did you have to reread parts of it?

It is a known fact that code we write personally instintively makes more sense to us than code other people write. This holds true even months after the code has been written. Good programmers write code that can be easily be understood by others. We are going to refactor this code to be more easily read.

First Analysis

A few easy things to point out... compare() and compareNoCase() are two functions that work opposite of how we read. If you use compare() to compare two identical strings, you get a return of 0, which ColdFusion treats as false, meaning we have to reverse our boolean logic in conditionals to accomodate this. Some people will tell you that compare() is faster than using an operator like IS or IS NOT. They might be right, I'm going to refactor the use of compare() and compareNoCase() out of the code anyways. If it turns out we needed the extra 'performance' of these functions, we should have implemented this part of the site in Hardware.

Next, the case is mixed inappropriately. Some operators are lower case, some are mixed case. Some of the conditionals are upper case, some are lower case. We'll normalize this and get it all looking consistant.

Also, this code has nested conditionals. Some times the only way to represent logical flow is to nest conditionals though most often it can be simplified for better readability. In this case, it looks like we truly care about a few conditions so I'll look at untangling the nest as well.

I'll put a few comments in as well, since that will help us remember what we were thinking in the middle of the refactor. Without further preamble...

First Refactor

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        
5        <!--- Exit conditions --->
6        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
7            <cfreturn />
8        </cfif>
9        
10        <cfif trim(arguments.eventName) IS "onSessionEnd">
11            <cfreturn />
12        </cfif>
13        <!--- Log and Exit --->
14        <cfif trim(arguments.eventName) IS "onApplicationEnd">
15            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
16            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
17            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
18            <cfreturn />
19        </cfif>
20        <!--- use error template file or print to screen --->
21        <cfoutput>
22            <cfif isDebugMode() is false>
23                <cfinclude template="/errortemplate.htm"/>
24            <cfelse>
25                <h2>An unexpected error has occurred.</h2>
26                <p>Error event: #arguments.eventName#</p>
27                <p>Error details:</p>
28                <cfdump var="#arguments.exception#"/>
29            </cfif>
30            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
31            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
32        </cfoutput>
33</cffunction>

Second Analysis

Ok, That is a pretty good start. We got rid of compare() and compareNoCase() so the code reads a little nicer. We got rid of the nested conditionals so we don't have to keep track of several layers of boolean logic and we cleaned up the inconsistent use of case.

Another thing that I try to stay away from is using negative boolean logic. See where we check for the isDebugMode() function? I'd much rather have the TRUE case up top and have the negative case be the ELSE portion.

Also, some of the logging is duplicated. Looks like someone was Copy/Pasting :). Let's clean that up as well.

Lastly, we are going to put in good comments all the way down the line and use appropriate whitespace for readability.

Second Refactor

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4    
5    <!--- We don't want to deal with the cflocation as an error, so bail --->
6        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
7            <cfreturn />
8        </cfif>
9    <!--- Lets deal with events next. --->
10        <!--- We don't want to deal with the onSessionEnd as an error, so bail --->
11        <cfif trim(arguments.eventName) IS "onSessionEnd">
12            <cfreturn />
13        </cfif>
14        
15        <!--- From this point onward, we want to log the errors --->
16        <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
17        <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
18
19        <!--- Log as Information and Bail --->
20        <cfif trim(arguments.eventName) IS "onApplicationEnd">
21            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
22            <cfreturn />
23        </cfif>
24    <!--- Now, let's deal with explicit types we want to handle... --->
25        <!--- If we get here, we have something to handle --->
26        <cfif isDebugMode() is true>
27            <!--- print the error to the screen --->
28            <cfoutput>
29                <h2>An unexpected error has occurred.</h2>
30                <p>Error event: #arguments.eventName#</p>
31                <p>Error details:</p>
32                <cfdump var="#arguments.exception#"/>
33            </cfoutput>
34        <cfelse>
35            <!--- use the nice error handler --->
36            <cfinclude template="/errortemplate.htm"/>
37        </cfif>
38</cffunction>

Final Analysis

That looks even better. Now that our conditionals use positive boolean logic they are much easier to read. We also were able to remove duplicate logging calls. Not all code duplication is bad, of course, but when we can get rid of it and improve the clarity and readability, we all win.

The comments are also very descriptive and tell us the intent and reasons for the code. This way, other developers can quickly understand what we were trying to do, even if it isn't working properly.

Just for fun, I'm going to paste the finished code below without comments and whitespace. Read through the code and notice how it reads more like English language.

Final Code - No Comments/No Whitespace

view plain print about
1<cffunction name="onError" output="true">
2    <cfargument name="exception" required="true"/>
3    <cfargument name="eventName" required="true"/>
4        <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
5            <cfreturn />
6        </cfif>
7        <cfif trim(arguments.eventName) IS "onSessionEnd">
8            <cfreturn />
9        </cfif>
10        <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
11        <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
12        <cfif trim(arguments.eventName) IS "onApplicationEnd">
13            <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
14            <cfreturn />
15        </cfif>
16        <cfif isDebugMode() is true>
17            <cfoutput>
18                <h2>An unexpected error has occurred.</h2>
19                <p>Error event: #arguments.eventName#</p>
20                <p>Error details:</p>
21                <cfdump var="#arguments.exception#"/>
22            </cfoutput>
23        <cfelse>
24            <cfinclude template="/errortemplate.htm"/>
25        </cfif>
26</cffunction>

Not to shabby, yeah? The code works just like the original sample, but it is much easier to understand the flow of the function. Also, by doing our refactoring in sweeps, we simplified the code in stages, reducing the chance we'll miss something. Now go to the last sample and read it aloud. Notice how it feels natural when you read it? This code will definitely be easier to maintain in the future, won't it? There are lots of other principles to keep in mind when refactoring. We'll look at a few more in the next article.

Agree? Disagree? Tell me all about it in the comments.

P.S. Do you have code you'd like to see refactored?

If you have a code sample you would like me to refactor, send it to me using the Contact Form on this blog. Please try to keep the code chunk below 100 lines as that seems to be the limit of clarity for a blog article.

I Present to the Hartford CFUG on CFUniform

Tonight (9/17/2008) at 7:30 EST, I'll present to the Hartford Adobe User Group on how to use the CFUniform custom tag library to create awesome forms in record time. I am a big fan of the CFUniform library, written by Matt Quackenbush and use it lots of projects.

You might be interested in CFUniform if:

  • you would like to create awesome forms in record time without writing HTML
  • you would like to keep your form markup consistent and feature-rich without reinventing the wheel
  • you aren't the best designer, but you want the best design
  • you are in a hurry and need to get it done right and quick
  • you want to make sexy, accessible, XHTML compliant forms without endless typing
  • you like to add widgets like masks, date pickers, time pickers to your applications with ease
  • you like accessible, feature-rich forms built with no muss, no fuss

If you can't make it to Hartford, CT tonight, you are in luck! The hosts have graciously agreed to provide Adobe Connect Access for all interested parties. Come in about 7:30 EST and have some fun with us...

Update: You can download the PowerPoint and presentation files by visiting the Features pod on the top right of this page. Simply click on CFUniform Preso.

So how did BFusion and BFlex go, you ask?

I am back home now after a very lovely and stimulating weekend at the BFusion/BFlex conference. BFusion and BFlex are back to back 1 day training/conference events held in Bloomington Indiana on the grounds of Indiana University. While some poor misguided souls might think any conference in Indiana would be nothing more than a projector pointed at a sheet hanging in a cornfield, I assure you this was not the case. Far from it.

The BFusion/BFlex event was awesome. Hands Down. The hallmark of a good conference is good organization and the promoters of this conference really put a lot of time into sorting out details. The moment we checked into the hotel we were handed colour coded maps showing important town features like the nearest grocery store, local restaurants, local watering holes and of course, directions to the conference facilities. Registration was simple and efficient. All of us there as Presenters, Instructors and Assistants were given branded polo shirts to wear so students knew who to ask for help. Lunch choices were color coded with the name tag to make finding ones particular choice a little easier. It was clear that our hosts had thought of everything.

The presenters had all the latest equipment at their disposal from dual monster projection screens to the Crestron powered audio/video equipment. The training sessions were stocked with quality instructors and had plenty of helpful assistants floating around the room to help keep the pace. To facilitate the learning environment, each of the rooms had power ports and ethernet jacks available for every seat which means we avoided the typical conference double wammy of running low on batteries and cramming everyone on an overloaded wifi router. Not least to mention, the campus of Indiana University is just simply beautiful!

So frankly, the quality of the event was on par with some of the best run conferences in the business. I am still a little shocked that the crew was able to provide all of the coordination, service and giveaways for free. Oh, thats right, giveaways. I need to talk about the giveaways.

Thanks to the awesome sponsors, there was an immense amount of giveaways. Everyone likes to get ColdFusion and Flex stickers, hats emblazoned with CF and technology themed t-shirts and those things were in good supply. More interesting were the tons of tech books, learning CDs, Lynda subscriptions and the like that were also raffled off to the attendees. The theme of this conference was learning and that means even the giveaways were there to help facilitate the learning. I brought my friend Tim Montgomery from Dayton, OH. He has been designing and implementing websites for many years now and wanted to get some good ColdFusion and Flex training. He left the conference with:

  • a CF hat
  • a new copy of John Farrar's book "ColdFusion 8 Developer Tutorial"
  • a really snazzy CF8 tag poster set
  • some free software
  • a new laptop bag
  • an Adobe Air with Ajax book
  • a Flex shirt
  • 16 new friends
...and 4 job offers. Everyone would have to agree that is some awesome conference loot!

All in all, the BFusion/BFlex series is impressive and of tremendous benefit to the community. Many people gained their first exposure to ColdFusion and Flex, others gained new skills and a good time was had by all. A big NoDans.com thank you to Bob Flynn, Prem Radhakrishnan, Michelle Buddie and the rest of the super cool staff for putting on a quality memorable show.