programming guidelines

7
Subject: Programming Guidelines Author: Ramesh Joshi Purpose The purpose of this document is to record the guidelines I use for programming. The guidelines are a result of the advice and suggestions given to me by my programming Gurus, best practices recommended by the authors of various programming books that I have read since 1980 when I was studying for the Diploma in Computer Management, and my own experience in the IT field since 1982. I do most of the programming in RPG and COBOL, so the guidelines are for these two languages. I recommend these guidelines to my students when I teach them RPG and COBOL. Guidelines 1. Write the code for humans first: Nowadays, the cost of machine time is a lot less than the cost of programmer time. Studies have shown that on an average, a program in a Business Application is modified by nine programmers other than the original author, before the program becomes obsolete or is re-written. Therefore, the program should be made as simple to understand as possible. Studies have also shown that for majority of the modifications, it takes more time for a programmer not familiar with that program to understand the existing code than it takes to modify it after the code has been understood. Many of the subsequent guidelines are based on this principle – Write the code for humans first. 2. Write one subroutine per file per IO operation: A typical Business Application program contains IO operations, for example, in RPG, op-codes READ, READP, WRITE, UPDATE, CHAIN, SETLL etc. For each file used in the program, code only one subroutine for each type of IO. For example, for a direct access to a record, code the CHAIN instruction only once in the program in a subroutine named GetFilename, where the Filename part of the subroutine name should be the actual file name. For example, if the file name is STUDENTS, the subroutine names should be GetSTUDENTS (Chain), PosToSTUDENTS (SETLL / SETGT), WrtSTUDENTS, and UpdSTUDENTS. READ is a bit different, and has been explained later. 3. Have only one Entry Point and one Exit Point: The program should have a single entry point and a single exit point. Each subroutine in the program also should have a single entry point and a single exit point. Never jump to any instruction that is outside the subroutine. 4. Avoid GOTO: The only acceptable GOTO in an RPG program is to its own ENDSR and that too, only if LEAVESR is not supported by the compiler. In COBOL, to its “EXIT” para. (See COBOL programming standards for the information about “EXIT” para.)

Upload: ramesh-joshi

Post on 25-Jan-2017

86 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Programming Guidelines

Subject: Programming GuidelinesAuthor: Ramesh Joshi

Purpose

The purpose of this document is to record the guidelines I use for programming. The guidelines are a result of the advice and suggestions given to me by my programming Gurus, best practices recommended by the authors of various programming books that I have read since 1980 when I was studying for the Diploma in Computer Management, and my own experience in the IT field since 1982.

I do most of the programming in RPG and COBOL, so the guidelines are for these two languages. I recommend these guidelines to my students when I teach them RPG and COBOL.

Guidelines

1. Write the code for humans first: Nowadays, the cost of machine time is a lot less than the cost of programmer time. Studies have shown that on an average, a program in a Business Application is modified by nine programmers other than the original author, before the program becomes obsolete or is re-written. Therefore, the program should be made as simple to understand as possible. Studies have also shown that for majority of the modifications, it takes more time for a programmer not familiar with that program to understand the existing code than it takes to modify it after the code has been understood. Many of the subsequent guidelines are based on this principle – Write the code for humans first.

2. Write one subroutine per file per IO operation: A typical Business Application program contains IO operations, for example, in RPG, op-codes READ, READP, WRITE, UPDATE, CHAIN, SETLL etc. For each file used in the program, code only one subroutine for each type of IO. For example, for a direct access to a record, code the CHAIN instruction only once in the program in a subroutine named GetFilename, where the Filename part of the subroutine name should be the actual file name. For example, if the file name is STUDENTS, the subroutine names should be GetSTUDENTS (Chain), PosToSTUDENTS (SETLL / SETGT), WrtSTUDENTS, and UpdSTUDENTS. READ is a bit different, and has been explained later.

