More reusable 4gl
Posted in 1995
Well, it looks like somebody has already done some major work on reusable 4gl code (I've given a quick look at POWER-4gl and I must say it looks good!), so here are my two cents on the subject. I started thinking about an application framework back in 1992, when the users of my radiotherapy info system begun complaining that it was too mastodontic (you had to go six or seven levels down a menu before getting to do somenthing, and had to go all the way up plus some more levels down to do something else); in the meantime some guy at the local university radiology department asked me to write a system which could generate a set of multiple choice questions he could use to prepare exam papers and his students to test their knowledge. I wanted to reuse quite a bit of the code I already had written, plus I needed a simpler interface, something that, for example, allowed the user to input on the fly a new record of some kind and after that get back to whatever the user was watching (which would be totally unerelated), and this without having to put in each "viewing" module the knowledge of what all the "input" modules were about! After some thought (and a quick glance at the turbo vision library manual!) I came out with the message oriented application framework I'll try to explain in the following few ;-) lines. Of course 4gl lacks fancy things like user definable constants or types, not to mention pointers, procedural parameters or *objects* (I'm not an OO fan, in the sense that I haven't had a chance to use OOP, but I like the idea), so 4glWorks (that's its name - not much fantasy, I know, but I spent more time working on it than thinking of a name) works in the exact opposite way than TV: modules waiting for a message actively do so on the stack, rather than passively sit on a heap I don't have,waiting to be called upon message arrival. The resulting operation, however, is similar to that of TV, with a few limitations (SDI vs MDI, windows are not movable or resizable). Before trying to explain 4glWorks, have a look at the typical 4glWorks application in this block diagram: Application | 4glWorks ~~~~~~~~~~~ | ~~~~~~~~ | | ->Services<- | | ^ | | | | v | | | Vertical Menus<--|----->Vertical Menu Library | | ^ | | | | | | v v | | Horizontal menu<------|----->Horizontal menu Library | ^ | | | | | ----------------|----->Scrollers | (|) | ^ |------- ----------------|----------| | | | v v | Viewers | | | v | Main Program | The idea is quite simple: the application is made up of a number of modules that call each other and exchange messages in order to comunicate what each wants the other to do. Messages are a couple of smallints that travel upwards (as parameters passed to the next module) and downwards, as values returned. Let's have a closer look at each type of module: "Viewers" stay at the bottom of the stack: they serve to handle completely a particular type of data (which may be complex, i.e. multi table, etc). A viewer is responsible of the retrieval of the data and its display on the screen. As such it must know how to: - display the data on demand (e.g. display a form, fill it with data, scroll a screen array up or down, etc) - perform db related functions on demand (open, close & free cursors, fetch rows) Depending on what the viewer does, it may be capable of performing, at the user request, actions on the data it handles either directly or with the aid of "Services". Such actions include: - the selection of data to be retrieved - data manipulation (insert/delete/modify records) - data printout "Services" are the modules used to carry out actual data manipulation. Horizontal & vertical"Menus" interface directly with the user, allowing him to choose the operations he wishes to perform. Menus wait for the user to select an action and then either call a service to perform whatever the user wants to be done, or pass the request back to the current viewer. Any given message can be associated with any of the following: - a horizontal menu entry - a vertical menu entry - a cursor or control key also, menus can be freely cascated, and these to facts allow the programmer to (re)design the user interface without modifications to viewers or service modules. Services can be called either by viewers or by menus, depending on the programmer wish, to allow to perform common, data type related tasks (insert, delete, modify records) without having to inform the menu on what to do, & to perform viewers unrelated operations without replicating such knowledge on the viewers themselves. The beauty of the system is in the fact that each service, however invoked, is free to screw up the screen (or the DB) in whatever way it needs to: on return a message will inform the viewer of the actions it needs to take to return to a safe state. The service may for instance open & display a new form, perform data input and insert a new row on a table; the return message will inform the viewer to redisplay its form, redisplay the data and, if the row was inserted in a table being viewed, to reopen the cursor and fetch all the needed rows to reflect the table changes. Viewers will not need to know what has been done, or who has doen it: all they need to restore their previous state is to know what to do next! Messages to the current viewer include also request to carry out operations like scroll up, scroll down the video, etc and most important, request to close down and return to the main program to either stop the application or switch to another viewer. The main program is only a viewer spawner: just a while statement with a big case inside. Having more than one viewer makes the application *modal*: the mode of operation depends on the capabilities of each viewer; apart from that services would make the application modal anyway: on a given moment the application could be in viewing mode, select mode or input mode. Now, I can hear you saying "Ok, this looks great (maybe!), but where's the code reusability?!?, I'll have to write all the data display functions from scratch!" Don't panic, we have "scrollers"! Scrollers take all the hassle out of viewer development by placing all the common data retrieval & display function in one convenient module. A viewer written to use a scroller sends & receives messages from/to this rather than to the menu system. The scroller filters messages from the viewer and the menu, performing all the d