views:

64

answers:

4

This is just a general design question. If you are developing a business component or service, (e.g. an object/service that exposes a relatively simple interface for handling billing transactions), what are some good ways to handle business-related errors?

Say the component/service must integrate with a few different external web services that all report back different errors, and must also do some database work on your side. There are many different things that can go wrong, both network/database-wise and business rule-wise. Would it be better to try to catch all types of errors within the component and report them back to the caller using an error-code scheme, or try to wrap all errors into various types of exceptions and throw them on to the caller.

This seems to be a struggle, because it gets awkward to deal with the business rule checks using exceptions, and I've read in several places to avoid using exceptions to control "non-exceptional" or business-logic flows. I feel that "exceptional" is often a debatable term, and it gets sticky trying to keep different cases defined as "exceptional" vs. "non-exceptional." (e.g. if your business logic checks for spending limits, age limitations, etc.). At the same time, using an error-code scheme is also awkward, because the caller might choose to ignore the error codes.

Any tips or references would be appreciated!

+1  A: 

I'd go for the error code scheme, because you said "many different things that can go wrong". You might want to have a scheme that returns a List of Error objects, where Error would encapsulate the code, explanation, original data, etc.

An exception can only tell one thing that's wrong, and it should be of an "exceptional" nature, not a run-of-the-mill problem.

Or perhaps a hybrid where you throw an exception that has a List of Error objects as a private data member and an access method that lets you iterate over the errors.

duffymo
+1  A: 

Business related errors should not be exeptions. Exceptions are there if there is an event in the program that the program is not designed to handle or completly unforseen. To this end, if you anticipate a large number of different exceptions, by all means implement some useful numbering scheme. Here I would recommend a guid for the reason of component reuse. Every component should expose some interface to query the list of possible exception numbers (this can then be added to a data store for documentation). Also as you reuse components, error codes will not conflict.

User or business data errors on the other hand almost warrant some numbering scheme. There is almost no way to anticipate all the silly things a user is capable of. However, I would strongly discourage formal language exceptions in favour of some custom error object. Language exceptions may incur significant overhead, or require specialized handling to prevent them from propogating up the call stack. A business error object may very well be a nice way to go.

MaLio
+1  A: 

Services are borderline, especially if they have to be hit from various languages that may not handle SOAP exceptions properly. There are also security concerns if it's on the WWW.

If it's not a service, is internal, and/or will be accessed by clients in known languages, use exceptions to handle failure conditions. Clients are not guaranteed to check error codes.

See http://msdn.microsoft.com/en-us/library/ms229030.aspx for a great discussion of this. (It's also in the book Framework Design Guidelines.)

TrueWill
+1  A: 

There's absolutely nothing that could prevent you from making both business rules and technical rules violations exceptions. I'd use exceptions in two cases:

  1. Precondition violation. If your function's specification says "the amount spent should not exceed the limit for this type of account", and user, knowing this, specifies greater limit anyway, throw the exception right into him!

  2. Postcondition violation. If all preconditions are met, but due to unexpected denial (database connection, for example; or completion of the transaction violates anti-monopoly law) you can't supply the correct result, do not supply it. Throw an exception.

Since all business logic probably is within one component and doesn't rely on anything else, case 2 for business exceptions is quite rare. And what falls into case 1 should be checked for in the front-end application. This makes me think that the approach of not throwing business-logic exceptions is not that you "should not do", but likely "you mostly don't need to".

Anyway, from the perspective of the language you're programming, it hardly notices the difference between "technical" and "business" exceptions, so it'll handle them all correctly. Second, exceptions are caught somewhere. I guess, that, from architector's point of view, business and technical exceptions will be caught in the different components. Of course, unless they're effectively uncaught, merely displaying error messages without programmatical handling falls into this category. So the use of the same mechanism won't make you mix these errors.

So, my point is, that if you chose not to repulse exceptions as programming concept, you may use them for business logic as well.

Pavel Shved