Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions as expected program execution flow control?

I always felt that expecting exceptions to be thrown on a regular basis and using them as flow logic was a bad thing. Exceptions feel like they should be, well, the "exception". If you're expecting and planning for an exception, that would seem to indicate that your code should be refactored, at least in .NET...
However. A recent scenario gave me pause. I posted this on msdn a while ago, but I'd like to generate more discussion about it and this is the perfect place!

So, say you've got a database table which has a foreign key for several other tables (in the case that originally prompted the debate, there were 4 foreign keys pointing to it). You want to allow the user to delete, but only if there are NO foreign key references; you DON'T want to cascade delete.
I normally just do a check to see if there are any references, and if there are, I inform the user instead of doing the delete. It's very easy and relaxing to write that in LINQ as related tables are members on the object, so Section.Projects and Section.Categories and et cetera is nice to type with intellisense and all...
But the fact is that LINQ then has to hit potentially all 4 tables to see if there are any result rows pointing to that record, and hitting the database is obviously always a relatively expensive operation.

The lead on this project asked me to change it to just catch a SqlException with a code of 547 (foreign key constraint) and deal with it that way.

I was...
resistant.

But in this case, it's probably a lot more efficient to swallow the exception-related overhead than to swallow the 4 table hits... Especially since we have to do the check in every case, but we're spared the exception in the case when there are no children...
Plus the database really should be the one responsible for handling referential integrity, that's its job and it does it well...
So they won and I changed it.

On some level it still feels wrong to me though.

What do you guys think about expecting and intentionally handling exceptions? Is it okay when it looks like it'll be more efficient than checking beforehand? Is it more confusing to the next developer looking at your code, or less confusing? Is it safer, since the database might know about new foreign key constraints that the developer might not think to add a check for? Or is it a matter of perspective on what exactly you think best practice is?

like image 301
Grank Avatar asked Sep 25 '08 17:09

Grank


2 Answers

Your lead is absolutely right. Exceptions are not just for once in a blue moon situations, but specifically for reporting other than expected outcomes.

In this case the foreign key check would still take place, and exceptions are the mechanism by which you can be notified.

What you should NOT do is catch and suppress exceptions with a blanket catchall statement. Doing fine-grained exception handling is specifically why exceptions were designed in the first place.

like image 113
levik Avatar answered Oct 27 '22 06:10

levik


Wow,

First off, can you please distill the question down a bit, while it was nice to read a well thought out and explained question, that was quite a lot to digest.

The short answer is "yes", but it can depend.

  • We have some applications where we have lots of business logic tied up in the SQL queries (not my design Gov!). If this is how it is structured, management can be difficult to convince of otherwise since it "already works".
  • In this situation, does it really make a big deal? Since it's still one trip across the wire and back. Does the server do much before it realises that it cannot continue (i.e.if there is a sequence of transactions that take place to your action, does it then fall over half way through, wasting time?).
  • Does it make sense to do the check in the UI first? Does it help with your application? If it provides a nicer user experience? (i.e. I have seen cases where you step through several steps in a wizard, it starts, then falls over, when it had all the info it needed to fall over after step 1).
  • Is concurrency an issue? Is it possible that the record may be removed/edited or whatever before your commit takes place (as in the classic File.Exists boo-boo).

In my opinion:

I would do both. If I can fail fast and provide a better user experience, great. Any expected SQL (or any other) exceptions should be getting caught and fed back appropriately anyway.

I know there is a concensus that exceptions should not be used for other than exceptional circumstances, but remember, we are crossing application boundaries here, expect nothing. Like I said, this is like the File.Exists, there is no point, it can be deleted before you access it anyway.

like image 31
Rob Cooper Avatar answered Oct 27 '22 06:10

Rob Cooper