3. Have only one Entry Point and one Exit Point: The program should have a single entry point and a single exit point. Each subroutine in the program also should have a single entry point and a single exit point. Never jump to any instruction that is outside the subroutine.

4. Avoid GOTO: The only acceptable GOTO in an RPG program is to its own ENDSR and that too, only if LEAVESR is not supported by the compiler. In COBOL, to its “EXIT” para. (See COBOL programming standards for the information about “EXIT” para.)

5. Write structured, top-down code: A typical Business Application program contains many files and corresponding IO operations. The IO operations are “routine stuff” if you have followed the guidelines for IO subroutines. You can (and should) create an IO routine for a file by copying corresponding routine already written for another file, and then make file name / field name changes. Place all the IO routines in a program at the bottom of the program. In the main code, “Exsr GetSTUDENTS” is enough for another programmer (even if he / she is not familiar with the IO routine guidelines mentioned above) to understand that a record from the STUDENTS file would be made available to the program by that subroutine. As a thumb rule, reading the top 25% of the C-specs (Procedure Division in COBOL) should clarify 75% of the program’s functionality to a programmer who is not familiar with the program.

6. Use meaningful names: Try to make the variable names and the subroutine names as meaningful as possible. Use mixed case, which is easier to read for most human beings. For example, use ValidateDate instead of VLDDAT; FoundStudent instead of indicator 99. Minimize the use of indicators 1-99.

Page 2: Programming Guidelines

7. Use Prefix keyword in RPG: When using files in RPG, use a distinct prefix for each database file. For input-only files, use prefixes F1, F2, and so on. For files used in other modes, use prefixes FZ, FY, FX, and so on. You may have to write extra code when you do this (Eval, Move etc.) when you want to move the value in the file’s field to somewhere else, but it will save time of the maintenance programmer. I personally know the havoc caused by the “automatic population of multiple fields having the same name” in an organization.

8. Write small subroutines: A subroutine should ideally fit on a single screen, that is, it should ideally be <= 30 lines. Studies have shown that it is easier for programmers to understand a piece of code if the entire code is in front of their eyes. Avoid coding conditional statements where the IF is in the heaven, the ELSE is on the earth, and the ENDIF is in the hell. If a subroutine is exceeding two screenfuls, it generally contains multiple functions, which should be placed in separate subroutines and merely executed from the current subroutine.

9. Avoid using “and” and “or” together in a single condition: Combining “and” and “or” in a single condition makes the code difficult to understand. The compiler may not interpret it the way you are thinking. So, split the condition. It is better to write some additional code now than to make the maintenance programmer look up the manual when an issue is reported by an end user when the application is Live.

10. Write comments and include examples to explain complex code: The original programmer generally has the benefit of documentation (program specs, or functional specs, or emails etc.) and personal discussions with the Business Representative, which help him / her to understand the functionality. The maintenance programmers generally do not have that advantage. They have to rely on the code itself. Including comments and examples in the source code can go a long way in improving the readability of the program.

11. Copy input parameters to program’s own variables: When the parameters are being passed by reference, copy the input parameters to the program’s own variables to avoid the risk of accidentally changing their values.

12. Initialize return parameters: Initialize the return parameters before passing them to a called program.

13. Write four / five subroutines for reading records from a file: Many times, a program in a Business Application needs to read records from a file, select some records, and then process selected records. The actual processing of a selected record is the primary function of the program – reading the file and skipping unwanted records is incidental.

Many times, a program may be processing some range. For example, a program may print reminders to be mailed to customers who owe more than $1000. And for the sake of convenience of mailing, the accounts department may print the letters for customers with names in the range A to I in the first week, J to R in the second week, and S to Z in the third week. The program for printing the letters may be using a file keyed on Customer Name. So, in the first week, the program should, ideally, stop processing after it encounters the first customer record starting with J – should not just keep reading and skipping records beyond I. Similarly, in the second week, it should directly start processing the records from J – should not read and skip records from A to I.

