Error Message FAIL

I was working on a server migration last night. In process, I set up the DNS for the mail servers. When I entered the value for the DNS server EXACTLY like Google said, I got the below error:

Alert: The domain was not added due to an error in the dns settings. Please check your dns template and verify. The message from the dns server was dns_rdata_fromtext: :26: near 'ASPMX2.GOOGLEMAIL.COM..': empty labelzone thehealthchallenge.com/IN: loading master file : empty label

Since I don't speak fluent Southern Klingon, my mistake was not immediately obvious. I, of course, tried to submit the form several more times. When I finally read the error message, I realized the Control Panel wants to be the one to add the trailing period (.). Removing my trailing period fixed it.

This is the most indirect, least helpful error message I've seen all month. I vow in 2009 to do better than these guys when alerting my users to issues.

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.

The Greatest Chicken Dish in the World! (with video)

Last night we had dinner with some dear friends, Jessica, Kyle and their baby Hunter. (Remind me one day to tell you about the fun I had feeding lemons to Hunter).

We had dinner at Sitar Palace, an Indian restaurant in North Durham. Of course, all the items on their buffet were awesome, but the standout was a dish cryptically called Chicken 65. Move over Chicken Makhani, make room for my new favorite chicken dish, Chicken 65.

Shannon and I searched the Internet for a good recipe and found some rather interesting descriptions for this dish. Apparently, no one can be sure of the origin of the name.

Wikipedia on Chicken 65:

The number 65 is variously said to be the number of days taken to prepare the marinade or the year of the dish's creation. One account claims that the dish emerged as a simple meal solution for Indian soldiers in 1965. Others accounts claim that an "enterprising hotelier" targeted macho diners with a 65-chilli recipe and named the dish accordingly. It is generally acknowledged that no one knows which (if any) of these anecdotal theories are true.

Enter Vah Chef

Vah Chef is apparently an Indian Celebrity chef from Chennai who is absolutely hillarious. He is infectious with his energy and has a simple cooking style. Anyone who has ever tried to make Indian food knows it can be involved and require WAY more ingrediants than typical American food. Vah Chef has a very popular website with videos and recipes of popular dishes. If you like Indian foods and like to cook, Vah Chef is a must-see website.

Where's the video you promised us?

Vah Chef has a video on Chicken 65 where he demonstrates step by step how to make the delicious dish. While preparing, he enterains by going through the history and misconceptions of the dish as well.

Do you cook Indian food? Do you have good resources you'd like to share? What is your favorite dish?

How I Cured My Back Pain

As I've gotten older, and gotten into the habit of working more hours, I'd become somewhat used to a pain in my back. This specific pain, inflammation rather, was located just under my right shoulder blade and would surface around mid-day. As I normally work 10-12 hours a day, the back pain impacted my ability to focus and to enjoy my work fully. I ended up casting a naughty glance at my office chair (Office Depot 79$ special), thinking it could possibly be contributing to the problem. After poking around at the Herman Miller Aeron chairs, I couldn't bring myself to spend over $1,000 for a chair that might or might not help me out.

After even more research, I found a chair called Ergohuman ME7ERG Mesh High Back Chair. Since it was half the price of the Aeron and was listed on a site claiming to have "Chairs professionally selected by certified Ergonomists", I simply had to have one.

And what did you think about it?

To be blunt, this chair cleared up my back problems. Within less than a week of having it, I had less pain, better focus and was more comfortable working than I had ever been. Quite possibly, the $500 I spent has delivered the most bang for the buck of ANYTHING I have in my home office.

Where did you by it?

I bought this chair from http://www.ergonomicchairpro.com, mostly because they had an eBay special for $500 with free shipping. They offer similar deals on their website right now, so don't worry about searching around.

How long did it take to receive?

The chair showed up in a few days. Considering how large the package is, and the Free shipping, I thought it would take much longer.

How was the Installation?

Putting the chair together took me about 15 minutes. All the necessary tools were provided in the package for me. They even included some extra screws, which I kept.

How was the Quality?

