The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Status codes or Exceptions

Hi,

We are building C# web application, which is expected to have UI, object and service-oriented layers.

There was a long design session with in-house and Microsoft architects and one of solution I was not quite happy about was a choice between status codes and exceptions.

For example standard method signature will look like this:

--- With status codes --------------------------
public StatusCode MethodName(parameters);
public StatusCode[] MethodName(parameters);

--- With exceptions ----------------------------
/// throws ExceptionA, ExceptionB
public void MethodName(parameters);

I believe Joel's forum attracts very experienced people and most of you had problems with one or another way of doing things in dot-Net.

Any personal experience you had with any of two approaches or just a link to relevant discussions/articles would be really appreciated.

Thanks a lot.
DK
Monday, March 28, 2005
 
 
No codes. All the information should be in the exception. Make a generic exception instead of lots of overly typed exceptions. Chain exceptions together so you never lose the stack and context to the top.

Why? Status codes can be ignored. Status codes don't have to be caught. Codes change values over time. Status codes don't have enough information in them to do you any good. Exceptions can be extended at any time with more information. Adding a new exception is less likely to break code, depending on the exception hierarchy.

The array of status codes defies belief.
son of parnas
Monday, March 28, 2005
 
 
I think it was Pragmatic Programmer that said "exceptions should be used for the exceptional". I use exceptions for actual errors and things you normally don't expect (file not found, memory full, file not in an expected format), and use status codes for normal behavior.

If you can afford the cast, create an enum of codes, and use this as your return. Which is what it sounds like you are doing with the StatusCode.

Ha. Found it.

http://www.pragmaticprogrammer.com/ppbook/extracts/rule_list.html

Also with C#, there's overhead in exiting the try/catch block.
moron
Monday, March 28, 2005
 
 
The pragmatic web page didn't actually explain anything.

> Also with C#, there's overhead in exiting the
>try/catch block.

That's a really poor reason.
son of parnas
Monday, March 28, 2005
 
 
The web page pointed to what I was remembering. They give a bit more detail in the book.

Our host on status codes/exceptions.
http://www.joelonsoftware.com/items/2003/10/13.html

Another interesting article, although of limited relevance
http://c2.com/cgi/wiki?DontUseExceptionsForFlowControl

Arguments for exceptions.
http://discuss.joelonsoftware.com/default.asp?pg=pgDiscussThread&ixDiscussTopicParent=17954&ixDiscussGroup=8

>> Also with C#, there's overhead in exiting the try/catch block.
> That's a really poor reason.

That's a really poor argument. Doesn't it depend on the frequency of how often the exception is expected to be handled? I ran a test, triggering an exception every time, looping 50000 times. 1 second (status codes) versus 70 seconds (exceptions). Once every 50 times, the exception code's time was reduced from 70 seconds to 4. Better, but still a factor of 4.
moron
Monday, March 28, 2005
 
 
> Doesn't it depend on the frequency of how often
> the exception is expected to be handled?

It sounds like you are considering using exceptions for control flow. That i don't think is a good idea either. But status implies status, not control. If something worked then you should should get a valid result object back and the code is straight line from then on. Otherwise the exception should get trapped at whatever layer gives a damn. Having a status code for each condition like file didn't open for permissions, doesn't exist, etc leads to a tangling of concerns all the way up and down the application stack.
son of parnas
Monday, March 28, 2005
 
 
I'm on the side of those who say that exceptions should only be used for exceptional conditions. The problem is that often it's the caller of a function who knows what's an exceptional condition and what's not, not the author.

Case in point: I often want to know whether a string that the user gave me is a valid date and time. I don't care about the actual DateTime value. That's some other code's problem. For me, the string not being convertible to a DateTime is not an exceptional condition. Rather, it's part of normal program flow and something to be expected. I'd like to write this:

if !System.DateTime.IsValidString(str) then
  ' complain and fail
end if

But I have to write this:

try
  System.DateTime.Parse(str)
catch ex as System.FormatException
  ' complain and fail
end try

It's not much more code, but it obscures what's going on. Because I'm forced to use exceptions for flow control, it's not obvious at a glance that the whole point of the code is to find out whether the string is convertible to datetime.