Let me explain the recommended five subroutines with an example. The fifth one is optional – to be used if the file is not to be processed from the beginning, that is, when positioning within the file is required using, for example, SETLL, SETGT in RPG or START in COBOL. The following code snippets should make the concept clear. (The subroutine that checks logical end of file is empty in the code snippet. In the AR letters example mentioned above, it would contain the code to set the EndOfFile variable to “Y” if the Customer Name read from the file is greater than the To Customer Name accepted from the screen.)

*=================================================================* * Files *-----------------------------------------------------------------* FSTUDENTSL2IF E K DISK PREFIX(F1) F RENAME(STUDENTS:F1FMT) ... *=================================================================*

Page 3: Programming Guidelines

* Switches *-----------------------------------------------------------------* D ValidF1 S 1A D F1End S 1A . *=================================================================* * Build Work File (F2/FZ) *-----------------------------------------------------------------* C BuildTmpFile BEGSR C EVAL RexWritten = *Zero C EXSR ReadF1 C DOW RexWritten < RexToBeWritten and C F1End = 'N' C EXSR BuildFZ C EVAL RexWritten = RexWritten + 1 C EXSR ReadF1 C ENDDO * * Records to be written will normally be equal to the * number of rows on the screen, that is, MaxScrLines. * * However, when building the Work File (F2/FZ) for the first * time, an extra record needs to be written. The routine * 'ProcPosTo' takes care of this by setting : * * (RexToBeWritten = MaxScrLines + 1) * * Also, when processing "Repeat Option", all records in F1 are * to be written to the Work File. The routine 'ProcRepeat' * takes care of this by setting : * * (RexToBeWritten = *All'9') * * The following code sets RexToBeWritten for future additions * to Work File. * C EVAL RexToBeWritten = MaxScrLines C ENDSR *=================================================================*. *=================================================================* * Build Work File when Refresh required *-----------------------------------------------------------------* C RebldTmpFile BEGSR C EXSR PosF1Refresh C EVAL F1End = 'N' C EVAL *In91 = *Off C EXSR ReadF1 C DOW F1End = 'N' C EXSR BuildFZ C EXSR StoreRecNo C EXSR ReadF1 C EXSR SetTmpKeyFrF1 C IF TmpKey > PrvLstKey C LEAVE C ENDIF C ENDDO C ENDSR *=================================================================*...

Page 4: Programming Guidelines

*=================================================================* * *-----------------------------------------------------------------* C ReadF1 BEGSR C EVAL ValidF1 = 'N' C DOW ValidF1 <> 'Y' C EXSR ReadF11 C ENDDO C ENDSR *=================================================================* * *-----------------------------------------------------------------* C ReadF11 BEGSR C EVAL ValidF1 = 'Y' C READ F1FMT 91

C IF *In91 = *On C EVAL F1End = 'Y' C GOTO ReadF11X C ENDIF C EXSR CheckEOF1 C IF F1End = 'Y' C GOTO ReadF11X C ENDIF C EXSR SelectF1 C ReadF11X ENDSR *=================================================================* * Check Logical End Of File *-----------------------------------------------------------------*C CheckEOF1 BEGSR C CheckEOF1X ENDSR *=================================================================* * *-----------------------------------------------------------------*C SelectF1 BEGSR C IF F1NUMBER < FRNUMBER or C F1NUMBER > TONUMBER C EVAL ValidF1 = 'N' C GOTO SelectF1X C ENDIF C IF F1NAME < FRNAME or C F1NAME > TONAME C EVAL ValidF1 = 'N' C GOTO SelectF1X C ENDIF C SelectF1X ENDSR *=================================================================* * Position File F1 for Refresh *-----------------------------------------------------------------* C PosF1Refresh BEGSR C EVAL TmpKey = Prv1stKey C EVAL F1NAME = TmpNAME C EVAL F1NUMBER = TmpNUMBER C F1Key SETLL F1FMT C ENDSR *=================================================================*

3

4

2

1

5