Let's say you are using a library that returns error codes. You'd like to write a wrapper for the library, and you'd like to handle errors with exceptions in the code.
If the library is still in development by someone else, and if the error codes may change (there can be new ones, there can be deprecated ones, or some error codes may change meaning slightly), what would your solution be to handle this?
This is the situation that I'm in right now. In my case, the library is written in C++, and we're using C#. The coder of the library says the error codes may change, and I have to find a way to work with it.
Our initial solution is to:
So let's say a method returns error code 100, then the wrapper checks the category of the error code. If it is a terminal error it throws a terminal error exception, if it is a user input error it throws a user input error exception.
This should work, but I feel like this is not the optimal solution. I'd like to know how good written enterprise software handle change of error codes.
What would you suggest doing?
Edit: I have already questioned the fact that error codes will be changing and the coder of the library says the code is in development. It's an algorithm, so even the way the algorithm works changes as it's original research (he's writing his PhD on that). So he says there may be different errors, or some may be irrelevant in the future.
The data-driven approach you're taking, using the XML file, seems like a good one, given the circumstances. However I'd question why the error codes are changing at all - this suggests that no proper design has been carried out for the library being developed. It ought to have a well-defined structure for its error codes, rather than requiring you to keep changing your interpretation of them.
You may want to try having an overall "library exception" exception class, and subclassing it for each different type of exception you want to throw based on the "type" of the library error. At least that way, you can catch all library errors, even if one of the specific types of exception slips through the net. ie. you'd catch something like LibraryException
after trying to catch TerminalErrorException
.
I guess you will solve this problem easier if you change your vision of the situation a little bit:
Now, the question comes down to the following one: is the internal framework's functionality clearly outlined and finalized? or is that changing too?
If it's changing (possibly because of the external framework), then the internal framework is under the development. This means, client application needs to wait until internal framework is ready to announce a first version ready (possibly after the external framework is complete).
Now error handling:
Errors in the application serve like contracts. Caller of the function expects particular exceptional situations, and particular kinds of errors only. Each possible error is predefined and documented by each function, similar to its input parameters and return values.
What it means for you:
Why is the last assumption fine? because we said the internal application's design is final and is not going to change. Error contracts are part of the final design too.
Example:
//external.
int Say(char* message);
//internal.
///<summary>
/// can throw (CONTRACT): WrongMessageException, SessionTimeOutException
void Say(string message) {
int errorCode = External.Say(message);
//translate error code to either WrongMessageException or to SessionTimeOutException.
}
Cannot translate? something is wrong either with current contracted errors or the external framework: maybe you should terminate the process? something went wrong, unexpected!!!
//client.
...
try {
Internal.Say("Hello");
}
catch (WrongMessageException wme) {
//deal with wrong message situation.
}
catch (SessionTimeOutException stoe) {
//deal with session timeout situation.
}
Let me know if anything raises the question.
Translating error codes to Exceptions:
This obviously is some kind of categorizing for each error code. Category can be each destination exception, and exceptions can be categorized by functions. This is exactly what the error contract means: categorize Exceptions by functions; and categorize error codes by exceptions.
Below is a pseudo configuration for this. Take this as an initial idea of how to categorize:
category Say [can throw]: { WrongMessageException, SessionTimeOutException }
category WrongMessageException [by error code]: { 100, 101 }
category SessionTimeOutException [by error code]: { 102, 103, 104 }
Of course you don't need to write a parser for such kind of impressions (this was human readable pseudo configuration). You can store similar sentences using XML or any kind of source, which will help you configure error translation rules and function contracts.
Reference
Book: Jeffrey Richter - CLR via C#, 3rd edition. Chapter 20 - Exceptions and State Management. Sub-Chapter - Guidelines and Best Practices. Sub-Sub-Chapter - Hiding an Implementation Detail to Maintain a "Contract".
This chapter will describe exceptions as contracts and will explain how to categorize contracts thrown by the function. This can confirm the correctness and the credibility of the explanations provided here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With