Conversely, I'd be pretty upset if I had to explicitly check for failure in code that has reason to assume that the supplied string is convertible to datetime. In this case, the best thing to do would be to provide both functions.
comp.lang.c refugee
Monday, March 28, 2005
 
 
Son of Parnas, I disagree with your advice to "make a generic exception instead of lots of overly typed exceptions". The problem with that approach is that it's not possible to catch certain types of errors but ignore others. I appreciate being able to write fine-grained catch statements when appropriate.
comp.lang.c refugee
Monday, March 28, 2005
 
 
> , I disagree with your advice to "make a generic
> exception instead of lots of overly typed exceptions"

If there is one you want to catch then make a specific derived class from the more generic class. Otherwise you get dozens of exception classes and that's not so good.
son of parnas
Monday, March 28, 2005
 
 
Don't forget why exception handling was added in the first place. It was added to FIX the issue of constantly having to deal with status codes for every function you call.

There has been some good advice given here:

1) Exceptions should be for exceptional conditions.

2) Don't use exceptions for program flow.

3) Exceptions should be caught by the layer that intends to do something about it.

With all of these in mind, there is no single correct answer. There will be times when you use exceptions and times when you use status codes.
matt
Monday, March 28, 2005
 
 
I'd say read "Object Oriented Software construction" by Bertrand Meyer - Prentice Hall, ISBN 0-13-629155-4,  which will give an understanding of (IMNSHO) good object oriented design, and reasoning behind the methods being advocated.
 
Use exceptions for the exceptional is the short way of saying a great deal.

If you design your system using a design by contract method, then you have as part of your design a definition for each class as to what it should be able to deal with and thus the other things that are exceptional.

It is a better design for instance to have a method for finding if you can withdraw the money from an account
 a.canWithdraw( 500 )
and if you can deposit
 b.canDeposit( 500 )
and then performing a transfer
 a.withdraw( 500 )
 b.deposit( 500 )
than it is to get to the point of depositing and finding a problem
 if( withdraw( acct1, 500 ) )
  if( ! deposit( acct2, 500 ) )
  // put it back!
    if( ! deposit(acct1, 500) )
      // uhoh, now what?

exceptions should come from breaking preconditions or postconditions.
you should have normal control structures for handling normal control situations.
gorf Send private email
Monday, March 28, 2005
 
 
>> Exceptions should be for exceptional conditions.

What exactly defines "exceptional"? To me, I may be expecting a properly formatted string and then in that case, it would be quite exceptional to see I received a malformed one. So, how do you seperate whats exceptional from what is code flow?
Anon Coward
Monday, March 28, 2005
 
 
I use status codes whereever possible.  I make a point of actually checking those return codes too.  But then, I write code that has to function in low memory conditions etc, so resource constraints and other stuff are not so "exceptional".

My compiler warns me if I ignore a return-value.  Yours does too, if you have the right warning level set.
i like i
Tuesday, March 29, 2005
 
 
> > Also with C#, there's overhead in exiting the
> >try/catch block.
>
>That's a really poor reason.

That depends on your environment.

Tuesday, March 29, 2005
 
 
I think Anon Coward brought up a good point - what is "exceptional". To me, the answer is "it depends".

Take the "improper date format" error. If this is called internally and the front end does validation, then it could be handled through an exception. If the input is coming from raw keyboard input, then that condition is moving from "exceptional" to merely "uncommon".

McConnell says "exceptional" equals "events that should never happen" (emphasis on never). What do the status codes actually signify? Is it "disk full" or "memory full", or a more prosaic "out of inventory" or "value out of range"?

Also (to the OP), if you're going to a true SOA, you may end up needing to create status codes anyway - AFAIK, exceptions don't travel too well through an HTTP channel unless you serialize them.
moron
Tuesday, March 29, 2005
 
 
> But then, I write code that has to function in
>low memory conditions

So do i. I have a fixed size memory pool of exceptions so memory is never an issue. I have seen too many status codes ignored to be so accepting.
son of parnas
Tuesday, March 29, 2005
 
 
"That's a really poor argument. Doesn't it depend on the frequency of how often the exception is expected to be handled? I ran a test, triggering an exception every time, looping 50000 times. 1 second (status codes) versus 70 seconds (exceptions). Once every 50 times, the exception code's time was reduced from 70 seconds to 4. Better, but still a factor of 4. "

OK, so the exception implementation costs roughly 1.4ms per pass.  How does that size compare to the overall time of your transaction?  That's really what it depends on - how significant a difference it makes in your actual context.

