Monthly Archives: June 2007

Error Handling Strategies

2
Filed under Software Architecture, VB Feng Shui

I once wrote an article about error handling in VB6 for Visual Basic Programmer’s Journal (Sept 2001, jeez that seems like a long time ago! {edit} and it would appear that that link is long since dead 🙁 ). It was born out of the need for a comprehensive framework for handling errors in an app I was working on at the time.

Since then, I’ve expanded the framework several times and it’s grown into something quite handy. Once I get it cleaned up a bit for public consumption, I’ll make the new and improved version available.

I’ve since been looking at the .NET error handler framework, and while it’s certainly much improved over the VB6 days, it still leaves a lot to be desired.

At the very core of handling errors is the division of error types into two distinct classes:

  • Expected Errors
  • Unexpected Errors

In a perfect world, every possible error is an Expected Error and there are no errors that can occur within your program that the code isn’t written to intelligently deal with.

At the other end of the spectrum, is, of course, where most textbook and magazine article sample code lies; where every error is an Unexpected Error that will crash the program.

Unfortunately, real world limitations on time, money, manpower, etc tend to force all code somewhere south of Nirvana.

The .NET fanclub used to decry VB’s on error goto as antiquated technology, and trumpeted try catch as the silver bullet of the day. And I suppose:

On Error Goto Catch
Try:
...code to try...
Goto EndTry
Catch:
...code to handle any error in the try block...
EndTry:

is quite different from

Try
...code to try... 
Catch ex as exception 
...code to handle any error in the try block... 
End Try

as long as you’re only looking at their checksums<g>.

Sure .NET incorporates a wealth of metadata about the exception. The module, function, line number, etc are all available directly while handling the error. But something’s missing.

Oh, yeah, What about those Unexpected Errors?

.NET does have the Exception Handling Application Block and it looks very promising, although it also looks very involved. And do you really want to be able to configure exception handling policies via config files? I mean, beyond indicating the level of logging you want (verbose, medium, low, off), and the email address to send exception report to (unluckysupporttech@mycompany.com), I’m having a hard time coming up with anything else I’ve ever needed to dynamically configure in my apps for exception handling. But, I won’t say it couldn’t be useful.

In the end, I suppose the thing that bothers me most about the EHAB, and the whole structured exception movement in general, is that it really does nothing to address the Unexpected Errors in an application. You still have to wrap your entire procedure in a TRY block in order to be sure that you catch any exception raised in that procedure. Otherwise, the exception is simply propagated up the call stack to the first point that is covered by an exception handler. The good news about .NET, though, is that at least, in those cases, you can still retrieve a call stack back to the real source of the exception and log it. With VB6, no such luck without some sort of framework.

My other issue is that Try Catch style exception handling forces the declaration of how you intend on handling errors to the END of the function you’re looking at. In this age of declarative programming and metadata-attributed interfaces, that just seems so…yesterday.

Take my above comparison of try catch and on error. What actually happens to the error is stated down at the end of the procedure in both styles. Now. I can understand that approach if you have code dedicated to handling specific errors, but then, those are Expected Errors. For the Unexpected Errors, I’d rather know, declared right up front, how the prodecure intends to handle them.

That was the impetus of my article way back when:

  • Provide a framework that could provide a call stack that VB6 was lacking
  • Provide a means of clearly declaring how the procedure intends on handling Unexpected Errors.

Compare a typical Try Catch structure:

Public Sub Test()
   Try                                          
   .....Lots and lots and lots of code....
   Catch Ex as Exception
   ....how to handle specific exceptions, plus how to handle general exceptions...
   End Try
End Sub

with a prologue style declaration like I use in my error handling framework for VB6:

Public Sub Test()
'############### ERR HANDLING #############
Dim Err As CErr: Set Err = New CErr: On Error GoTo Problem
Problem:
Select Case Err.Handle(EHF_PRESENT or EHF_ALLOWRETRY, MODULE, "Test")
Case EHE_NONE: Case EHE_RETRY: Resume: Case EHE_PASS: Resume Next: Case EHE_RESET: Resume Problem
End Select
'##########################################
   .....Lots and lots and lots of code....
End Sub

The code states right up front how unexpected errors are handled (in this case, EHF_PRESENT or EHF_ALLOWRETRY indicates that the user will be shown a dialog and allowed to retry the operation). There’s a bit more verbiage here because of the requirements of VB6, but that’s not the point.