This chair is seriously built. Some chairs are cheap plastic and will wear out soon. The Ergohuman ME7ERG is built with a heavy steel base and composite frame. I've used this chair every day for a year now and there is no sign of wear. It is very comfortable and adjusts in a number of manners for the best fit.

Seriously? No Back Pain?

I have not had a recurrence of the back pain at all since I've been working in this chair. Even when working in lengthy spurts of 60-80 hours, no back pain.

How much money do you get from selling these chairs?

I don't make a single nickel from selling these chairs. Frankly, at DataCurl, we do just fine providing high-quality consulting and applications to the Health and Wellness industry that we don't need to shill chairs for pennies. You don't see any ads on this blog do you?

In closing, if you have back pain from working at a computer all day long, you owe it to yourself to invest in a proper chair. Most people have vehicles that cost between $10-50k which are driven less than an hour a day. A quality work chair is used between 6-12 hours a day, so it is worth the extra money to get a quality chair designed around human beings. If you want one of these chairs, go check out Ergonomic Chair Pro and get one today.

Customize CFUnited 09

The fine folks at Stellr have put together a list of all the proposed presentations for CFUnited 09. You are invited to help choose the presentations you'd be most interested in watching.

The CFUnited 09 presentation survey will take less than 10 minutes and will help make sure the conference content is relevant, timely and in line with audience expectations.

I think this is a great idea and will help make sure the conference is tuned for the audience. Vote Today!

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.

<xAxis>
<groupStyle skipLabels="{SkipLabels}"/>
</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!

Must Read: Matt Woodward on Refactoring Yourself In A Corner

Matt Woodward has a keen mind for technical topics. I've enjoyed his work for a variety of years on a variety of topics such as Mach-II, The CF Weekly, Conference Presentations, CHUG and others. Today, Matt wrote a thought provoking piece about a situation that happened on his team. The piece is entitled Avoid Refactoring Yourself Into A Corner

Apart from being well written, this article explains how a change in the stakeholders precipitated a supposed change in requirements. Implementing this requirements change would have been lengthy and time-prohibitive. Through the benefit of a sharp team and open dialogue, Matt's crew was able to forgo a long and drawn out refactoring.

Refactoring is a great way to make incremental improvements to a code base, or to deal with shifting requirements. Often refactoring requires a deep understanding of many ongoing processes and the dependancies between each. All of this complication can obscure possible solutions. As Matt points out:

It's easy when you're neck deep in an application to have your thinking get a bit rigid and not be able to see the numerous other ways in which the problem you're facing might be solved. So you start going down straight-line path you see in front of you and figuring out ways to tweak what's already there to handle a new requirement that may well be the antithesis of what your domain model was originally designed to address.

I challenge you to give Avoid Refactoring Yourself Into A Corner a read and then have an honest think about similar situations you've been in before.

Give Model-Glue A Piece Of Your Mind

We on the Model-Glue team have put together a simple survey and want to hear from you. Even if you aren't using Model-Glue or Frameworks or OO at all, your views are important to us.

How long will it take?

We've all taken long and boring surveys with endless questions requiring 1-10 rankings on sundry topics like "How much do you prefer crunchy peanut butter over creamy peanut butter?". Model-Glue is all about making things easy for developers and this survey is no exception. This survey was tested with several monkeys from the North Carolina Zoo. Each monkey was able to complete the survey and give quality answers, all within a 20 minute period. The way we see it, a reasonably intelligent ColdFusion user like yourself should be able to complete the survey in 10 minutes.

Would you kindly give us 10 minutes of your time for the Model-Glue Survey? We promise to read all answers and use the answers for the good of the framework.



No monkey's were harmed in the making of this Blog Post.

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