Certainly, if you already prefer status codes, this is good news.  If you prefer exceptions, I wouldn't expect that "consistency plus occassional performance benefits" trumps the counter arguments.
Danil
Tuesday, March 29, 2005
 
 
You're right, Danil - it's a matter of context and tradeoffs. I'm not saying "use status codes" - frankly, I don't think I have enough information to answer that question beyond an "it depends." 

The thing I wanted to point out was in C#, there can be a significant time lag if you use exceptions as opposed to status codes. That needs to be taken in account (along with other factors, like code readability, ease of use, maintenance, etc.) when the poster decides what to do.
moron
Tuesday, March 29, 2005
 
 
I'm not understanding the claimed "time lag".

Just wrapping code in a try-catch does not cause a significant amount of overhead (3% or less from my tests). It is only when an exception is actually THROWN that there is significant overhead because you are creating a new object, assigning the stack trace, and unwinding. If you keep in mind that exceptions are only for "exceptional conditions" (things that rarely if ever happen), then there is virtually no overhead at all. This assumes that you are not using exceptions for things that happen thousands of times a second or even several times a minute. But then those aren't "exceptional conditions" then are they?

Also, I could argue that there are times when a single try catch block around a group of function calls would actually be faster than multiple status code tests. It all depends on whether or not exceptions are thrown and how many status tests you would be performing without the try-catch handling. As many have said here... "it all depends".
matt
Tuesday, March 29, 2005
 
 
By the way DK (OP)... which way did the Microsoft people recommend? Which way did you prefer? You said that you weren't very happy with the decision.
matt
Tuesday, March 29, 2005
 
 
I agree that we don't have enough information.