Personally, I’d prefer it if every routine in .NET could be (or maybe even had to be) attributed as to how unexpected errors are to be handled. Those that need to show a dialog would do so based on one or more “predefined” dialogs that depended on where in the app the error was thrown.

And for those apps that you never want to show an error dialog, you could instead indicated that any unexpected errors should be logged to the Event Log (or somewhere else) and then press on as best as possible.

Unlike the implications in so many magazine articles, error handling is hard. Proper error handling is like a prostate exam; you know you have to do it, but you’d really rather not bother.

InstallShield Upgrade Joyosity

7
Filed under Installations, Software Architecture

I’ve been hunting down an issue with an InstallShield Installation for almost a week now.

Very strange. I have a new installation that is a BASIC MSI install (meaning it contains no funky InstallScript at all, and is this fully MSI compliant).

It is intended to upgrade several previous installations, one of which is also a BASIC MSI, but the others are all InstallScript MSIs.

When I first started testing the upgrade process, I did the install of the old version, followed by an install of the new version. When I went to ADD REMOVE PROGRAMS, the new was there, but the old version was as well. The upgrade didn’t work.

Grrr.

So I start digging. Eventually, I determined that the old version was actually being uninstalled (I paused the install midstream and sure enough, all the old files are one point are completely removed). However, for some reason, the entry in the Add Remove Programs list was not being removed.

More digging.

So I reset my test, installed the old version and at Macrovision’s request, I searched the reg and found a key here:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F1C8EEFE-8019-44AB-8AA9-D6F13E3BFAF0}]

that contained all the info about the old installation.

There’s a value called NOREMOVE set to 1. Hmm, that sounds suspicious. So I set it to 0 and install my new version.

No joy, the old version is still listed in ARP. However, when I went back to the registry to check that key, it was gone! What the hell!? Ok, the entry in ARP must be coming from somewhere else. A few reg searches later turned up this key:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\InstallShield_{F1C8EEFE-8019-44AB-8AA9-D6F13E3BFAF0}]

Notice that the GUID there is the same as the other GUID, but this one has “InstallShield_” at the front of the key name.

Delete THAT key, and suddenly, the ARP entry is completely gone.

It would appear that upgrading an InstallScript based install with a BASIC MSI install unintentionally leaves behind a key that it shouldn’t. Some searching the KBs with more specific keywords turned up exactly that.

An InstallScript based install created two entries in the Uninstall registry key, but one is ‘hidden’ from the ARP list view.

A Basic MSI install only creates one key. And if you upgrade an InstallScript based installation with a Basic MSI installation, that second key (the visible one) won’t get removed properly.

You have to add an entry to the RemoveRegistry table in the MSI file and connect it to a component that will be installed by your new installation.

Didn’t table-driven programming constructs die back in ’91 with Magic. No, wait. Ack, they’re still alive?!

Well, tried it then and hated it, still hate it today. To each his own.

SQL and Portability

0
Filed under Software Architecture, SQL

There’s an interesting discussion going on at SQL Server Central about applications and database portability.

The question thrown out was “How valuable is portability to your application”.

And by portability, they’re referring to portability across different database backends. Can your app run on Oracle, SQL Server, MySQL, etc, or do you just lock down to a specific vendor, and sell to your apps strengths and not DB portability?

It’s an interesting question and from the responses so far, it would seem that DB portability is a 4 letter word. But I think many of the responses are a little short sighted or limited to the DBA/developer perspective.

There is one comment saying something along the lines that an app this company purchased was DB agnostic and was found to contain no where clauses. Now that may have been an exageration to make a point, but I’d argue that an app like that was poorly architected from the outset. The fact that it performs poorly would seem to have less to do with being DB agnostic and more to do with just poor coding/architecture. My guess is, if you looked past the DB code in that app, you’d find a lot more to dislike as well.

The bottom line in any business is 1) The customer is always right and 2) you have to sell the product you have in order to make the product you want to sell.

Now, as to part 1, I’m not saying you can’t educate the customer, but in the end, if they really want Oracle as their backend, there may be some business reasons for that that you can’t sell around. And if the IT shop of that customer is centered on Oracle, good luck going in with a SQL Server based app.

I suppose it’d be nice if every shop was an IBM sized house that could hire DBAs specifically to design and support the backends for every reasonable DB, but most shops don’t have those kinds of resources.

In small shops, it’s all about leveraging code as much as possible.