Tuesday, November 17, 2009

Error handling in revTalk

No matter how carefully we craft our code to do the right thing, there will always be error outside of our control: a disk may be full, we may not have sufficient privileges, the server connection is lost, etc. So how do we handle this sort of situation in revTalk? Depending on the situation, we check 'the result' after each potentially failing action, or we adopt the 'try-catch-throw' triad.

Personally, I favor the triad as it is common in languages such as Java or the .NET family. And that's why I used it extensively in Quartam PDF Library, throwing errors whenever something was wrong. Some people find this annoying, I feel that it keeps my code cleaner as there is no error checking all over my script, obfuscating what I'm really trying to accomplish.

The important thing to remember is that revTalk is a language which mixes the approaches: for a command like 'open file' you must check the result to see if it failed by any chance. However, if you try to set the 'angle' of an image to "foobar" it will throw an error as "foobar" is not an integer. It's probably due to the HyperCard heritage, where there was no try-catch-throw triad, but it's an inconsistency I'd rather see cleaned up.

Anyway, here's an example to get you started with the try-catch-throw paradigm. Just create a new stack, add a field named 'Log' and add a button with the following script:
on mouseUp
try
Foo
catch tError
Log "mouseUp: running catch block"
answer error tError
finally
Log "mouseUp: running finally block"
end try
end mouseUp

command Foo
try
Bar
catch tError
Log "Foo: running catch block (" & tError & ")"
finally
Log "Foo: running finally block"
end try
if tError is not empty then
Log "Foo: rethrowing error (" & tError & ")"
throw tError
end if
end Foo

command Bar
Log "Bar: before calling Snafu"
Snafu
Log "Bar: after calling Snafu"
end Bar

command Snafu
answer "Continue, throw or exit to top?" with \
"Continue" or "Throw" or "Exit to top"
Log "Snafu: user picked (" & it & ")"
if it is "Throw" then
throw "Snafu: user decided to throw"
else if it is "Exit to top" then
exit to top
end if
end Snafu

--

private command Log pText
put pText & return after field "Log"
end Log


Click the button and pick the option 'Continue' - the following text should be in the log field:
Bar: before calling Snafu
Snafu: user picked (Continue)
Bar: after calling Snafu
Foo: running finally block
mouseUp: running finally block

As you can see, everything went smoothly, and the code in the finally blocks of both the Foo and mouseUp handlers were called. This is where you should handle any cleanup (such as closing the database, files, cursors,...)

Now click the button again and pick the option 'Throw' - the following text should appear in the log field:
Bar: before calling Snafu
Snafu: user picked (Throw)
Foo: running catch block (Snafu: user decided to throw)
Foo: running finally block
Foo: rethrowing error (Snafu: user decided to throw)
mouseUp: running catch block
mouseUp: running finally block

As you can see, the throw in the Snafu handler caused the catch block to be executed in the Foo handler, followed by its finally block. In this case, I decided to re-throw the error after the try block of the Foo handler, so that the catch block in the mouseUp handler would also be called, automatically followed by its finally block. Note that the Bar handler was immediately interrupted so no 'after' log line was written.

Now click the button once more and pick the option 'Exit to top' - the following text should appear in the log field:
Bar: before calling Snafu
Snafu: user picked (Exit to top)

Yes, that's right, this means that execution halts completely, and not even the finally blocks in the Foo and mouseUp handlers are called.

This last bit teaches us to be cautious and not try and mix the different approaches to error handling without testing out the consequences.

Saturday, November 14, 2009

Some time for reflection?

What do you do when you have two weeks off, after working hard for months to meet deadlines and ship a new module on time and per specification, with as only interruption: going to the RunRevLive'09 conference and doing three presentations? Well, I'm glad you asked - I started by catching up on sleep and doing the couch potato thing, watching Star Trek Enterprise season 3.

But along came the release of version 4.0 of the revPlatform, with the highly anticipated revWeb browser plug-in. A-ha, that means it's experiment time! So I sat down and made a little demo revlet, using nothing but graphics, gradients and a few lines of code to demonstrate one way of faking a reflection while playing a simple animation of three circles.


If you don't have the revWeb plug-in installed yet, get it here. Then open a new browser window to run the demo here. Click the 'Start' button to let the three circles roam around. I've included a link for you to download the original stack; if you don't yet have a copy of revMedia 4.0, you can download it here for free.

I'm sure the resident animation and graphics revGurus Ben Beaumont, Malte Brill or Scott Rossi could make it look so much better and smoother, but it's the result of playing around for about an hour, and I'm quite pleased with what I put together, given that my multimedia skills are virtually limited to stick figures.

The beauty of the revPlatform is its elegant language and extreme productivity. And now you can take revMedia for free and start creating revlets - no need to learn Flash ActionScript or JavaScript. Who can resist that?

Support questions and bug reports

They're part of every-day life in the software business: users or colleagues encounter problems, and they need some way to find solutions. Sometimes a quick email is the answer, but generally speaking, there should be procedures in place to handle these items efficiently and transparently.

At my day-job, we have an internal application called MIA, which offers a complete environment for running a software business. Aside from the more mundane tasks of accounting, billing and license keys, it also keeps track of complaints, incidents, modifications and releases.
There is a web interface where customers can enter their issues, the support team picks these from the queue and tries to resolve them; if necessary, these incidents are escalated to a software engineer, which can result in a solution or a modification. The customer can track the status of the incident and if development is needed and scheduled, the planned version is added to the display as well.
We have corrective, functional and structural releases of our products and depending on the type of incident, it will be resolved in one of the next releases. Overall, it is an efficient system that our customers appreciate very much - even if they may not always like how long it takes to actually implement the change.

Of course, the situation is a little different for Quartam Software. It is mostly a one-man-show - apart from the external accountant who takes care of the taxes, and some help for the other accounting duties, I take care of everything: sending license keys, answering support emails, developing new features and fixing bugs, plus the information requests as well as the consulting and custom software jobs.
Unfortunately, that means I can't get to everything as quickly as I wish. I do try and get back to people in a reasonable time frame, and try to offer patch versions when some big problem pops up and the next functional release is still some time off. Sometimes, I fail to meet my own standards. But I, Jan Schenkel, am the person to send emails to, for everything.

In a larger organization, that is simply impossible to do: the manager is there to run the business and ensure the commercial success while the operations run smoothly. When procedures are in place, they should be followed to ensure that every item is handled correctly by the designated person. Only when things don't appear to be moving or important issues seem to get ignored, should you go one step higher, and involve management.
But please don't do it for every item that crops up, and be willing to compromise. The customer may be king, but the guy with the compiler is not a serf.