5

I'm currently having an issue with a 3rd party control library provider. They have an exception occulting culture that gets in the way of my general fail-fast approach when developing software.

An example: their grid control proposes a RowValidating event in which it's possible to check user data input before it's committed to the underlying object. The event argument has a IsValid boolean property and an ErrorText string property. If the handler had the IsValid property set to False, the grid will treat the row as invalid, present the error text followed by "Do you want to correct the value?" in a yes / no dialog box.

The problem is that if the handler throws an actual Exception during the validation process, the grid catches it and will behave exactly like described above - only it will use the caught exception's Message property as the validation error text. The exception instance, even though it's actually MY code that caused it, can't ever be caught afterwards. There's no way for me to handle it other than wrapping my validation code in a try/catch block that catches everything.

Of course I don't want my code to throw any exceptions, but hey... errare humanum est! If that ever happens, I'd much prefer having the app crash and burn than hiding the exception away! For these scenarios I have a global handler that will log the unhandled exception right before the app crashes. This is where I'd expect any of them to end up.

Since my company made a huge investment in this particular 3rd party provider (both from learning and actual code running with it), I can't just run to another vendor - much less making my own grid control.

I tried talking to the vendor so that this gets fixed but they won't do anything in fear of causing breaking changes for other customers (understandable). They also won't introduce any kind of boolean flag to circumvent the behavior (less understandable).

Right now I'm uncomfortable deploying an app in which I know there's a chance for it to run in a corrupted state. I also hate having to wrap my event code in a try/catch block that may encounter an Exception from which it's impossible to gracefully recover from.

What kind of solution can I use to prevent or fix this problem?

TL;DR: 3rd party vendor takes away Exception instances thrown from my own code, workarounds are ugly and unsatisfying, don't know what to do with this.

  • 1
    It's unclear to me whether your problem here is a hypothetical concern, or an actual impediment to your use case. – whatsisname Feb 11 '15 at 6:26
  • 1
    DevExpress doesn't like to admit that mistakes happen =/ – Wilbert Feb 11 '15 at 9:49
  • @whatsisname Right now, more of an impediment. I'm starting development on an app and at this early stage I get all sorts of bugs. For 99% of them the app will crash and the logs will help me figure out what happened so I can fix it. In the above scenario though, nothing gets reported - unless I make every handlers catch / log any unexpected exceptions and crash the app. – Crono Feb 11 '15 at 13:28
  • @whatsisname When this reaches deployment stage, hopefully the known exceptions will all be handled adequately. But if I did miss one exception scenario, when it occurs I will want the app to crash and log the exception. I hate it at least as much as your typical end-user, but I find it far worse to keep the app running on wrong assumptions. – Crono Feb 11 '15 at 13:31
2

I recently solved a similar problem with a third-party library. Allow me to restate to make sure I'm not misinterpreting your situation. You know how to work around it, but you don't like the repetition of the workaround, and you feel it obscures your actual code?

I solved my problem using a python decorator that catches an exception and handles it appropriately. That way, it's only one additional @handle_errors to my function definitions, not a bulky try-catch block that's repeated everywhere. I'm not very familiar with the .net product line, but I know there are aspect-oriented programming libraries you can get, or you can use the decorator pattern to achieve a similar reduction in boilerplate.

Unfortunately, there's not much beyond that you can do. It's just the price of vendor lock in. However, this seems to be a low probability, low impact situation, with validation routines that ought to be mostly stateless and relatively easy to test thoroughly. Also, the exceptions are hardly "hidden" if they're presented to the user. This isn't the situation described in Jeff Atwood's blog.

  • I had a look at the Decorator Pattern. Can I be the first to say, for the record, OMG that's a lot of boilerplate? I'm not familiar with the python syntax you're using, but it looks more like an attribute than a "decorator," except that attributes in .NET are not capable of this functionality (The decorator pattern appears to be unfortunately named; it's really just a wrapper, and doesn't really "decorate" anything, but the Adapter Pattern also uses a wrapper). – Robert Harvey Feb 10 '15 at 20:19
  • Yes, the decorator pattern is a wrapper. The name is to differentiate from other wrapper patterns. The difference between a decorator and an adapter pattern is a decorator has the same interface as what it's wrapping. Python decorators are a completely different thing from attributes. They let you statically specify a wrapper, rather than having to add it at runtime. – Karl Bielefeldt Feb 10 '15 at 20:38
  • Attributes in C# are specified at compile time, but they don't wrap anything; they're just metadata classes. – Robert Harvey Feb 10 '15 at 20:39
  • That was poorly worded on my part. Python decorators are different from attributes because they specify a wrapper, whereas my understanding of attributes is they more append than wrap. They are different from a decorator pattern in that they are statically specified. – Karl Bielefeldt Feb 10 '15 at 20:45
  • 1
    @KarlBielefeldt: see my answer how to accomplish what you suggested in C#. Not so elegant as in Python, but I think it will do the trick. – Doc Brown Feb 10 '15 at 22:37
