Advertisements
Posted by: jsonmez | August 27, 2010

I am an Exception Extremist

Had a code review today, and I realized that I am an exception extremist, an exception bigot if you will.

I don’t like exceptions.  I’d rather throw up than throw an exception.

I have a rule, if you can detect the situation it’s not an exception and there are no exceptions to that rule.  (Okay, there is one exception I blogged about earlier, but it makes the code so much cleaner.)

Why I don’t like exceptions

Most of the time the way you find out an API throws one (at least in C#), is when your code runs in production.

Of course I also hate when I am forced to handle and exception in Java using checked exceptions.

One of the things I really don’t like about exceptions is that they break up the flow of the code.  Exceptions are essentially goto statements.  You can’t always know exactly where code flow will go.

I also really don’t like that when I handle an exception I have to declare my variable above the try catch block so that I can use it after the block.  I understand why I do, but I just don’t like it.  It makes me grumpy because now I have to try to initialize that variable to some default value that makes sense.

Exceptions also lead us to bad code that gets written like:

catch(Exception e)
{
   // LOL, I don't have to do anything with your exception.
   // I'll just eat it.  NOM NOM
   // You can't stop me, mwahahahahaha!
   // Why did you click that button
   // and absolutely nothing happened and there
   // was no error message either, and nothing in the log file?  LOL....
   // N00b... I eated it.
}

I don’t think I need to explain the above code more than it is already.

eatedit

Exceptions also send off false alarms.  I mean really, is it such a big deal that I passed you a string that has a dollar sign in it?  Can you not figure out that if I pass you “$3.00” and ask you to parse it as an integer that I want 3?  Give me a break.  When I see exceptions I think, “something really bad has happened that is likely to cause the very universe to become unmade.”  I don’t think “perhaps I left the dollar sign in my string.”

And the number one reason why I don’t like exceptions: “My inbox is full of them.”  Every place I work, it is the same.  Emailed uncaught exceptions.  Clearly throwing exceptions is not working too well.  Yeah, I know the system is throwing null pointer exceptions, and you can’t do much about that.  (Except maybe, hmm I donno let’s ignore method calls on null objects…)

What to do instead?

Well, there are a few lines of defense we can throw in before waving the exception flag.

  1. See if you can actually do something smart with the data.  For example, if you are writing code to parse a string into a number, can you ignore non-numeric characters?  Sometimes the answer is no, but many times you can figure out a way to work with what you got.  If you can find a way to proceed forward without throwing an exception do it.
  2. If you’re returning back some data, return back some default or empty value.  (Not null though.)  This doesn’t always make sense, but it can be nicer than throwing an exception.
  3. Give the caller a way to check for success first.  Returning a result code from your method is probably bad.  But, if you let me call something first to validate my input, at least I can handle the problem there.  Consider the tryParse methods in the .NET framework.  They let you check to see if something will parse instead of throwing an exception if it won’t.
  4. If the exception didn’t originate from your code, try and handle it in your code first.  Is there a way you can deal with the exception, instead of just rethrowing it or wrapping it?
  5. If you are not exposing an external API, try to use some sort of error collection, or error property you can check on your class to indicate a failure occurred.

If you must, (and sometimes you must)

  • Don’t rethrow a system exception.  The exception should match your level of abstraction.  Wrap the exception (keeping the call stack intact) and then throw it.
  • Don’t throw 50 million different kinds of exceptions.  No one likes to catch all your many exceptions.  You can always include details in the exception to say what specifically happened incorrectly.

A coworker of mine had a really good point.  He said that it depends on your perspective.  You might have to think as if you were someone using your API.

What is the most obvious thing to do?  Would you expect a call to silently fail or to throw an exception?

It is worth thinking about from the user of your code’s perspective.

It’s pretty fair to say that I am still pretty undecided on this topic.  I really don’t like exceptions, but I also don’t like calling a method in an API and then calling another method to check for error conditions.  And I certainly don’t like error codes or booleans returned from methods to indicate failure or success.

What do you think?

As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple.  Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week.  Also, you can follow me on twitter here.
Advertisements

Responses

  1. Hi John,

    Great post, but I’m not sure I understand why you don’t like error codes or booleans returned from methods to indicate success/failure. If the method failed, why is calling a separate method to check the error condition better than just returning a boolean or meaningful return value?

    Thanks,
    Bill

    • Great question Bill,

      I should have addressed it in this post, but it could be a post itself. I’ll try to give you the short of it. (Also take a look at the link in my post above.)
      Basically it comes down to single responsibility. A method should do one thing and only one thing. It may seem a bit picky, but a method should not do something and return a boolean value.
      There are methods that are command and methods that are queries. If a method is a command, it should not return information also.

      For example, let us say we have a method SaveToPDF(). That method shouldn’t really be returning anything, because it is a command. It is tempting to return a boolean to indicate whether the method failed or passed, but doing so makes the method responsible for saving a PDF and providing information. It might not be obvious to the caller of that method what the return value indicates.
      The alternative would be a method callled, IsSavedAsPDF(). In this case we are querying to find out if something was saved as a PDF. It would be very strange if that method actually did a save, or did something else other than a simple query of that data.

      The problem also is that error codes end up having to be chained down. If you pass back error codes, refactoring really becomes a nightmare (especially when dealing with nest loops and early returns.) This part I show an example of in my post on not chaining error messages. (Above)

      Consider also HRESULT in COM programming. This is the extreme of returning error codes. Every single call you make in COM you get back an HRESULT which you have to check for failure. COM code becomes unbelievably painful to write and modify.

      I don’t really like having to check another method for error conditions either, but it really makes more sense form a single responsibility and command and query separation viewpoint.

      When you think about it though, no matter how you slice it, you have to remember to do something:
      If you throw an exception, someone has to realize they need to put a try catch block around it.
      If you pass back a boolean, someone has to realize that they need to check the returned value.
      If you set a flag on the object, someone has to know to check that flag after making the call.

      The only alternative I can think of is to do something like this:
      void SaveAsPDF(string FileName, IPDFErrorHandler errorHandler);

      Then you force the user of you method to consider the case and handle it. This seems somewhat extreme. I don’t think this problem will be solved except by language design.

  2. Hi there. I don’t have any wisdom to impart, but wanted to say how much I enjoy your thoughts on programming, which align very closely to mine even though I haven’t been active in this space for a few years now.

    It is always a pleasure to read you, and I imagine (I hope!) that your words will get others to think about the code they write in such thoughtful ways. There is something very elegant about your approach, and our industry needs lots more of the same.

    • Thank you very much. I am just glad that I can be of help to people. I really appreciate your encouragement.

  3. I have written quite much C/C++ and I have never liked exceptions. They’re ugly.

    In C/C++ you can often get away w/using return values and something akin to exit_unless(cond, rv, format_string, …), because if you’re programming in the Unix-style, you will have several small binaries anyway. Just make your exit_unless print out the file, line and the offending variable values to log or stderr and it often works just fine. Some control module can then also catch the exit signal from the binary and can decide what to do about it.

    This might not work as well in Windows, because I guess people often use there one big binary which you cannot just exit safely w/o bringing the whole program down. Surely this is also true for many modern languages and systems as well.

    Then again, this is just a different way of using an assertish/exceptionish mechanism. I just like it better because it doesn’t add try { … } catch – ugliness into the code. And maybe I’m just used to it. Anyway, this is one possible way of getting around exceptions in a specific domain.

    Many times it also makes no sense anyway to try to handle the error outside of the context where it happened in the first place.

    I’m not instantly a fan of IsSavedAsPDF(). Let’s say that we have some kind of a general service that lets you save PDF:s. Let’s say you call it like this:

    Storage.saveAsPDF(foo)

    Then, if you call Storage.IsSavedAsPDF(foo), storage actually needs to store information somewhere to be able to tell you. I find this a bit odd, because it’s a generic Storage helper. It should not care about what it stores.

    Then, if you have an object that can save itself as PDF:

    Foo.saveAsPDF()

    Fine. Now you can call Foo.isSavedAsPDF() and it can tell you how it went. However, when I see that object, I instantly wonder what that isSavedAsPDF is supposed to mean? If I’ll save the PDF now and call that functions a week later, will it still return true? If I save again, will it just keep on returning true?

    Of course, that’s not a real problem, but something about the above somehow still bothers me.

    If, however, you just return a value and write:

    if(whatever.saveAsPDF()!=true) { … }

    there is no possible disconnect from the time of calling. It is obvious that you are referring to this very PDF right now.

    Exceptions and exits also satisfy this time-relatedness. They both fire at once if things did not go well and they don’t give you an odd method that gives you this odd feeling about not being quite sure when it’s okay to call that functions and what it means if you call it now or at some other time.

    Anyway, having said all this, I think I have thought about this in depth a few years ago and if memory serves right, I came to the conclusion that there just is no way around the issue.

    If you take the approach that you will have to make sure that things went well, this is the return values path.

    If you take the approach that you assume things go well, you will still have to be somehow able to signal when they don’t. This is the exceptions/assert/exit approach.

    In both of these cases you almost always have to detect the failure at once and deal w/it right away. So the context where to respond to the issue is right there and right at the time when it happened. That is where you (hopefully) have all the information about how things were when something went wrong.

    I understand very well what is your objection to all this. It is not beautiful. And programs should be beautiful. Having to handle the errors makes the program less readable, less clear and therefore makes it look like a beautiful novel that has all these pencil markings between the lines speaking of things that can go wrong that have nothing to do w/the actual storyline.

    In a perfect world disk space would be infinite and network access always there. Hosts would never go down and malloc would never return null. Sadly, this is something that will be the assumptions made in a university course book rather than in this oh-so-imperfect reality which we inhabit.

    In a way needing to handle errors is an offense against perfection and this is what we dislike. We came up w/the concept of god to express that which is perfect and this perfection we love. We would like our creation to resemble this god as closely as we can ever make it.

    In this ugly world we ache to create something beautiful and perfect and in our effort to do that through programming we’re being torn down by the very reality we wish so desperately to escape.

    Sounds like a Greek tragedy. 🙂

    In any case, every time I see really beautiful engineering I am deeply moved. I really loved the bridge in France that the Romans built that stood there unmaintained for a thousand years.

    • Interesting points. And I think you are right about there being no easy way around this. It is a problem that I think will have to be solved at the language design level.

      It is worth thinking about and knowing what the choices are so that at least we know what the consequences of those choices are and the alternatives.

      Thanks for your reply.

  4. […] This is from a reply I wrote to: I am an Exception Extremist […]

  5. I agree in the broad sense of your post. The dollar example you give is so common that it still makes my eyes bleed.
    However, there are different uses for exceptions.

    At our current project, we’re writing webservices for a windows client. We write WCF services in .net, the client is a fancy 3D winapp written in C++.

    Whenever a request is sent to our service, the happy path is always easy to handle: get some stuff from the database, do something with it, return some data.

    However, when something can’t be done, we want to notify the client app as to what was the reason it couldn’t be done. Things like: “user is not subscribed to this service”, “quota has been exceeded for this month”, “the picture you’re uploading is showing too many kittens” (made that one up ;-).

    These are data specific things that can happen, but you don’t want these specific to clutter up the happy path in your code. The code should be as readable as possible and throw an exception as specific as possible. This exception should then bubble up to the top of the call stack, where a generic exception handler will translate it to something the consumer of your service will be able to understand.

    • Hmm, I can definitely see your point about not cluttering the happy path. The only problem with that approach is that exception throwing and handling really becomes flow control. The exception is being used as an immediate return.

      Not that that is in itself bad, it is just not ideal. The way you describe the problem you are facing, I think I would probably choose the same solution. Thanks for the input.

  6. Hi John,

    I have to second Tobias’ comments above.. Your posts are always funny, informative and most of all, practical. I found myself at work yesterday with “Pulling out the Switch” open on one monitor, and an epic switch (which has since departed this world) on the other. Was very helpful! Thanks for your witty insight; it’s always an enjoyable read.

    Matt.

    • Thanks very much for the encouragement. It really motivates me to keep blogging and doing the best I can at it.

  7. Very good post. I follow mostly the same principles. But actually, I quite like exceptions in a strange way, mostly for the same reasons you ‘dislike’ them 🙂

    I tend to think of exceptions of ‘freeing’ me from verbose error handling code. Design By Contract is my guiding principle there. When you call my API and you don’t live by the rules, I will throw an exception. This typically makes my code down the line much easier to write and maintain, because I don’t have to handle invalid input over and over again.

    OTOH, as the consumer of an API, I actually try to NOT care about exceptions. I try to program in a robust way (checking arguments before calling a method), but I *want* to rely on exceptions being thrown if I make a mistake. Of course, the fix should not be to add an empty catch block, but instead investigate what’s happening, and probably add some input validation logic + error reporting. Only in very specific cases I really need to write a try-catch.

    Obviously, a good “unhandled exception” report is also crucial. By the time we go to production, this report should be mainly empty, and only the exceptions that are really unhandled should be reported.

    Following these rules, you can generally avoid exceptions altogether. But I guess what I’m trying to say is this: without the framework providing us with the concept of exceptions, our code would be way uglyer. That’s why I really *like* exceptions.

    • You make a pretty compelling argument there. I can definitely see how passing the burden of responsibility to the caller of the API make the code much more simple. I’ll have to think about that some.
      There still is a distinction in my mind between true exceptions and the language feature of try catch blocks.
      I can understand not catching an exception that might be thrown from an API you are calling, but what if that API is that for the file system, where regardless of what you pass in an exception could be thrown for some other reason (a true exception?) At that point, it seems like you must catch those exceptions and do something rather than wait for it to blow up?

  8. What do you do when you *can’t* do anything? You’ve no doubt seen the idiom:

    void DoSomething(object o) {
    if (o == null) { throw new ArgumentNullException(“o”); }
    // …
    }

    If you *require* o in order to complete, there’s not really much you can do. You can ignore the call, but then you’re not living up to your end of the deal.

    Hopefully design by contract may helps with this in the future.

    • I’m definitely not a fan of checking for nulls in parameters passed in.
      Unless you have some automated way of doing it, it is just a waste of time and adds a huge amount of code bloat.
      I put the burden of responsibility on the caller, because I think that is where it belongs. If you call a method that requires o and you don’t provide o, what do you expect to happen?
      In that case throwing a null pointer vs specifically throwing an AgrumentNullException doesn’t make much of a difference to me, except one doesn’t require any code to do.

  9. jsonmez, I coded RPG back in the 1990s and from your post, I can tell you think just like an RPG programmer. Your statement “You can’t always know exactly where code flow will go.” is absolutely wrong. Any competent programmer can follow flow of execution. If you can’t figure out flow of execution when an exception is thrown, then you shouldn’t be coding – give management a try PLEASE!

  10. Uncaught Exception: BlogTextOverflowException

  11. Geez, I don’t know why this post is getting so much hate from DZone. I’ll say now that I fall in the ‘is not a fan of checked exceptions’ camp (and I’m a Java programmer). This mostly comes from having been put into work supporting large systems where checked exceptions are abused to the point of being a return value all of their own, like adding a 3rd value to a boolean: TRUE, FALSE, and FILE_NOT_FOUND_EXCEPTION.

    • Emanuel –
      Developers shouldn’t need to write a lot of code that catches exceptions.

      The most common way of handing Exceptions is to let them bubble up by adding a ‘throws xxxException’ to the method definition but the suggestions in the original post ignore this. The suggestions given in the original post include wrap the Exception, do something with the data and try again, return an ’empty’ value.

      I don’t want an empty value returned to my code in the place of an Exception. I want my code to be rudely notified so that my code will exit the happy path thus preventing bad data from making it into the database. Exceptions are one of the best parts of Java.

  12. I love exceptions. I don’t use code contracts yet, but think most of the ‘throw new …’ statements will go away when I start using Code Contracts.
    I want to have an exception thrown when something goes wrong straight away e.g. when withdrawing more money than an account has. If the model has the knowledge how to deal with such scenarios then they will be implemented. If not – then goodbye and go find the bug in the calling code as the current method is not the place to implement something smart that will hide the bug higher in the call stack.

    Exceptions is a great mechanism. What sucks is the poor usage of them.

  13. I think returning a bool for success is about as simple as you can get and worrying about seperation of concerns here is overkill – and decoupling action and error is just asking for trouble for multi-threaded code.

    > The only alternative I can think of is to do something like this:
    void SaveAsPDF(string FileName, IPDFErrorHandler errorHandler);

    I think not just an errorHandler is important, but a normal-case continuation handler which can use fn ptrs/delegates/lambdas, etc. – but both is handy. Consider (using (mostly-correct) C# named args and lambdas):

    SaveAsPDF( doc,
    err: e => showMsg(“Doh!” + e.Problem));

    or to use both continuations:

    void SaveAsPDF(string doc, Action fnOk, Action fnErr)
    {
    exportToPDF( doc,
    err: er => showMsg(“Can’t export: ” + er.Problem)
    ok: pdf => saveFile( pdf,
    err: er => showMsg(“Can’t save: “+ er.Problem),
    ok: return fnOk(pdf));
    fnErr( new Error(Problem:”Can’t save PDF file”));
    }

    Using continuation-passing style solves most all the problems – and there’s not one if statement in sight.
    (You do get “indent creep” to the right for normal control-flow, however. This can be mitigated depending on the language your using (F# computation expressions) or by formatting or preprocessing.)

  14. Lost all my indents, and getting badf word-wrap…


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: