Thanks again to all the presenters and contributers to last weeks Northern European CLD Summit in Newbury. Anyone who wasn't able to attend, you missed some great presentations and discussions.
One such discussion which I wanted to follow up on further is exploring better error handling within LabVIEW. Pretty much the only conclusion we came to is that nobody is 100% happy with the way they handle errors in applications - I agree with Steve Watts's comment that this is not a problem limited to LabVIEW, error handling in most languages could be improved (if anybody is 100% happy with their error handling - we need to hear from you!)
The method everyone is taught during the LabVIEW Core training courses is to daisy chain the error cluster from one function to the next, which passes the error along and helps to enforce the correct sequence of actions. This works OK for a small single-threaded application but can cause problems in more complex applications. What happens if the error is non-critical and can be corrected to allow the application to continue running? What about other areas of the application which may need to continue executing even if a particular function errors out?
In an ideal world it would be good to have something like a right click option to tell each function/sub-vi to only respond to or ignore certain error codes - of course I could individually wrap each vi in a wrapper vi to achieve this, but thats a lot of extra work to do and maintain.
There are a number of different ways of handling this, each with benefits and drawbacks. What I would like to attempt is to gather together some best practise ideas and then to combine these into something like a toolkit/reference design or something to help improve how we do this. Part of this will potentially involve leading some discussions at CLD/CLA Summits and User Group meetings, but I'd like to encourage everyone to add their thoughts in the comments below.
Looking at the Error-Handling techniques section in the book 'Code Complete', a lot of the techniques we all use today are mentioned there too. Idea's mentioned there are range from trying to correct/ignore the error, to stopping the application for serious errors (I can give more details on what is meant by any of these headings if needed, but wanted to avoid this initial post becoming too long):
I can give more detail on the recommendations in the book if needed, but think it would be best to stop now and see what everyone in the community is doing.
For what its worth, my favoured approach for complex applications is to have a standardised error handler object which I can move between applications. The data required to log an error should stay consistent (error status, error code, error source, timestamp and maybe some other details) and therefore the interface doesn't change. This could essentially be a drop in vi which passes out a queue/user event reference to allow other objects to throw errors to it. This approach definitely isn't perfect but its the best I have figured out so far.....
Thoughts, in no particular order:
-- Logging is not the same as handling. Logging can be generic and reusable; handling is specific.
-- A per-VI configured ignore-error would blow up in complexity (N VIs and M possible errors is NxM)
-- Even complex applications should have lots of dependant-action "threads" (select file--> open file--> parse file--> validate data--> use data--> update whatever) where error chaining makes a lot of sense.
I couldn't make the summit this time around but error handling is a topic in which I think I/you can always improve.
My current iteration is that I have QMH modules which will try to handle their own errors and report them to a central handler. Often this is done by 'retrying' - for example if an FPGA I/O node fails then it's probably because it lost connection so I go back to my initialise case and keep retrying (with a timer if there is an error during the initialisation) until the connection is established again. My 'error handling' module keeps the errors in a lossy queue, logs them to disk and reports them to a generic message window (where other application notices are shown).
There is some functionality in the error reporter (which I think could be further improved) to prevent reporting the same error over and over again (e.g. with some timing and checking the error code hasn't changed)
Some other thoughts include:
- If a user doesn't need to know about an error, don't tell them about it. If it's something that won't affect the performance of the application, the user doesn't need to do anything and it can be recovered then just get on with it. The worst thing you can do is just shut-down the application if an error occurs...that's super frustrating for users!
- Logging errors for debugging is a must if you're building applications. It's often very difficult to re-create the scenario that generated the error so some logging of the error with some additional state information is invaluable! You'd have more luck finding the pot of gold at the end of a rainbow than getting the user to tell you exactly what the error was!
- drjdpowell is right about 'threads' - I will chain errors where it makes sense to do so...when you have operations that rely on the valid outcome of the previous. If it doesn't make sense to chain the errors, I often have parallel 'threads' and then a merge errors node to bring them back together for reporting.
Oh, someone gave me a copy of a useful poster/handout a while ago but apparently it isn't easily available online but it pretty comprehensively covers pretty much everything you might want to do with an error. (Ok, except the reporting/logging part - but it does cover things like errors on shift registers in loops). I'd already scanned it in so thought I'd add it to the discussion.
Sorry I missed the summit too.
One library I use quite frequently is the Structured Error Handler library
It does use express VIs but that is just about the only library I use with express VI.
This may be used to implement local or distributed error handling.
Thanks for the replies so far guys. I definitely think there is no silver bullet and agree that all the points made so far can work in the right situations.
I have used the SEH library a few times before. .aCe., out of interest - what options would you typically use within the SEH library? Would you always use the same or do you choose different options depending on the situation, and if so - what determines that choice?