But what questions would we need answered to have enough information?  Branch frequency, proximity of the error to the reporting/recovery mechanism(s), amount of drag imposed by using each technique in the language of concern (generalizing away from C#)....
Danil
Tuesday, March 29, 2005
 
 
matt--

To clarify about the time lag, you are correct - the lag only occurs when an exception is thrown (in the test I ran, if you go from throwing an error every time to only throw 1 in 50 items, the lag decreased significantly). Merely placing a try/catch block around the code is insignificant, resource-wise (then again, making a case statement to report a specific status code probably is just as insignificant, resource-wise).

You say: "If you keep in mind that exceptions are only for "exceptional conditions" (things that rarely if ever happen), then there is virtually no overhead at all."

I agree, but son of parnas made a blanket "use exceptions". Not "use exceptions if the status code only reports exceptional conditions". I was merely pointing out a reason why you don't want to use exceptions except when something that shouldn't happen happens.
moron
Tuesday, March 29, 2005
 
 
First, thanks a lot for taking time and sharing your thoughts and experience - it is really inspiring. If you have other examples or strong opinion - please, voice them.

Now we have at least three ways:
  1. No Codes (son of parnas, pro-exception link in moron’s post)
  2. "Exceptions for exceptional situations" (comp.lang.c refugee, matt, gorf)
  3. No Exceptions (moron, Joel, i like i, Danil?)
…and I apologize if I misunderstood anyone.

Of course, "pure" solutions (1 and 3) are not so pure in all situations: e.g. with windows development you would hardly avoid status codes in Win API or exceptions in dot-Net framework. So, as Joel put it - (3) would actually mean "Never throw an exception of my own".
 To make things worse, developer sometimes want to extend framework or external components functionality and add new methods, which would behave similar to original API, but that's “yet another topic”.

If I'm getting it right, the argumentation for status codes is based on the ability of precise control of errors after each method call and fixed execution flow. Arguments against them are the requirement to actually handle status codes for each method call, requirement to revalidate handling mechanism for each new or modified status code, restrictions applied to method signature and that codes can convey only limited amount of information.

Exceptions on the other hand were introduced to fix limitations of status codes (thanks, matt, that is really strong point) for the price of tolerable performance overheat. Against exceptions stands the potential of misusing them for control flow as opposed to error handling and performance overheat.

It looks like both status codes and exceptions have their followers here. We can probably agree that the choice of using either one approach (or some mix between them) is situational and depends on development priorities, experience, application design, used frameworks/components/libraries etc.

All points in this thread were quite interesting, but I’m scared to go into huge discussion over them (though not as scared as of 1200-pages book that gorf suggested. The book is very interesting by the way, and it looks very useful … both for studying OOD and for self-defense ;). Andrew Hunt and David Thomas (thanks, moron) with their "The Pragmatic Programmer" series are not that straightforward – their opinion is stated differently in different books - in Ruby book they recommend to abandon status codes, while in “Jorneyman to Master” coin that catchy phrase “Exceptions for Exceptional Problems”. I have no idea how they can be this productive with publishing - their other book “Pragmatic unit testing in C# with nUnit” is exactly what I wanted now.

Anyway it is still open questions for me when exceptions introduce more performance overheat then status code handling or if it is appropriate to use Parse method for validation instead of parsing (and yes, I don’t understand why dot-Net framework does not have method IsValidDateTime(string)), but fortunately in my concrete case these are lesser issues. Main consideration is maintenance overheat and design limitations of status codes against potential misuse of exceptions for flow control.
DK
Tuesday, March 29, 2005
 
 
Hi, matt

matt> By the way DK (OP)... which way did the Microsoft people
matt> recommend? Which way did you prefer? You said that
matt> you weren't very happy with the decision.

In our case, which is multi-layer c# e-commerce application, I believe there should be significantly more development and maintenance efforts if we will go with status codes as opposed to the amount of work to create exception management components.

Personally I was quite shocked, by the amount of discussions in internet forums devoted to (mis-)using exceptions for execution flow control, which seems like a main argument against exceptions. Perhaps this is less of an issue in big projects, when all exceptions developer is allowed to throw from his code are limited to specific custom base type and there is no room for ControlFlowException type.

It might be a good idea to add to developer guidelines document some criteria of “exceptions for exceptional situations”, statement that “component should either throw some specific exception or catch it, not both” etc.

What is really bugging me after lunch-time discussion of this “status codes vs. exceptions” choice is the code left on a napkin:

    public class StatusException : Exception
    {
          public StatusException(StatusCodeEnum statusCode) : base() {}
          public StatusCodeEnum StatusCode {get;}
    }

    // use as a status code:
    return new StatusException(StatusCodeEnum.DBServerUnavailable);

    // use as an exception
    throw new StatusException(StatusCodeEnum.DBServerUnavailable);


What is “OP”, by the way?
DK
Tuesday, March 29, 2005
 
 
+1 for using exception handling only the exceptional things in da code
DanielChein Send private email
Tuesday, March 29, 2005
 
 
"OP" stands for "Original Poster". It is an easy way to refer to the person who started a thread without having to look back at the name.
matt
Tuesday, March 29, 2005
 
 
Basically use exceptions for the exceptional stuff.

A good example of "bad" exceptions is in the date/number parsing routines MS provide. If you want to make a best effort attempt to parse a file then the normal date/number parse routines throw exceptions (This can really hurt when reading in a CSV file).
Checking a number/date is complicated because of all the multilingual issues (let alone the unicode ones) so I'll let the framework do it for me.
MS recognises this issue and .NET 2.0 has a TryParse function. My view is in general provide a .Parse routine that throws an exception and a TryParse routine that doesn't.
Another example is testing for stuff in collection classes. Often it's useful to be able to write code like this:

MyObj=MyColl(key);
if (MyObj==null) //Doesn't exist so add it
{ MyObj=new MyType;
  MyColl.Add(MyObj,Key);
}
MyObj.Counter++;

The main argument here is if MyColl should throw an exception when the key value isn't present.
The alternatives are:

a) Try/Catch requires a big pile of code that obscures what the code is trying to do and is expensive in operational terms if your key check fails often
b) A .KeyExists function requires two lookups on the collection (one to check, one to retrieve) and is at least cleaner but still has extra code.
c) A .TryFind function does solve the problem but then can confuse some programmers, and actually not finding something in a collection isn't really exceptional and the program will probably throw an exception when they attempt to use the null object.
Peter Ibbotson
Wednesday, March 30, 2005
 
 
I think an example where exceptions are great to use is when you have an object whose state you want to enforce.  For example some data / model object that you never allow to be in an invalid state (a bank account balance, a radar status).  Exceptions notify you that the something tried to set the object in an invalid state. 

Status codes are good when you want to carry out some steps based on the specific status code returned.  They provide good information on the result of the operation and allow you to use that information to execute specific code.  For example sending out a message through HTTP.  You would want the status code returned to tell you exactly what happened, not some exception object.  The point is different things can happen after the operation is performed. 

Sujan
Sujan Kapadia Send private email
Monday, April 18, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz