Showing posts with label ColdFusion. Show all posts
Showing posts with label ColdFusion. Show all posts

Tuesday, December 16, 2008

Multi-part emails on the iPhone and Thunderbird

At APT, most of us read our email in Outlook. But many of us also have iPhones, and a few of the more adventurous folks (myself included) use Thunderbird out of the office. For the longest time, our software's emails would look just fine in Outlook but would be completely blank in other mail clients (notably iPhone and Thunderbird).

So it turns out that when you send a multi-part email, and one part is plain text and the other part is HTML, most clients will display whatever part occurs LAST.

When you use the <cfmail> tag with <cfmailpart>, and the only part you declare is HTML, ColdFusion "helpfully" adds another plain text mailpart for you. At the end. With no content. Thanks a lot, ColdFusion. Very helpful.

So, the "solution" is to explicitly declare an empty <cfmailpart type="text"> tag BEFORE the <cfmailpart type="html"> tag.

Monday, July 21, 2008

Debugging at APT - Part 1: Firebug

Like most developers (using any language or platform), folks at APT crave robust and powerful debugging tools. Fortunately, ColdFusion 8 introduced some fantastic new debugging and monitoring tools, on top of the robust logging and request debugging that has been available for a long time. Unfortunately, our architecture seems to prevent us from using most of those tools. (But we'll have plenty of architecture discussions later.) More generally, our system is not "pure" ColdFusion -- we also use Java directly, as well as SQL, JavaScript, CSS, .NET, VBScript, Ant... you name it -- so we often wonder which debugging tools are best for which jobs.

I recently hosted an internal "Wednesday Noon Session" on debugging at APT. (Every three weeks or so, one of our engineers puts together a presentation that focuses on one aspect of development at APT.) I learned a lot by preparing my session, so I'm going to post a series of articles on the tools we use and how we use them. I'll start today with Firebug.

Firebug

For the client side, as well as some server-side debugging, Firebug is one of our best friends. We don’t officially support Firefox for our clients, because their IT departments pretty much all mandate IE6 and prohibit the installation of any other browser. In fact, 95% of our product logins come from IE6, and almost all of the rest are from IE7. Once in a while we even see someone try to use IE6 on Win2K, which typically is missing the past five years worth of bug fixes and security patches. (Yes, even in mid-2008!)

But we’re working toward full Firefox support for a number of reasons, one of which is debugging capability. We have all sorts of complex pages in our software. If you’re not familiar with them, simply finding an element on the page, let alone debugging a script, can be daunting. Thank goodness for the "Inspect" button.


We make heavy use of the Script tab to evaluate JS expressions on-the-fly and step through functions, as well as the Net tab to see what's going on with our AJAX requests (like sorting, searching and pagination within each component). We also used Yahoo!'s YSlow extension to discover that our menus were rendering upwards of 85 iframe tags on each page. (Ouch! Well, it turns out that all of the iframes were there to work around a well-known IE6 bug. But we've since gotten smarter about the "hidden iframe hack" and we've also switched to using YUI menus, which are also smarter about using iframes and about rendering efficiency in general.)

Next time: Firebug's cousin and competitor, the IE Developer Toolbar.

Friday, May 2, 2008

Fault-Tolerant ColdFusion Error Reporting


ColdFusion’s default reporting mechanism for uncaught errors is to dump the error information to the console. This has several disadvantages, two of them being that the console would have to be monitored and whoever is monitoring it is limited to the dumped information. To address this issue, ColdFusion Administrator has a setting for a Site-wide Error Handler. This is a custom template to execute when an error is encountered, and allows for sophisticated post-processing of the error.

At APT, we take advantage of this feature and have a very robust Site-Wide Error Handler. Among other things, it retrieves additional information about the user and setup, retrieves information about the product’s state, diagnoses the error, logs the error to a database, and sends an e-mail to relevant engineering and delivery team members. But there is a catch: if an error is encountered within the Site-wide Error Handler it stops processing and dumps that error to the console. Should this happen, we are right back where we started.

The solution is simple: make sure your Site-wide Error Handler never fails. However, if you have a complicated template, this is easier said than done. In this situation, we must make the Site-wide Error Handler fault-tolerant.

How do we achieve fault-tolerance? The foundation is liberal use of try-catch blocks within your Site-wide Error Handler. While it may at first appear sloppy and clutter up the code, it is critical for isolating the effects of errors, making sure the maximum amount of processing takes place, and ensuring the most information possible makes it back to you.

Look at this simple example template:


<cftry>
    Retrieve user information
    <cfcatch> Handle exception </cfcatch>
</cftry>
<cftry>
    Retrieve information about the product’s state
    <cfcatch> Handle exception </cfcatch>
</cftry>
<cftry>
    Send an e-mail with error and additional
     retrieved information

    <cfcatch> Handle exception </cfcatch>
</cftry>



If retrieving user information fails, we will still be sent an e-mail containing the error information and information about the product’s state. This is exactly the isolation we are going for. Subcomponents within in the try-catch blocks can be wrapped in their own try-catch blocks as well, creating an even more granular and fault-tolerant template.

When errors with your Site-wide Error Hander are caught, be sure you attempt to report information on them instead of letting them get swallowed up silently. In the above example, the information about the error encountered while retrieving user information should be included in the final e-mail sent. This feedback is critical in debugging and improving the Site-wide Error Handler—you will be glad you have it. However, be sure to wrap this reporting in its own try-catch in case there is an error with reporting the error. The overall theme is: the more paranoid the better!

By treating your Site-wide Error Handler as a series of granular tasks contained within try-catch blocks, the effect of failures will be limited while the maximum amount of error information safely makes its way back to you. This will be speed up the time it takes to identify, diagnose, and fix bugs and thus improve the quality of your software. <cftry> and <cfcatch> tags are essentially free, but engineering time is not.