Automatic Error Handling and Prototyping [ Getting Started With TRANSACT V ] MPE/iX 5.0 Documentation
Getting Started With TRANSACT V
Chapter 5 Automatic Error Handling and Prototyping
This section will demonstrate how easy it is to develop a working
prototype of an application system by taking advantage of Transact's
power, in particular the automatic error handling facility.
We will take a particular example and follow it from the initial
prototype attempt until the finished product emerges.
Usually, when prototyping of a system is discussed, it is thought of in
terms of throwaway code. This need not be the case with Transact.
Unlike most other application development tools, Transact is a complete
procedural language. However, as an integral part of the language, there
are high level, more nonprocedural types of constructs that provide the
true power of the language.
These high-level constructs and facilities can be used to advantage to
produce a working prototype of a system. The prototype can then be
reviewed with and even developed with the user community until mutual
agreement has been reached as to the functionality of the system and its
appearance to the user.
Because agreement can be reached much more quickly than with traditional
languages, prototyping is a viable tool to help get the users more
involved. At the same time, the effort of the application developer is
not wasted because the code does not need to be thrown away as the
production system is developed. Instead, much of the code can be
retained as is, and only those procedures where Transact's automatic
facilities do not provide the required control need to be expanded to
provide the necessary control. The emphasis on expansion is there
because typically the code is not rewritten at this point, but additional
options are added to existing Transact constructs and additional code is
written to provide the necessary control.
The example that we will develop in this chapter consists of providing
the functionality to add an order to the database. We could prototype
the database design, forms design, etc., as well as the program design,
but let's assume that there are valid reasons to have the database design
remain as it is. We will concentrate on how we present data to the user
and get data from the user.
This program is our first attempted solution:
____________________________________________________
| |
| 1 system ex36,base=orders,vpls=formfile;|
| 2 list(auto) vorderhead; |
| 3 list(auto) vorderline; |
| 4 get(form) vorderhead,init,freeze; |
| 5 put orderhead,list=(order-no, |
| 6 cust-no, |
| 7 order-status, |
| 7.01 order-date); |
| 8 level; |
| 9 get(form) vorderline,init,append; |
| 10 put orderline,list=(order-no, |
| 11 line-no, |
| 12 part-number, |
| 13 quantity); |
____________________________________________________
Figure 5-1. Basic prototype program for adding data
This program would not be considered a good working version, since it
will only add one order. It must be restarted to add another order.
However, the program does allow us to demonstrate or prototype for our
user the data flow for adding an order to the database.
The program first displays and inputs data using the vorderhead form
(line 4), then adds this data to dataset orderhead (lines 5 to 7).
It will then repeatedly (line 8) use form vorderdetail to display, input
(line 9), and add data to dataset orderline (lines 10 to 13) each time we
press [[ENTER]]. A new vorderdetail form is put onto the screen for each
line of the order. Each form is appended to the preceding form. An
example of entering an order with three lines follows:
___________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [123 ] customer [1 ] status [0 ] date [850101]|
| line number [1 ] part-number [p001 ] quantity [12 ] |
| line number [2 ] part-number [p002 ] quantity [12 ] |
| line number [3 ] part-number [p003 ] quantity [20 ] |
| line number [ ] part-number [ ] quantity [ ] |
___________________________________________________________________________________
Figure 5-2. Running the basic prototype program
When we have entered the last order line, pressing [[ F8 ]] gets us back
to the point where we can either exit the program or restart it.
Thus with just a small amount of code, we can generate a program that
adds data to two datasets. We can use this program to verify with the
user that we are creating the correct solution and we can also use this
program to enter data that can be used to test other modules within the
system.
Perhaps our prototype should have started with a version that could add
more than one order to the database. Even so, the first version is
important to emphasize how much can be accomplished in Transact with a
small amount of code.
A prototyping version which will add more than one order follows:
________________________________________________________________
| |
| 1 system ex37,base=orders,vpls=formfile; |
| 1.1 define(item) lastkey i(4): |
| 1.2 enter i(4),init=0; |
| 1.3 list lastkey: |
| 1.4 enter; |
| 2 list(auto) vorderhead; |
| 3 list(auto) vorderline; |
| 3.1 level; |
| 4 get(form) vorderhead,init,freeze; |
| 5 put orderhead,list=(order-no, |
| 6 cust-no, |
| 7 order-status, |
| 7.01 order-date); |
| 8 level; |
| 9 get(form) vorderline,init,append,fkey=lastkey;|
| 9.1 if (lastkey) = (enter) |
| 9.2 then |
| 10 put orderline,list=(order-no, |
| 11 line-no, |
| 12 part-number, |
| 13 quantity) |
| 14 else |
| 15 do |
| 16 set(form) vorderline,clear; |
| 17 end(level); |
| 18 doend; |
________________________________________________________________
Figure 5-3. Prototype program to add multiple master records
Here we have added an additional level (line 3.1) to our program to
control entering each order; we still retain the level that controls
adding order lines.
We also added a test to see whether the [[ENTER]] key was last pressed
(lines 9.1 to 9.2) or whether one of the function keys was pressed
(pressing [[ENTER]] sets 0 to lastkey; pressing any function key sets the
number of that key to lastkey). Pressing any of the function keys (lines
14 to 18) is our way of indicating that all order lines have been entered
and we want to enter a new order now.
In order to find out what key was pressed by the user, line 9 was
modified by adding an option to tell Transact where to put this
information and lines 1.1 to 1.4 were added to define the variable
lastkey.
As a side note, the variable enter was set up to improve program
readability when checking if [[ENTER]] was pressed.
What happens if we enter some invalid data using this prototype?
Transact's automatic error handling takes over and redisplays the screen,
while asking for new input. It also attempts to let us know what caused
the error. For example, cust-no is a numeric field. If non-numeric data
is entered, Transact displays an error message in the VPLUS window,
pauses for a few seconds to give us the opportunity to read the message,
and then redisplays the screen that was in error for us to enter data
again. The following screen illustrates that process.
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [123 ] customer [CUST1] status [0 ] date [850101]|
| |
| |
| |
| *ERROR: ENTRY NOT NUMERIC (USER 1,10) |
_____________________________________________________________________________________
Figure 5-4. Automatic error handling with VPLUS
Things are more complicated if an error occurs on form vorderline because
it is displayed using the APPEND option. After Transact displays the
error message, the new form for data entry is appended to the last form.
Thus the line in error remains on the screen and a new empty form for
correcting the error is added to the screen. The two example screens
below illustrate this point.
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [123 ] customer [1 ] status [0 ] date [850101]|
| line number [1 ] part-number [PART1 ] quantity [10 ] |
| |
| |
| |
| *ERROR:THERE IS NO CHAIN HEAD (MASTER ENTRY) FOR PATH 2 (IMAGE 102,32,ORDERLIN|
_____________________________________________________________________________________
Figure 5-5. Automatic error handling with VPLUS append
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [123 ] customer [CUST1] status [0 ] date [850101]|
| line number [1 ] part-number [PART1 ] quantity [10 ] |
| line number [ ] part-number [ ] quantity [ ] |
| |
| |
_____________________________________________________________________________________
Figure 5-6. Automatic error handling with VPLUS append
Up to this point, no order line has been added to the database. The
valid line number, part-number, and quantity would be entered into the
blank form line.
After you have a good understanding of the VPLUS interface using
Transact, you will discover that there are ways to get automatic error
handling to do what you want it to, even when using the APPEND and FREEZE
options. The following version of our program demonstrates this. No
functionality has been added. Only code to make automatic error handling
properly display the correct screen format has been added.
____________________________________________________________
| |
| 1 system ex38,base=orders,vpls=formfile; |
| 1.1 define(item) lastkey i(4): |
| 1.2 enter i(4),init=0; |
| 1.3 list lastkey: |
| 1.4 enter; |
| 2 list(auto) vorderhead; |
| 3 list(auto) vorderline; |
| 3.01 set(form) vorderhead,init,list=(); |
| 3.1 level; |
| 4 get(form) vorderhead,fkey=lastkey; |
| 4.1 if (lastkey) <> (enter) |
| 4.2 then |
| 4.3 do |
| 4.4 set(form) vorderhead,init,list=(); |
| 4.5 end(level); |
| 4.6 end; |
| 4.7 doend; |
| 5 put orderhead,list=(order-no, |
| 6 cust-no, |
| 7 order-status, |
| 7.01 order-date); |
| 7.1 set(form) vorderhead,freeze; |
| 7.2 put(form) vorderline,init,list=(); |
| 8 level; |
| 9 get(form) vorderline,fkey=lastkey,current;|
| 9.1 if (lastkey) <> (enter) |
| 9.2 then |
| 9.3 do |
| 9.4 set(form) vorderhead,init,list=(); |
| 9.5 end(level); |
| 9.6 end; |
| 9.7 doend; |
| 10 put orderline,list=(order-no, |
| 11 line-no, |
| 12 part-number, |
| 13 quantity); |
| 19 set(form) vorderline,append; |
| 20 put(form) vorderline,init,list=(); |
____________________________________________________________
Figure 5-7. Functional prototype with automatic error handling
This version delays specifying whether a form is to be frozen or appended
to another form until the last possible moment. Recall that our goal is
to first display a blank form for entering global order information. If
there are any errors in the data, then the form should not be cleared,
since that would require the user to re-enter all data.
Once the global information has been entered, then each line of the order
is entered. If the data is invalid, the form for that line should not be
cleared, but left for correction of the data.
Line 3.01 initially clears form vorderhead. Line 4 has been modified to
capture the key pressed by the user. If any of the function keys are
pressed, it indicates that no more orders are to be entered. Lines 4.1
to 4.7 perform this function and cause the program to end if the user
presses any of [[ F1 ]] through [[ F8 ]].
If the user presses [[ENTER]], Transact will continue to loop through
lines 4 to 4.7 until the data entered is valid. When this occurs, line
7.1 freezes the form on the screen so that the forms to enter each order
line will appear after this form.
Line 7.2 displays the first form for entering an order line after
blanking it out. This is an important step and gets us started in our
order line data collection loop.
Line 9 is the important line within this loop. It specifies that we want
to work with the form currently displayed on the screen. This is also
where the automatic error handling will restart if Transact discovers any
input errors. It is this line the prevents the problem discussed in the
previous example from happening; that is, it prevents automatic error
handling from putting a fresh form on the screen when it encountered data
errors.
Lines 9.3 through 9.7 detect that the user has pressed any of [[ F1 ]]
through [[ F8 ]] to indicate that all lines have been added for the
order. It reinitializes vorderhead and terminates the level.
Lines 19 through 20 are reached after a valid order line has been added
to the database. They specify that the next form is to be appended to
the screen and put a new blank form on the screen so that the loop can be
started again.
So far, we are only letting the automatic error handling detect the
entering of non-numeric data into a numeric field and trying to add an
entry that is missing a master.
There are additional validation checks that can be handled automatically.
The next version of our prototype implements these checks.
____________________________________________________________
| |
| 1 system ex39,base=orders,vpls=formfile; |
| 1.1 define(item) lastkey i(4): |
| 1.2 enter i(4),init=0; |
| 1.3 list lastkey: |
| 1.4 enter; |
| 2 list(auto) vorderhead; |
| 3 list(auto) vorderline; |
| 3.01 set(form) vorderhead,init,list=(); |
| 3.1 level; |
| 4 get(form) vorderhead,fkey=lastkey; |
| 4.1 if (lastkey) |
| (enter) |
| 4.2 then |
| 4.3 do |
| 4.5 end(level); |
| 4.6 end; |
| 4.7 doend; |
| 4.8 set(key) list (order-no); |
| 4.9 get order,list=(),nofind; |
| 4.91 set(key) list (cust-no); |
| 4.92 get customer,list=(); |
| 5 put orderhead,list=(order-no, |
| 6 cust-no, |
| 7 order-status, |
| 7.01 order-date); |
| 7.1 set(form) vorderhead,freeze; |
| 7.2 put(form) vorderline,init,list=(); |
| 8 level; |
| 9 get(form) vorderline,fkey=lastkey,current;|
| 9.1 if (lastkey) |
| (enter) |
| 9.2 then |
| 9.3 do |
| 9.4 set(form) vorderhead,init,list=(); |
| 9.5 end(level); |
| 9.6 end; |
| 9.7 doend; |
| 9.8 set(key) list (part-number); |
| 9.9 get parts,list=(part-number); |
| 10 put orderline,list=(order-no, |
| 11 line-no, |
| 12 part-number, |
| 13 quantity); |
| 19 set(form) vorderline,append; |
| 20 put(form) vorderline,init,list=(); |
____________________________________________________________
Figure 5-8. Prototype with programmatic data validation
Figure 5-8 will help you see how automatic error handling can work for
you.
In this version, lines 4.8 and 4.9 have been added to verify that the
order now being entered does not already exist. The NOFIND option on
line 4.9 specifies that it is not an error if a record is not found. It
is an error if a record is found. If the error occurs, automatic error
handling will display a message and restart at the data collection point,
which is line 4.
Lines 4.91 and 4.92 verify that the customer already exists. If not, the
program is restarted at line 4 after displaying the error message.
Lines 9.8 and 9.9 validate the part number. If the part number does not
exist, the program is restarted at the last data entry point which is
line 9.
The examples below illustrate the messages generated by the automatic
error facility when there are errors, such as:
* order already exists
* customer is invalid
* part number is invalid
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [123 ] customer [1 ] status [0 ] date [850101]|
| |
| |
| |
| *ERROR: ENTRY ALREADY EXISTS (IMAGE 1,23,ORDER) |
_____________________________________________________________________________________
Figure 5-9. Automatic error handling, duplicate record
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [124 ] customer [987 ] status [0 ] date [850101]|
| |
| |
| |
| *ERROR: NO ENTRY FOUND (IMAGE 17,27,CUSTOMER) |
_____________________________________________________________________________________
Figure 5-10. Automatic error handling on frozen screen
_____________________________________________________________________________________
| |
| vorderhead order data |
| |
| order number [124 ] customer [1 ] status [0 ] date [850101]|
| line number [1 ]] part-number [PART1 ] quantity [10 ] |
| |
| |
| |
| *ERROR: NO ENTRY FOUND (IMAGE 17,55,PARTS) |
_____________________________________________________________________________________
Figure 5-11. Automatic error handling on appended screen
When using this version of the prototype to demonstrate to the users how
the system operates, we explain what each particular message means, for
example, that we were attempting to add an order for a customer, but the
customer is not valid. We could also explain that when the production
version of the system is implemented, the error message will
appropriately say "invalid customer" and that it will highlight the
customer field for data correction.
However, these details do not have to be addressed until the user agrees
with the overall system design and flow.
Finally, the user agrees with our system design. The user may also agree
to use the system "as is" or he may agree to use the system temporarily
until the final version is ready. Most production environments will
probably need the additional control in order to make the system more
user friendly.
The production version of our prototype follows. The automatic error
handling provided by Transact has been replaced with programmatic control
and user defined error messages.
____________________________________________________________________________________
| |
| 1 system ex40,base=orders,vpls=formfile; |
| 1.1 define(item) lastkey i(4): |
| 1.2 enter i(4),init=0; |
| 1.21 define(item) valid i(4): |
| 1.22 yes i(4),init=1: |
| 1.23 no i(4),init=0; |
| 1.24 list valid: |
| 1.25 yes: |
| 1.26 no; |
| 1.3 list lastkey: |
| 1.4 enter; |
| 2 list(auto) vorderhead; |
| 3 list(auto) vorderline; |
| 3.1 level; |
| 3.2 set(form) vorderhead,init,list=(); |
| 3.3 repeat |
| 3.4 do |
| 3.5 let (valid) = (yes); |
| 4 get(form) vorderhead,fkey=lastkey; |
| 4.1 if (lastkey) |
| (enter) |
| 4.2 then |
| 4.3 do |
| 4.5 end(level); |
| 4.6 end; |
| 4.7 doend; |
| 4.8 set(key) list (order-no); |
| 4.9 find order,list=(); |
| 4.901 if status > 0 |
| 4.902 then |
| 4.903 do |
| 4.904 set(form) vorderhead,window=(order-no,"order already exists");|
| 4.905 let (valid) = (no); |
| 4.906 doend; |
| 4.91 set(key) list (cust-no); |
____________________________________________________________________________________
Figure 5-12. Production version of prototype program
______________________________________________________________________________________
| |
| 4.92 find customer,list=(); |
| 4.93 if status = 0 |
| 4.94 then |
| 4.95 do |
| 4.96 set(form) vorderhead,window=(cust-no,"customer does not exist");|
| 4.97 let (valid) = (no); |
| 4.98 doend; |
| 4.99 doend |
| 4.991 until (valid) = (yes); |
| 5 put orderhead,list=(order-no, |
| 6 cust-no, |
| 7 order-status, |
| 7.01 order-date); |
| 7.1 set(form) vorderhead,freeze; |
| 7.2 set(form) vorderline,init,list=(); |
| 8 level; |
| 8.1 repeat |
| 8.2 do |
| 8.3 let (valid) = (yes); |
| 9 get(form) vorderline,fkey=lastkey; |
| 9.1 if (lastkey) |
| (enter) |
| 9.2 then |
| 9.3 do |
| 9.5 end(level); |
| 9.6 end; |
| 9.7 doend; |
| 9.8 set(key) list (part-number); |
| 9.9 find parts,list=(part-number); |
| 9.91 if status = 0 |
| 9.92 then |
| 9.93 do |
| 9.94 set(form) vorderline, |
| 9.95 window=(part-number,"invalid part number"); |
| 9.96 let (valid) = (no); |
| 9.97 doend; |
| 9.98 if (quantity) <= 0 |
| 9.99 then |
| 9.991 do |
| 9.992 set(form) vorderline, |
| 9.993 window=(quantity,"must be > 0"); |
| 9.994 let (valid) = (no); |
| 9.995 doend; |
| 9.996 doend |
| 9.997 until (valid) = (yes); |
| 10 put orderline,list=(order-no, |
| 11 line-no, |
| 12 part-number, |
| 13 quantity); |
| 19 set(form) vorderline,append,init,list=(); |
______________________________________________________________________________________
Figure 5-12. Production version of prototype program (cont.
The main thing done to this version is to replace the automatic looping
on data errors until the data is valid with explicit programmatic looping
until the errors are corrected.
Lines 1.21 to 1.26 define new variables to programatically detect whether
a data entry form contains valid data or not. Valid can be viewed as a
switch which is either yes or no depending on whether the data entered is
valid or not.
Lines 3.3, 3.4, 4.99, and 4.991 set up the boundaries of a loop that is
executed until the data entered is valid.
Within the loop, the valid flag will be set to indicate the data is
invalid if an error is found. However, before any data validation is
done, line 3.5 sets the default for the flag to be that the data is
valid.
Line 4.9 changes the verb of the previous prototype from GET to FIND. GET
was useful when depending on the automatic error handling facility,
because when we use GET, Transact assumes that we know the data we want
either exists or doesn't exist. Therefore it is an error if the opposite
condition occurs. When we use FIND though, Transact does not assume that
we know whether the data exists or not. In effect we are asking whether
it does exist or not. Therefore, it is not automatically an error if the
data does not exist.
FIND tells us how many records it found by putting the number of records
in the system variable called STATUS. Lines 4.901 to 4.906 detect whether
the user is attempting to add an order that already exists. If so, line
4.904 uses the WINDOW option to highlight the order-no field as being in
error and to display the error message "order already exists" in the
VPLUS form window.
Lines 4.92 to 4.98 perform a similar validity check on the cust-no field.
The only difference is that the error occurs if there is no existing
customer record.
Lines 8.1, 8.2, 9.996, and 9.997 set up a loop that will repeat until the
data for an order line item is valid.
Lines 9.91 to 9.97 validate the part-number.
Lines 9.98 to 9.995 perform an additional validation on the order
quantity which we could not do using automatic error handling.
MPE/iX 5.0 Documentation