5

Since the .NET framework standard UI controls do not catch unhandled exceptions by themselves, and offer you some mechanisms to catch those exceptions in a central place, I agree that it is questionable why a 3rd party control should behave differently.

Lets assume, from the nature of your application, in case of a severe failure, you are 100% sure you can safely exit the application at any time, even in an arbitrary GUI event, without the risk of letting behind too much inconsistent data. Then you might consider to create a functional wrapper like this:

public class MyExit
{
  public void WhenUnhandledException(Action action)
  {
    try
    {
        action();  
    }
    catch(Exception ex)
    {
         // ... do some additional logging, if you like ...
         Environment.FailFast(ex.Message+"\n"+ex.StackTrace);
    }
  }
}

and use this function throughout you code like this:

  void MyGUIExceptionHandler(object o, EventArgs e)
  {
     MyExit.WhenUnhandledException(() => {
       // add code, maybe using o and e
     });
  }

That way, you don't need to repeat the same try/catch/log/FailFast code more than once, and you can change your fail-fast and logging strategy afterwards, if you like.

  • The lambda expression decorator is indeed a good idea. However, I must say that I don't quite see your point on preventing a UI event to throw back an exception. If I use a save button's Click event handler to save data and the saving routine throws an exception, the button won't swallow it. Therefore why should the grid's validating event do? – Crono Feb 11 '15 at 0:34
  • @Crono: good point, see my edit. – Doc Brown Feb 11 '15 at 5:15
2

What is there to do. In my view, the decision to turn an exception during validation into a failed validation is a correct way of handling such exceptions.

  • Letting the exception pass through and crash the application has a significant risk that you lose the work the user had been doing, even if the situation was caused by bad user-input and entirely correctable.
  • In a validation routine, you should only check if the input is valid and not make any changes to the state of the application. Therefore, if an exception gets thrown in a validation routine, there should be zero risk that the application state is corrupted.
    If you are doing more than just validation in your handler, then it is your problem to ensure that there is no path out of it with an invalid application-state.
  • I can't agree that it is right for any API to assume it can swallow an exception it didn't itself caused. Furthermore, a validation event can be a candidate for last minute end-user actions on the record, in which state may very well change. – Crono Feb 11 '15 at 0:27
  • 1
    @Crono: I would find it wrong to let an exception through if you know that it will cause a crash. On the other hand, apparently that is how the .Net widgets work and I value a consistent user/programmer experience more. In that light I find it strange that this 3rd-party component works differently. – Bart van Ingen Schenau Feb 11 '15 at 7:57
  • In .NET, the developer is accountable for any exceptions his code encounters. However, when you are writing an API for another developer to use, you should NEVER hide any exception thrown from one of its delegates / subscribers / listeners. Doing so won't make your API any better; it will in fact TAKE AWAY the ability for the developer to be aware of a problem and solve it adequately. – Crono Feb 11 '15 at 18:15
  • Worse yet: it can lead to an app logic making bad decisions under wrong assumptions that some previous logic was executed successfully. This, in turn, can lead to data being lost or corrupted up to a severe level. It can take long for both the user and the developer to notice there's something's wrong. And once you do, depending on how huge / complex your app is, you may need an even much longer time figuring out what is causing the corruption. So as much as it sucks for an app to crash on an unhandled exception, it can be far, FAR worse. – Crono Feb 11 '15 at 18:19
  • 1
    @Crono: Swallowing exceptions (catching them and doing nothing about it) is a cardinal sin. Handling exceptions, even if they originate from client code, is something completely different. From the looks of it, this grid component is handling the exceptions, not swallowing them. Note that exceptions are designed to be a long-range error-reporting mechanism for errors that the software/user might be able to do something about. By the very nature that they can be caught, exceptions are not the best mechanism to signal the presence of a bug. – Bart van Ingen Schenau Feb 12 '15 at 7:57
