I realise this is an older programming environment, but I have to clean up some VB6 code and I am finding that most of it uses:
On Error Resume Next
What is the general consensus about the use of On Error Resume Next?
Surely, if there is an error, you would want the app to stop what it was doing, rollback any data changes, and inform the user of the error, rather than just resuming.
When is it a good idea to use On Error Resume Next?
It is perfectly reasonable to use On Error Resume Next to implement local structured error handling. This involves testing for an exception and acting on it of course, as well as disarming the mechanism afterward. Example:
On Error Resume Next
GetAttr strFilePath
If Err Then
On Error GoTo 0
'Deal with "no file" scenario.
Else
On Error GoTo 0
'Open and process the file.
End If
That's just a simple example where only one sort of exception is expected. In some cases it is necessary to test Err.Number for specific values and take different actions based on them.
The unstructured approach based on GoTo label can often work as well, but it is hardly superior in most instances. In VBScript the pattern shown above is the only form of exception handling you even have since there are no GoTos or labels.
What's objectionable is arming explicit exception testing at the head of every procedure and ignoring it... a sort of Trust the Force, Luke approach to trying to mask coding errors.
I have found it useful in functions where an error would not warrant the user being interrupted with the issue. A good example is in the resize event. If you make a mistake or there's a problem in the resize event then you probably don't want the user to see this, as it probably wouldn't affect functionality.
I would say in general, use it sparingly.
Almost never - unless used consciously for example on a line where a successful call will set a particular return value, and the subsequent code handles the return value to cater for the error case.
Related
I need some help with selecting a value from a dropdown list. The dropdown is a WebElement, and the flow works well up to the point where the value should be selected.
My code is as follows:
.Browser("Browser").Page("PageName").WebElement("DropDownList").Click
.WebList("ListOfItems").Select(itemToSelect)
Note: itemToSelect is the name of the item that needs to be selected from the list, which is being passed as a parameter within the function.
When running the code, I get an unspecified error.
The weird thing is that before the error is thrown, I can see the value being selected from the list in the browser, as upon selecting it, some fields in the form change. Also, if I press "Skip" in the error message panel, the process goes on as if nothing happened.
I am certain the error comes from .WebList("ListOfItems").Select(itemToSelect) but I do not know what to do in order to fix it.
Try this code.It works for me.
StrAllItems = Split(Browser("name:=.*").Page("title:=.*").WebList("name:=.*").GetRoProperty("all items"),";")
For intCounter = Lbound(strAllItems) to Ubound(strAllItems)-1
If Browser("name:=.*").Page("title:=.*").WebList("name:=.*").GetItem(intCounter)= "SomeValue" Then
Browser("name:=.*").Page("title:=.*").WebList("name:=.*").Select (intCounter)
Exit For
End If
Next
Please let me know if this help.
If the test behaves correctly and you're just getting an superfluous error you can just ignore this specific error. It's best of course to understand where the error comes from, you should probably contact MicroFocus support but in the meantime you can turn off error handling for the offending line.
Browser("Browser").Page("PageName").WebElement("DropDownList").Click
On Error Resume Next ' turn off error handling
Browser("Browser").Page("PageName").WebList("ListOfItems").Select(itemToSelect)
On Error Goto 0 ' turn error handling back on
BTW, I changed your code a bit to make it valid, I assume this is what your code really looks like.
Possible timing issue: You might need to wait for the hole list to appear before you select the item.
Often, the item exists, but the app is still updating its GUI.
Whenever you access the GUI with UFT while the app is not idle (f.e. not ready for user input because it is still updating its HTML), you might get all kinds of strange results, including unexpected errors, hangs, instability.
So how do you wait for the list to be complete? I don't know, because it heavily depends on the way your app is refreshing its GUI. You need to explore that, and integrate some synchronization code that waits for the right condition to be met.
Unfortunately, this is a hell of a job sometimes.
A suitable workaround (and a good way to verify if my hyphothesis is correct) might be to insert a large delay between the first click and the list item selection click. (A quick way to do a similar thing is to single-step through the code.) If that does not generate any error or issues, you can be pretty sure it is what I describe, and you can experiment with lower delay durations to find a good value.
Thanks to everyone for your replies.
The issue turned out to be due to the object not being added well to the repository.
It was eventually fixed by adding it properly.
Ruby offers two possibilities to cause an exception programmatically: raise and fail, both being Kernel methods. According to the documents, they are absolutely equivalent.
Out of a habit, I used only raise so far. Now I found several recommendations (for example here), to use raise for exceptions to be caught, and fail for serious errors which are not meant to be handled.
But does it really make sense? When you are writing a class or module, and cause a problem deep inside, which you signal by fail, your programming colleagues who are reviewing the code, might happily understand your intentions, but the person who is using my code will most likely not look at my code and has no way of knowing, whether the exception was caused by a raise or by fail. Hence, my careful usage of raise or fail can't have any influence on his decision, whether she should or should not handle it.
Could someone see flaws in my arguments? Or are there other criteria, which might me want to use fail instead of raise?
use 'raise' for exceptions to be caught, and 'fail' for serious errors which are not meant to be handled
This is not what the official style guide or the link you provided say on the matter.
What is meant here is use raise only in rescue blocks. Aka use fail when you want to say something is failing and use raise when rethrowing an exception.
As for the "does it matter" part - it is not one of the most hardcore strictly followed rules, but you could make the same argument for any convention. You should follow in that order:
Your project style guide
Your company style guide
The community style guide
Ideally, the three should be the same.
Update: As of this PR (December 2015), the convention is to always use raise.
I once had a conversation with Jim Weirich about this very thing, I have since always used fail when my method is explicitly failing for some reason and raise to re-thrown exceptions.
Here is a post with a message from Jim (almost verbatim to what he said to me in person):
http://www.virtuouscode.com/2014/05/21/jim-weirich-on-exceptions/
Here is the relevant text from the post, a quote attributed to Jim:
Here’s my basic philosophy (and other random thoughts) on exceptions.
When you call a method, you have certain expectations about what the method will accomplish. Formally, these expectations are called post-conditions. A method should throw an exception whenever it fails to meet its postconditions.
To effectively use this strategy, it implies you must have a small understanding of Design by Contract and the meaning of pre- and post-conditions. I think that’s a good thing to know anyways.
Here’s some concrete examples. The Rails model save method:
model.save!
-- post-condition: The model object is saved.
If the model is not saved for some reason, then an exception must be raised because the post-condition is not met.
model.save
-- post-condition: (the model is saved && result == true) ||
(the model is not saved && result == false)
If save doesn’t actually save, then the returned result will be false , but the post-condition is still met, hence no exception.
I find it interesting that the save! method has a vastly simpler post-condition.
On the topic of rescuing exceptions, I think an application should have strategic points where exceptions are rescued. There is little need for rescue/rethrows for the most part. The only time you would want to rescue and rethrow is when you have a job half-way done and you want to undo something so avoid a partially complete state. Your strategic rescue points should be chosen carefully so that the program can continue with other work even if the current operation failed. Transaction processing programs should just move on to the next transaction. A Rails app should recover and be ready to handle the next http request.
Most exception handlers should be generic. Since exceptions indicate a failure of some type, then the handler needs only make a decision on what to do in case of failure. Detailed recovery operations for very specific exceptions are generally discouraged unless the handler is very close (call graph wise) to the point of the exception.
Exceptions should not be used for flow control, use throw/catch for that. This reserves exceptions for true failure conditions.
(An aside, because I use exceptions to indicate failures, I almost always use the fail keyword rather than the raise keyword in Ruby. Fail and raise are synonyms so there is no difference except that fail more clearly communcates that the method has failed. The only time I use raise is when I am catching an exception and re-raising it, because here I’m not failing, but explicitly and purposefully raising an exception. This is a stylistic issue I follow, but I doubt many other people do).
There you have it, a rather rambling memory dump on my thoughts on exceptions.
I know that there are many style guides that do not agree (the style guide used by RoboCop, for example). I don't care. Jim convinced me.
I am looking at code written by someone else.
Some of the big functions are a mess, with changes to the error handling at many points throughout the function. There is a variety of On Error Goto ErrHandler, On Error Goto 0, On Error Resume Next, as you go through the function.
What would be the best way to go through and clean up this error handling so that there is just one On Error Goto ErrHandler at the top of the function as it should be?
I don't think that having a single Error Handler is necessarily the best solution.
If you have a huge function with one error handler and something goes wrong, you have no idea at which point it failed.
It sounds to be as though the functions you describe have the correct error handling in them but that doesn't mean it is easy to read.
Maybe the best solution is to re-factor the big functions into several smaller ones which can have their own single error handler that way when an error occurs you only have a few lines to track down the bug?
You could use the existing error handler statement to give you suitable markers for code re-factoring.
It's hard to say without looking at the code in question, but there are times when several different types of error handling in a single function is legitimate. In general, a single On Error GoTo ErrHandler at the top of the function serves the same function as an enclosing try/catch block in a language that supports exceptions -- it's there to catch the unexpected errors that occur.
However, within the function, there may be places where an error is a normal, expected occurrence that you want to check for inline. For example, say you're going access a network drive, where you have to account for the remote server being offline, the network down, etc. In this case, even though there's an On Error GoTo ErrHandler statement at the top, you can turn that off locally with an On Error Resume Next and try to access the drive. If an error occurs, VB6 will now just fall through to the next statement where you can check Err.Number for anything other than 0. This is analogous to a nested try/catch to trap an expected error condition that you can handle locally. Once execution has passed beyond the risky code, you have to mark the end of the section where you're going to "manually" check for errors this way with another On Error GoTo ErrHandler statement to re-enable the function-level handler.
So there's a case where more than one On Error... statment is valid. The argument can be made that the risky function should be refactored out and have its own handler, but you'd still have to deal with the specific (expected) error return values from that separate function, because the called function probably won't know what to do in the face of these errors in the context of the calling function. You would still handle that with the short-term On Error Resume Next technique.
On Error GoTo 0 disables all error handling, letting VB6 bail out of your function whenever an unexpected error occurs. I'm having a hard time coming up with a non-contrived situation where that would be a good option.
I have a procedure that returns an OUT parameter.
procedure foo (in_v IN INTEGER, out_v OUT integer)
BEGIN
...
EXCEPTION
WHEN OTHERS THEN
--sh*t happend
out_v := SQLCODE;
END
That parameter will be 0 if everything goes OK, and <> 0 if something ugly happened.
Now, if sh*t happens along the way, an exception will be thrown.
Is it ok to assing the SQLCODE value to the OUT parameter ? Or is this consideres a code smell, and I will be expelled from the programming community ?
Thanks in advance.
If there is no additional handling of the error, I would probably advise against it. This approach just makes it necessary for each caller to examine the value of the out parameter anyway. And if the caller forgets it, a serious problem may pass unnoticed at first and create a hard to debug problem elsewhere.
If you simply don't catch OTHERS here, you ensure that the caller has to explicitly catch it, which is a lot cleaner an easier to debug.
Whether it's OK or not depends on what you're trying to achieve with it, I suppose. What problem are you trying to solve, or what requirement are you trying to meet?
the usual behaviour with errors is to gracefully handle the ones that you expect might happen during normal functioning and to allow those that you do not expect to be raised, so this does look odd.
Its ok, but I don't recommend it. By doing it this way you're forcing the calling code to do non-standard error handling. This is fine if you are the only person ever calling the code and you remember to check the error code. However, if you're coding in a large system with multiple programmers I think you should be kind to your fellow programmers and follow the standard way of exception handling supported by the language.
If you do decide to go down that route, also pass back SQLERRM as without the error text you only have the error code to go by. After years of catching "-20001" for the hundreds of application errors in 3rd party software the SQLERRM is often important.
This coding style is not a good idea for a number of reasons.
First, it is bad practice to mix errors and exceptions, even worse practice to mix return values and exceptions. Exceptions are meant to track exceptional situations - things completely unexpected by normal programming such as out of memory issues, conversion problems and so on that you normally would not want to write handlers at every call site for but need to deal with at some level.
The second worrying aspect of the coding style is that your code is effectively saying when an exception is encountered, the code will signal to its caller that something bad has happened but will happily throw away ALL exception information except for the SQLCODE.
We are changing some of the text for our old, badly written error messages. What are some resources for best practices on writing good error messages (specifically for Windows XP/Vista).
In terms of wording your error messages, I recommend referring to the following style guides for Windows applications:
Windows user experience guidelines, and specifically the section on error messages here.
Microsoft Manual of Style
The ultimate best practice is to prevent the user from causing errors in the first place.
Don't tell users anything they don't care about; error code 5064 doesn't mean a thing to anyone. Don't tell them they did something wrong; disallow it in the first place. Don't blame them, especially not for mistakes your software made. Above all, when there is a problem, tell them how to fix it so they can move on and get some work done.
A good error message should:
Be unobtrusive (no blue-screen or yellow-screen of death)
Give the user direction to correct the problem (on their own if possible, or who to contact for help)
Hide useless, esoteric programmer nonsense ( don't say, "a null reference exception occurred on line 45")
Be descriptive without being verbose. Just enough information to tell the user what they need to know and nothing more.
One thing I've started to do is to generate a unique number that I display in the error message and write to the log file so I can find the error in the log when the user sends me a screenshot or calls and says, "I got an error. It says my reference number is 0988-7634"
For security reasons, don't provide internal system information that the user does not need.
Trivial example: when failing to login, don't tell the user if the username is wrong or the password is wrong; this will only help the attacker to brute force the system. Instead, just say "Username/Password combination is invalid" or something like that.
Always include suggestions to Remedy the error.
Try to figure out a way to write your software so it corrects the problem for them.
For any user input (strings, filenames, values, etc), always display the erroneous value with delimiters around it (quotes, brackets, etc). e.g.
The filename you entered could not be found: "somefile.txt"
This helps to show any whitespace/carriage returns that may have sneaked in and greatly reduces troubleshooting and frustration.
Avoid identical error messages coming from different places; parametrize with file:line if possible, or use other context that lets you, the developer, uniquely identify where the error occurred.
Design the mechanism to allow easy localization, especially if it is a commercial product.
If the error messages are user-visible, make them complete, meaningful sentences that don't assume intimate knowledge of the code; remember, you're always too close to the problem -- the user is not. If possible, give the user guidance on how to proceed, who to contact, etc.
Every error should have a message if possible; if not, then try and make sure that all error-unwind paths eventually reach an error message that sheds light on what happened.
I'm sure there will be other good answers here...
Shorter messages may actually be read.
The longer your error message, the less the user will read. That being said, try to refactor the code so you can eliminate exceptions if there is an obvious response. Try to only have exceptions that happen based on things beyond your user or your code's control.
The best exception message is the one you never have to display.
Error handling is always better than error reporting, but since you are retrofitting the error messages and not necessarily the code here's a couple of suggestions:
Users want solutions, not problems. Help them know what to do after an error, even if the message is as simple as "Please close the current window and retry your action."
I am also a big fan of centralized logging of errors. Make sure the log is both human and computer scanable. Users don't always let you know what problems they are having, especially if they can be 'worked around', so the log can help you know what things need fixed.
If you can control the error dialog easily, having a dialog which shows a nice, readable message with a 'details' button to show the error number, trace, etc. can be a big help for real-time problem solving as well.
Support for multilanguage applies for all kinds of messages, but tends to be forgotten in the case of error messages.
I would second not telling the user useless esoteric information like numeric error codes. I would follow that up however by saying to definitely log that information for troubleshooting by more technically savvy people.