2006-06-16

User script clashes

Aditya Mukherjee noticed that my Blogger post tagger/publish helper recently failed to link Del.icio.us from the "posted" page in his setup, and some debugging later, we found it was a clash between that script and Stephen's Blogger trackback script.

Collisions like these are inherent to the stigmergy model of user scripts, where multiple scripts affect the environments of one another. It takes a bit of attention to defensive coding practices to avoid problems like these. Especially considering that invocation order might make the combination of two scripts sharing environment work with the one script installed prior to the other (which, at least in Greasemonkey, is what decides the script invocation order), but not the other way around. Apply Murphy, and users will encounter trouble, even if you made sure one of the combinations worked. (This gets increasingly unwieldy if you widen scope from two scripts to three scripts, or indeed seventeen.)

It took us a bit of debugging to weed out what went wrong and why, but Aditya found me on a good day with a bit of time on my hands, and we dug into the problem, sprinkling alert()s and try{ ... }catch(e){alert(e)} statements all over the place until we had it down to where what happened and didn't, and before long it was aparrent that it was some other script that tripped mine, and Aditya homed it in to Stephen's, which in turn was based on mine.

In-bred scripts that try to do very many things, for various reasons, are more likely to suffer this condition than others. I often make whole little applications in user script form, rather than separating each feature into a user script of its own, and this script was no exception; it made links out of plaintext paths, added some useful links Blogger does not, and so on, and Stephen's adopted version of the script did many (if not most) of the things the original did, so when they both tried to, one was doomed to fail, and uncharted chaos ensue.

The more assumptions a script makes about its environment, the more likely it is to break. Picking up some script to use as a base for another script is a practice I rather like, and encourage; this lowers the bar for many a scriptwright to achieving results, which is of course good. The point I try to make here is that you should try to strip off as much of the cruft of the base as you possibly can before doing what you want with it, refactoring it to avoid as many side effects as you can that are not what your script sets out to achieve.

Similarly (and this goes just as much for me), it is a healthy practice not to add a busload of side effect featurities to a scipt, if you can stay away from it, as every assumption made adds potential conflicts to integration with other scripts. As user script authors, we deal with an unryly fauna of cooperating or competing scripts that all try to live their lives, and we do not have the luxuries of memory protection and similar safe-guards which applications developers have; indeed the whole point of the user script is to tamper with the bits of others.

Occasionally, it is unfortunately necessary to marry wildly different features into a single script for doing cross-script configuration data sharing, to have them instead share a local storage namespace. (As some scripts depend on the same set of configuration data to do their job and to work in concert.)

Otherwise, my tip is to avoid the temptation of bundling up everything under the same hood while you are at it, at least if you write your scripts, intending to share them with a wider audience.
blog comments powered by Disqus