I'm talking about exceptions here. Which is better, avoiding throwing exceptions as much as possible by trying to safely recover from errors, or throwing exceptions that will contain useful information for debugging purposes? I ran into this issue today...
The company I work for uses a program called Fourth Shift. It comes with managed libraries for client access in .NET. I am using a feature called impersonation, whereby transactions can be executed as if a different user was logged in. There are a few things you have to do in order for this to work:
- Grant the logged in user permission to impersonate a given user.
- Enable impersonation when connecting the client.
- Supply a non-null impersonation user name when processing a transaction.
I had to figure all this out because the developers of the client library decided to go with safe execution. Here's what will happen if the above conditions are not met:
- If the user does not have permission to impersonate the given user, the transaction will proceed normally without impersonation. No exception will be thrown.
- If impersonation is not enabled but a non-null impersonation user name is supplied, the transaction will proceed normally without impersonation. No exception will be thrown.
This behavior is about as useful for debugging as the "Failed for some reason" exception message I ranted about in an earlier post, which involved the same client library I might add. All I knew was that for some reason impersonation was not taking place. In any case, here is the behavior I would normally expect from a .NET class library:
- If the user does not have permission to impersonate the given user, an exception is thrown indicating this.
- If impersonation is not enabled but a non-null impersonation user name is supplied, an exception is thrown indicating this.
Now sure, this would help debugging immensely, but won't it make the program less stable? Well, in the case of the latter, no. Whether or not impersonation is enabled is hard-coded and will not change at run-time. It will either always throw an exception (not work at all) or never throw one (always work). In the case of the former, do we want the transaction to succeed if the user does not have permission to impersonate? Sure, if they don't, the program will fail, but at least we'll know exactly why and it's a no-brainer to fix. Another thing to consider is security. If impersonation does not take place, the transaction will be executed under the security context of the logged in user, which in this case, most likely has more security rights than the user that should be impersonated.
So in this case, I would say throwing exceptions would be a better approach. But is it always? Or is this one of those trade-offs like high cohesion vs. low coupling that needs to be weighed in every design? Or is there a way to have both safe execution and easy debugging?