Thoughts on successful exception handling
In the last article, a (very) brief introduction to the benefits of exceptions, we saw that exception handling may produce more efficient and stable code. The example was kept simple enough to provide an operation breakdown on how exceptions basically work. This article will explain how exceptions may be used for greater benefits, how programs and program parts get more stable using exception handling and how exceptions and parts of the programming efficiently interact with error handling and each other.
Why exceptions?
As stated before, many coding efforts directly flow into error handling in general. In case a simple "or die" expression is not enough when an error occurs ("or die" just stops processing of the program-code at once), exception handling provides useful mechanisms to write code that may handle the erroneous behaviour or helps finding the cause of it.
Following the IPO principle, errors in programs or program parts do occur because of a flaw in programming or incorrect input to the program / program part. Assuming we only take a single method call retrieving parameters, the following conditions which result in wrong output can be classified:
How exception handling is done (right).
Using exception handling is as simple as that: If you write a method and you are able to handle the behaviour without breaking the flow of your code or stressing external logic through "workarounds", you do not need exceptions at that place. The time you wonder about how you may "get this check of a variable/state into an if-then-else" - construct or you rely on methods or (external) resources which may throw exceptions of their own it's another part of the story.
Before your code gets overly complicated throw an exception. You then surely can determine the place where the exception will be thrown and, because of try-catch - blocks, you always have a defined place where your exception and the execution of your code will lead to.
And you cannot handle every error, better: exceptional behaviour, at the place it (immediately) occurs. If you write a method that, say, reads some file content and returns it as a string, and you do not exactly know from which routines this method will be called in the future, then you should let pass or (re)throw the input/output exception as it occurs in your method. What good is it to return an empty/null string if an error happens? Firstly, you will have to check for a null pointer reference anyway, otherwise the surrounding code will not work properly either. Most times checking for a null reference is as verbose as catching an exception. On the other hand, if you don't throw an exception, does returning an empty (not null-) string mean that an error occured or that the file was "empty"?
Take your time and rethink if the method where the error happens really has all informations to react accordingly or handle that error. Else (or if you are not sure how to handle this kind of exceptional behaviour at that place) throw an exception.
And never forget: If you decide to throw an exception, be as precise about the error as you can be. If your language accepts an error message to pass with the exception, make it as accurate as possible. If the language allows to specify different exceptions or even subclass exceptions, be as precise in selecting the type of the exception as possible.
Somewhere ... by and beyond exeptions?
Do not listen to people who argue that exceptions are (time-)expensive. Firstly they are right, no argument needed. But the benefit of clear, more stable and readable code leaves enough time for you to optimize your algorithms on other places more needed. Remember that exceptions represent "exceptional behaviour", they represent erronous states which only happen in special erronous cases. Ordinary spoken: If you do not throw exceptions to just simply leave a loop or code block you will be fine on the performance side of life.
And there are a couple of open points and additional benefits introducing concepts like exceptions. Some of them, more or less tightly married with exceptions, are thingies like stacktraces where you can follow the whole way of the exception through the complete code (in most languages introducing exceptions), finally-blocks and (in a certain way) assertions and closures. But handling these issues would blast this article.
Alas, one controversially discussed exception technique, the so called checked exceptions of the programming language Java, should at least be mentioned here to round off.
Checked exceptions are exceptions you have to catch or, via definition, throw up to the next ("calling") instance. A method, for instance, that does not want to catch the exception on it's own has to declare that the exception which then has to be catched from the caller of the method by default - if not, the compiler will not compile the code. This is a very controversial issue within the (Java-) community because the need to catch checked exceptions naturally leads to more programming overhead. But again, the compiler tells you that the programmer of the method wanted you to explicitely respect that this kind of exception(s) may occur - and you have to deal with it. Integration might be tough, but at least you know about the possible exceptions without consulting the documentation simply by compiling your code. I, personally, had my difficulties accepting this feature, but at least the advantages had beaten the "programming verbosity" pants off for me and I think you will love this feature as it follows your way in larger projects.
So, go on throwing exceptions, and may the catch be with you!
Why exceptions?
As stated before, many coding efforts directly flow into error handling in general. In case a simple "or die" expression is not enough when an error occurs ("or die" just stops processing of the program-code at once), exception handling provides useful mechanisms to write code that may handle the erroneous behaviour or helps finding the cause of it.
Following the IPO principle, errors in programs or program parts do occur because of a flaw in programming or incorrect input to the program / program part. Assuming we only take a single method call retrieving parameters, the following conditions which result in wrong output can be classified:
- The parameters given to the method are not well defined (i.e. are wrong or empty / null where they must not be)
- The "constellation" of the parameter values are not expected in the given way by the method (because if parameter "a" has a certain value, "b" must not be of another certain value)
- The caller of the method simply calls it in an improper way (i.e. the environmental conditions are not correct, needed resources are not allocated yet etc.)
- The method allocates external resources (i.e. open connections, file handles etc.) and does not free them (thus leading to an invalid internal state of the program, the operating system or other components like databases)
- The method relies on external resources (i.e. file system, database etc.) which are not available at the moment they are needed
- The method and therefor it's programming trusts on an internal state that is not correct (i.e. corrupt data/instances needed to compute the result)
- The method contains a programming error
How exception handling is done (right).
Using exception handling is as simple as that: If you write a method and you are able to handle the behaviour without breaking the flow of your code or stressing external logic through "workarounds", you do not need exceptions at that place. The time you wonder about how you may "get this check of a variable/state into an if-then-else" - construct or you rely on methods or (external) resources which may throw exceptions of their own it's another part of the story.
Before your code gets overly complicated throw an exception. You then surely can determine the place where the exception will be thrown and, because of try-catch - blocks, you always have a defined place where your exception and the execution of your code will lead to.
And you cannot handle every error, better: exceptional behaviour, at the place it (immediately) occurs. If you write a method that, say, reads some file content and returns it as a string, and you do not exactly know from which routines this method will be called in the future, then you should let pass or (re)throw the input/output exception as it occurs in your method. What good is it to return an empty/null string if an error happens? Firstly, you will have to check for a null pointer reference anyway, otherwise the surrounding code will not work properly either. Most times checking for a null reference is as verbose as catching an exception. On the other hand, if you don't throw an exception, does returning an empty (not null-) string mean that an error occured or that the file was "empty"?
Take your time and rethink if the method where the error happens really has all informations to react accordingly or handle that error. Else (or if you are not sure how to handle this kind of exceptional behaviour at that place) throw an exception.
And never forget: If you decide to throw an exception, be as precise about the error as you can be. If your language accepts an error message to pass with the exception, make it as accurate as possible. If the language allows to specify different exceptions or even subclass exceptions, be as precise in selecting the type of the exception as possible.
Somewhere ... by and beyond exeptions?
Do not listen to people who argue that exceptions are (time-)expensive. Firstly they are right, no argument needed. But the benefit of clear, more stable and readable code leaves enough time for you to optimize your algorithms on other places more needed. Remember that exceptions represent "exceptional behaviour", they represent erronous states which only happen in special erronous cases. Ordinary spoken: If you do not throw exceptions to just simply leave a loop or code block you will be fine on the performance side of life.
And there are a couple of open points and additional benefits introducing concepts like exceptions. Some of them, more or less tightly married with exceptions, are thingies like stacktraces where you can follow the whole way of the exception through the complete code (in most languages introducing exceptions), finally-blocks and (in a certain way) assertions and closures. But handling these issues would blast this article.
Alas, one controversially discussed exception technique, the so called checked exceptions of the programming language Java, should at least be mentioned here to round off.
Checked exceptions are exceptions you have to catch or, via definition, throw up to the next ("calling") instance. A method, for instance, that does not want to catch the exception on it's own has to declare that the exception which then has to be catched from the caller of the method by default - if not, the compiler will not compile the code. This is a very controversial issue within the (Java-) community because the need to catch checked exceptions naturally leads to more programming overhead. But again, the compiler tells you that the programmer of the method wanted you to explicitely respect that this kind of exception(s) may occur - and you have to deal with it. Integration might be tough, but at least you know about the possible exceptions without consulting the documentation simply by compiling your code. I, personally, had my difficulties accepting this feature, but at least the advantages had beaten the "programming verbosity" pants off for me and I think you will love this feature as it follows your way in larger projects.
So, go on throwing exceptions, and may the catch be with you!
Labels: exception handling, exceptions, thoughts
0 Comments:
Post a Comment
<< Home