One of the (boring) topics of application development is what to do about/with utility code. This article describes an approach which I've been using over the past couple of years with APL/W and which seems to be serving me well.
Another of the longstanding questions of code development; my conceptualisation extends from the "useful on-liner" (for example the ubiquitous delete-leading-blanks) which might as easily be coded in-line, but arguably self-documents if embodied with a recognisable name to the sub-application (functionality which is common to many applications, for example the configuration tool described in another article).
Well, there might be lots of problems, but the one that plays on my mind in this context is ensuring that when several applications are being developed concurrently (and the utility code is similarly being expanded and enhanced - maybe even corrected) that the applications automatically use the intended (usually the latest, otherwise what's the point?) versions of utility code.
Try to keep in step manually and all the effort that the developer should have been putting into application code goes into copying utilities hither and thither - version control soon becomes catastrophic.
What we (well, I) need to do is to have a mechanism in place that automatically fetches the latest versions of required utilities, and propagates them back when changes are made.
Which would be all very well if all applications always stayed in the developer's world and never got into production use (or shrink-wrapped and sent out to work in the real world). The last thing an end-user wants is to have an application fail because an improved version of a utility was "improved" in the sense of failing to work as it always had.
We need to be able to bolt down the application and ensure that it does not fetch utility code unless that's the intent (meaning, a developer is working on it and wants to expose themselves to the latest utility versions).
The approach described here is driven by an external parameter (supplied as an APL/W startup parameter) to turn off/on the utility loading mechanism.
Sometimes it seems as if every problem that someone has with APL/W can be resolved with namespaces; well, here's another one (you could implement a similar solution in other APLs without the APL/W twiddly bits, but they're available, so might as well use them).
There are a number of possible approaches that I considered and discarded, among them...
What I decided to do was implement a mechanism in which utilities could be grouped in some (logical?) fashion and brought into the application if it needed them.
Within an application all utility code is put into subspaces of a #.UTILS namespace (so, for example ther might be a #.UTILS.BLANKS namespace for al those pesky blank-deletion one-liners, one called #.UTILS.GUI for GUI tools like yes/no dialogues, one called #.UTILS.CONFIG for the configuration utility).
The hierarchy is flat, there aren't spaces-within-spaces. Maybe that'll happen one day, but, for now, I haven't needed it (note that J locales may not be nested, so maybe I have a manageable scenario).
Utilities are stored in a component file, identified to the application by the variable #.UTILS.UtilFile; there's an index component...
MAPS 2004 12 29 13 57 16 0 55 Mapping EXTEND
STATS 2005 10 6 16 55 38 0 56 Statistics
PLOT 2005 12 6 13 45 43 0 57 Plotting Tools STATS
This contains five columns...
What's held in the utility components are ŚOR representations of the namespace. I wasn't totally happy about using these - because at the back of my mind was a wish that utility-handling be APL-portable - but it seemed an acceptable compromise (holding individual functions/operators/variables was going to be just too fussy and long-winded, collections of purpose-related entities felt a lot more manageable than a single soup of all utilities).
Within the latent expression (function) lines like this are included...
utils„'DOGON' 'GEN' 'GUI' 'HELP' 'PLOT' 'STRINGS' 'TODO'
utils„umode UtilLoad utils
The environment variable (startup parameter) called umode controls whether the utility load/save mechanisms operate; if it's set to 'D' they do, otherwise it's assumed that the workspace was saved "complete" and will be used as such.
There's a design decision here - while it might have been more "elegant" to load utilities on demand the decision was to load everything the application needs at startup, it's just a simpler way to do things.
As part of the code that runs when the user shuts down the application there's this line...
umode UtilSave utils
Having got all the bits in place to use utilities, completeness demands a utility maintenance tool. This is the user interface...
Which should all be pretty self-explanatory. Among the features...
And, having done all that - in practice I find that the vast majority of utility extension gets done on-the-fly as part of the application development process. This misses the audit trail feature, but you win some you lose some...
After just over a year of essentially unchanged use I'm pretty happy with the way this has worked out.
When a new application comes along...
As an application develops...
There's probably some things I could change, and may do as and when the need arises, but they've slipped my mind for now,
Code is available (free of charge for non-commercial use) for Dyalog APL/W Version 10 and higher from Dogon Research.
If you want to know more, please contact Dogon Research.
Copyright © Dogon Research 2005; Latest Update: 07 December 2005 15:16