The purpose of this section is to provide guidelines for these modifications so that the reliability and maintainability of the program are preserved. As the number of programs in an application and the number of programmers increase, having standards that all programmers follow becomes increasingly important.
These guidelines are not to be considered as absolute statements of style, but as methods to follow unless the logic of the application dictates otherwise.
The guidelines here are specific to VMS Basic and it assumed that the reader is familiar with the language. However most of these guidelines can be generalized to other languages.
The DO key should cause any changes made to be saved by writing the changes to disk. A check should be made that pressing the DO key does not cause a program to skip some edit checks such as a required field that is currently blank. If an edit check fails, an error message should be generated and the program should go to the field that failed the edit check.
This key should cause the program to exit the current section or, if at the beginning of a program, exit the program. A user should be able to press F10(E xit) repeatedly and eventually return to a menu.
If the exit will cause changes to be lost then the prompt 'Sure abandon changes' should be displayed with a default of N. If the user enters Y or F10 (Exit) then the changes should be discarded and the exit taken. If the user enters N or any other function key, the program should return to the field that the F10(Exit) was typed.
Although it is possible to write a program without using any GOTO statements, this causes much unnecessary complication in a real business program. The current trend in "structured programming" to not use GOTO statements is overcompensating for programs with too many GOTO's. Do not introduce new "flag" variables into a program when a simple GOTO solves the problem. Maintainable programs reflect the logic of the application.
Use SELECT instead of multiple IF statements. For example the following code can be confusing to read because you have to examine all the tests to determine what the program will do.
IF A = X THEN
IF A = Y THEN
IF A = Z THEN
It should be written as :
The file name included should always have a logical such as SOURCE or DSILIB. This will allow the program to be compiled when it is inside a CMS library.
OPEN statements should always be inside a WHEN ERROR IN block. There should be only one OPEN in an error block. The file name in an OPEN statement should be the same as the message in the PGMERR trap for the open. If the file name is a variable, use the variable in the error message also.
Do not use physical device names in any program or command procedure. The only command procedure that should reference a physical device is the command procedure called by the system startup to establish logicals names.
If the file name is a logical name, use a : at the end so that the program will not accidentally create a new file if the logical is not defined. For example if the logical INVOICES is defined as DATA:INVOICE..DAT use OPEN 'INVOICES:'
If all the cases in a select specify a particular value and the program would produce undesirable or unpredictable results if a value was used that didn't match any of the test, use a CASE ELSE with a call to PGMERR showing the value in the error message.
WHEN ERROR IN
The Basic commands DELETE, FIND, GET, INPUT, KILL, OPEN, PUT, UPDATE, VAL, should be inside a WHEN ERROR IN block. Also a division, if it is possible to have a divide by zero.
The USE section should explicitly trap by error number and call PGMERR for any error that was not expected. For example, do not assume that if an error occurs in a key look up with a GET is an error 155, "Record not found." It could also be an error 14, "Device hung or write locked." See also the section on PGMERR.
Although WHILE statements may seem attractive in reducing the number of GOTO's and program labels, they should be avoided as they invariably cause maintenance problems in programs that far outweigh their advantages and are the most common cause of programs going into compute bound loops when unexpected data is encountered.
Use ENTER_SELECT or ENTER_SELECT_2 to validate against a table of values.
Use ENTER_CODE or ENTER_CODE_ALT instead of writing code to validate a response against a database.
Don't use defaults that are invalid according to the input flags.
If further validation of the user response is to be done, use a dummy variable for the response variable, and then perform the validation. If the respone is not valid, return to the CALL ENTER using the same default as the first time. If the response is acceptable, then update the real variable. This prevents the program from defaulting to a known bad value.
All programs should establish a global ON ERROR trap and have it call PGMERR. All other errors should be trapped by putting the appropriate statement inside a WHEN ERROR IN block.
The message in the PGMERR should be unique throughout the entire program and all subprograms. It should contain some explanation of what the program was doing, the relevant program label and the module name if in a subprogram. For example a GET should be coded as follows:
CHECK_COMPANY: WHEN ERROR IN GET #COMPANY.CH, KEY #0 EQ COMPANY_NUMBER, REGARDLESS USE CALL PGMERR('GET on COMPANY.CH at CHECK_COMPANY in SUB1') & IF ERR <> 155% CALL ERROR('Invalid Company') CONTINUE GET_COMAPNY END WHEN
All dates should be 8 byte strings. Use DATE8 if a user is going to be asked to enter a date without a time (such as an invoice date). Use VMSDATE for internal dates such as date last changed.