Grant asks:
Hey Ray, I'd like to see you do an article sometime on "When to catch an error". I've been working on my own sorta ORM for ColdFusion and I've definitely seen that there can be benefits to throwing errors and/or not catching them. It seems to me there should be a practice for this because if you caught every error, a broken piece of code would just fail silently, but still fail to do whatever it was programmed to do. I'm thinking that you probably want to let your "backend" throw as many errors as it wants and write all the error catching at the application or request level, but I digress. :)I told Grant that I didn't have a good answer to this, but that I'd try and throw (heh, get it?) it out there for folks to discuss. I want to start this discussion by doing two things. First, lets try to clarify the question a bit. Secondly, be sure to notice he isn't talking about not caching bugs at all. He ends with mentioning error catching at the end. I think we can agree (or probably agree) that a naked error should never be shown to the general public.
So with that being kind of a base level assumption, how can we more narrowly define the problem? Given that we probably have multiple layers to an application (even if you don't use MVC, you are hopefully encapsulating business logic in CFCs, custom tags, UDFs), and given that an error can occur at any level, where is it appropriate to handle and "accept" that the error is Ok?
Let's consider an example of what an "Ok" error is. If your site makes use of an external RSS feed to display news items, I think you can agree that the failure of the RSS feed to parse, or respond, or whatever, should not be something that constitutes an error that should abort all processing.
Now let's consider an opposite example. He mentioned ORM so I'll use that. If your service layer was taked with using ORM to do some business process like authentication, most likely you would not want to catch that error. (By the way, as I'm writing this I can already think of reasons why you should - so keep in mind I'm just trying to come up with samples here. :) If it completely failed (like a bad table for example) then I think it makes sense to let the top level error management catch the error and present the user with the dreaded "Oh Snap!" error page. (Favorite feature of Chrome by far.)
I think it's also reason to expect that certain things should always work. For example, I expect my database to be up. It may not be, but under normal operating procedures, it will be up and if it isn't, I really do want my site to come to a screaming halt. However, I should not expect someones remote site (and RSS feed) to always be available. Therefore I'll add additional levels of error handling above and beyond my "final" catch all at the Application level.
Any one care to share thoughts on this? I'll use this opportunity to remind folks about my error handling guide, but it does not go into detail at this level. I would also love to hear non-ColdFusion thoughts as well. I've not yet done enough Flex/AIR work to get this deep into error handling, but if any of my readers have, please share as it would be an interesting perspective.
Archived Comments
Haha, I'll add the first comment, since it was my question. :) Just some examples / clarification of the different types of errors the ORM is throwing where I've thought, "huh... I wonder what's best".
Some are pretty fairly obvious, like form validation-type errors. These include errors like: ( of course ) data format validation that could have gotten by javascript, duplicate data errors [ thrown by DB indexes ], that CF should react to after the submission. These should be handled by display code.
The funny thing I noticed was that if I programmed my ORM to catch all the database errors with transactions and roll them back automatically, then nothing would happen on the form side.
The form would submit, and since my forms are so rockin' they would show the data the user just submitted, making it look like the user had a "good save". But really, the database rejected the submission and everything went "poof".
So, I realized that I had to let my Data Access Objects throw big nasty errors and let the form [ or hopefully in later versions ] some sort of event object collect those errors and do something with them, be it logging, alerting or what have you.
All of this seems pretty straightforward. We've probably all dealt with this many times. But the idea still floating around my head is a the need for a "error-catching design pattern".
I could go on about all the different types of errors and when they can happen, but that's outside the scope of this discussion. If I had a pattern, some way to classify errors, subclass them, and / or deal with them programatically, I'd feel a lot better.
@Ray... I think we're asking the wrong question man. I'm not very smart, but I've got that inking in the back of my head.
Something is saying to me, "some smart guy is going to read this and scoff, saying, 'you're asking the wrong question here'".
I'm not smart enough to predict what said smart guy is going to say the real question is, but I thought I'd throw it out there.
I don't think it's the wrong question at all, Grant.
When trapping a bad form input (invalid date got past the JavaScript, for example), then the error has to get back to the View layer in one way or another.
When trapping a bad data input (we already have that username in use in the DB ... valid format, but invalid data, for example), then we still need to throw a useful error back to the View, but we have to get down into the Controller and into the DB and back to the Controller to realize it's bad data.
There can be others, though, and sometimes I don't know there's going to be a problem until things are running, like Ray's example of a the bad RSS feed. The user really doesn't need to know "this URL is not available or doesn't appear to be valid XML or valid RSS format", but they probably would like to know something happened, like "Your news feed is currently unavailable". So, in the try/catch that's generically looking for 'problems with this feed', I like to return a standard message to the event model or the View, but I will also have a Notification widget that gets triggered on those, so that I can get the full cfcatch struct ... maybe I made my RSS parser too strict, or maybe this feed moved or maybe they switched to Atom and I didn't catch it. In those cases, I can do something about it, fix the problem, but again the user never saw the raw error AND it didn't really fail silently.
At the same time, I do NOT want an email every time someone tries to enter 2/30/2010 as a valid date ... I just need to make that one the user's problem.
Something I'm always wrestling with is how to gracefully show an error page when the error is in the framework.
For example, lets say that the main layout template has some variables that are initialized during some preprocess event, but the framework throws an error before those variables are created. i can't just show my error page (which uses the main template layout) then can I. Any good suggestions here?
I think that best practice is not to use try/catch except:
1. When accessing remote resources
2. When processing needs to continue even if there are errors
In all other cases, your code should be allowed to raise an exception to the application level. In the case of Coldfusion, that is Application.cfc's onError event handler.
It is important to remember that errors impact performance, whether you are using onError or try/catch.
When using try/catch blocks, I recommend setting up a notification system so that you know when those errors occur (since they won't be raised to the application level.) If an error occurs every time a piece of code is run, it should be fixed even if the error is "hidden" by a try/catch block.
When should you throw an error?
This is useful for logical errors, if you can anticipate them. Carefully consider the range of input your variables might have and the acceptable range of output. For example, a simple function that calculates BMI should throw an error if the result would be negative, rather than returning a value that makes absolutely no sense.
I think I just discovered a "rule" for the "try/catch" practice.
Rule #1: If writing a function to be called by other code, throw errors when function is called improperly.
Explanation:
Caller code should be able to see and react to this error, because otherwise "bubble up" effect would be lost and the caller could not reliably consume said function.
There may be caveats to this rule. Shoot holes in this if you can please.
Any ideas on how to try/catch an error when calling an external javascript? For example, we call a javascript file at traffic.com to display a traffic magnet. If their service fails or does not completely return all of the expected html, our page breaks as we end up with incorrect/incomplete html.
Javascript has try/catch functionality, but having incorrect/incomplete HTML might be different than a "hard" error.