<cffunction name="onError" output="true">
   <cfargument name="exception" required="true"/>
   <cfargument name="eventName" required="true"/>
      <cfif compareNoCase(trim(arguments.eventName),"onSessionEnd") And compareNoCase(trim(arguments.eventName),"onApplicationEnd")>
         <cfif compareNoCase( arguments.Exception.RootCause.Type, "coldfusion.runtime.AbortException") >
            <cfoutput>
            <CFIF isDebugMode() is false>
            <cfinclude template="/errortemplate.htm"/>
            <CFELSE>
            <h2>An unexpected error has occurred.</h2>
            <p>Error event: #arguments.eventName#</p>
            <p>Error details:</p>
            <cfdump var="#arguments.exception#"/>
            </CFIF>
            <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
            <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
            </cfoutput>
         </cfif>
      <cfelseif not compareNoCase(arguments.eventName,"onApplicationEnd")>
         <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
         <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
         <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
      </cfif>
</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

<cffunction name="onError" output="true">
   <cfargument name="exception" required="true"/>
   <cfargument name="eventName" required="true"/>
      
      <!--- Exit conditions --->
      <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
         <cfreturn />
      </cfif>
      
      <cfif trim(arguments.eventName) IS "onSessionEnd">
         <cfreturn />
      </cfif>
      <!--- Log and Exit --->
      <cfif trim(arguments.eventName) IS "onApplicationEnd">
         <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
         <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
         <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
         <cfreturn />
      </cfif>
      <!--- use error template file or print to screen --->
      <cfoutput>
         <cfif isDebugMode() is false>
            <cfinclude template="/errortemplate.htm"/>
         <cfelse>
            <h2>An unexpected error has occurred.</h2>
            <p>Error event: #arguments.eventName#</p>
            <p>Error details:</p>
            <cfdump var="#arguments.exception#"/>
         </cfif>
         <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
         <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
      </cfoutput>
</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

<cffunction name="onError" output="true">
   <cfargument name="exception" required="true"/>
   <cfargument name="eventName" required="true"/>
   
   <!--- We don't want to deal with the cflocation as an error, so bail --->
      <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
         <cfreturn />
      </cfif>
   <!--- Lets deal with events next. --->
      <!--- We don't want to deal with the onSessionEnd as an error, so bail --->
      <cfif trim(arguments.eventName) IS "onSessionEnd">
         <cfreturn />
      </cfif>
      
      <!--- From this point onward, we want to log the errors --->
      <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
      <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>

      <!--- Log as Information and Bail --->
      <cfif trim(arguments.eventName) IS "onApplicationEnd">
         <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
         <cfreturn />
      </cfif>
   <!--- Now, let's deal with explicit types we want to handle... --->
      <!--- If we get here, we have something to handle --->
      <cfif isDebugMode() is true>
         <!--- print the error to the screen --->
         <cfoutput>
            <h2>An unexpected error has occurred.</h2>
            <p>Error event: #arguments.eventName#</p>
            <p>Error details:</p>
            <cfdump var="#arguments.exception#"/>
         </cfoutput>
      <cfelse>
         <!--- use the nice error handler --->
         <cfinclude template="/errortemplate.htm"/>
      </cfif>
</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

<cffunction name="onError" output="true">
   <cfargument name="exception" required="true"/>
   <cfargument name="eventName" required="true"/>
      <cfif arguments.Exception.RootCause.Type IS "coldfusion.runtime.AbortException">
         <cfreturn />
      </cfif>
      <cfif trim(arguments.eventName) IS "onSessionEnd">
         <cfreturn />
      </cfif>
      <cflog file="#this.name#" type="error" text="Event name: #arguments.eventName#"/>
      <cflog file="#this.name#" type="error" text="Message: #arguments.exception.message#"/>
      <cfif trim(arguments.eventName) IS "onApplicationEnd">
         <cflog file="#this.name#" type="Information" text="Application #this.name# ended."/>
         <cfreturn />
      </cfif>
      <cfif isDebugMode() is true>
         <cfoutput>
            <h2>An unexpected error has occurred.</h2>
            <p>Error event: #arguments.eventName#</p>
            <p>Error details:</p>
            <cfdump var="#arguments.exception#"/>
         </cfoutput>
      <cfelse>
         <cfinclude template="/errortemplate.htm"/>
      </cfif>
</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.

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.9.001. Contact Blog Owner