2

I am very fond of hard error & fail fast, I believe they are the one true and right way to go, but I try not to be dogmatic about them.

There are cases where the best thing to do with an unexpected exception is to log it and swallow it. I will give you an example which is more simple than your situation: suppose you have an observable collection which, when changed, issues a notification to a list of registered observers. And suppose that one of the observers throws an exception. Is it the collection's fault? No, as it has no control over who registers with it. Is it the fault of the code that modified the collection? Certainly not, that code probably did not even know that the collection that it was modifying was an observable one. Is it the fault of any of the remaining observers that are registered and also expect to receive their notifications? Also no, as each of them has no knowledge of other observers, and no control over who will be notified first. So, clearly, the only thing that makes sense for the observable collection to do is to log the exception, swallow it, and keep invoking the remaining observers in the list as if nothing happened.

So, the creator of that library is in a similar situation, and has had to make the same decision.

What I would do in your shoes is that I would surround all my entry points with try-catch so as to be sure that a meaningful error message will always be returned to the library that calls me.

It would be nice to have support by the language for doing things like that, (automatically generated decorators that catch exceptions and invoke an overridable to handle them,) and Karl Bielefeldt's answer seems to indicate that python does have such a mechanism, but those of us who don't have such niceties at our disposal are stuck with doing it by hand.

EDIT:

Your need as a developer to know that a non-fatal exception has occurred should mostly be covered by logging the exception. (You do watch your log while debugging your application, don't you?)

Now, if, like me, you want to eliminate the possibility of any non-fatal exception ever scrolling by the log and going unnoticed, you can do what I do:

I have a centralized utility method for swallowing exceptions which, immediately after logging the exception, performs the following extremely useful call:

System.Diagnostics.Debugger.Break();

On the field, this does nothing. But in a development environment, (while running under the debugger,) this breaks into the debugger, which theoretically allows me to examine the state of the machine and gain more information about the cause of the exception, but even more importantly, it makes sure that I notice that the exception was thrown.

Of course this presumes that while developing your application you never run it, you always debug it. That's the correct mode of operation. If by any chance you do not already have that habit, I would strongly recommend that you acquire it.

  • I'm starting to believe I am dogmatic because I would personally think even though the exception isn't directly caused by the collection, it should still let it go down the stack. In the end, the developer still gets to decide which observer will be registered; if s/he registers a failing one, that's his/her responsibility to either fix it (if possible) or use a collection decorator that is aware of it - and only it. Now in my scenario, we are talking about a validation mechanism that takes for granted it can occult anything that goes wrong while validating data. Dead wrong IMHO... – Crono Feb 11 '15 at 0:54
  • Back to your example again: the faulting observer could very well be one of my own. If anything is wrong with it, I sure as heck would want to know. – Crono Feb 11 '15 at 0:56
  • @Crono I amended my answer. – Mike Nakis Feb 11 '15 at 8:30
  • You're using your utility in a catch block? If so then yes I'm doing something similar already. Although it doesn't change the fact I'll want the app to crash if the exception can't be handled. ;) – Crono Feb 11 '15 at 13:41
  • Yes, in a catch block. – Mike Nakis Feb 11 '15 at 13:43
-1

So here, you're writing the handler that throws the exception and the grid manages that exception itself.

I see this as fair enough - after all, you're writing the library code that throws on error states, and the caller (ie the grid) catches and manages the exception how it likes, in this case showing a message to the user in a dialog (which is perfectly understandable given its a UI control).

Now I can understand that you'd like some exceptions to pass through and crash the app, or allow you to catch them, and they might have only caught exceptions based on their own hierarchy instead of catching all exceptions, but they made that choice. You'll just have to live with not being able to catch exceptions and handle them inside the handler (possibly setting some state elsewhere or sending an alternative message to notify your application).

  • You know any other .NET UI controls that behaves like this? – Crono Feb 11 '15 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.