The Standards Manual

1. Introduction

For programs to be easily understandable to others and to yourself at a later date, it is important that all program documentation, which includes not only the source code but also design documents, test plans etc, should adhere to well defined standards.

In the coursework for this module you are expected to keep to the standards defined below.

2. Source code

For ease of understanding, source code should strictly adhere to the following rules.

2.1. Use of comments

For the purposes of these standards, comments are described as long or short. Long comments are delimited /* ... */ and typically occupy several lines, short comments start with // ... and are either on lines of their own or at the ends of program lines.

Five categories of comment are identifiable in source code, these are :-

2.2. Program layout

2.3. Variable and method naming

Class names should ALWAYS start with a capital letter. EVERYTHING else should start with a small letter.

Unless a variable is being used for a loop counter, variable names should be meaningful and if they represent a phrase, each word of the phrase (except the first) should start with a capital letter. Avoid using underscores. Hence :-

      bookLoanDate

rather than :-

      book_loan_date

or :-

      bld

2.4. Use of methods

It is important for ease of understanding that code should be as concise as possible and should occupy as small an amount of space as possible without it being crammed together.

One of the most powerful ways of achieving this is to avoid repetition of similar code whenever possible. This can be done in three ways :-

To illustrate the point, the following segment of code takes command line arguments and reverses the strings before displaying them :-

First attempt - three strings each of three characters :-

   String temp;    //variable to store string before printing
 
   //reverse first string

   temp = "";                         //empty string
   temp = args[0].charAt(2);          //pick up last character
   temp = temp + args[0].charAt(1);   //pick up middle character
   temp = temp + args[0].charAt(0);   //pick up first character
   System.out.println(temp);          //display result

   //reverse second string

   temp = "";                         //empty string
   temp = args[1].charAt(2);          //pick up last character
   temp = temp + args[1].charAt(1);   //pick up middle character
   temp = temp + args[1].charAt(0);   //pick up first character
   System.out.println(temp);          //display result

   //reverse third string

   temp = "";                         //empty string
   temp = args[2].charAt(2);          //pick up last character
   temp = temp + args[2].charAt(1);   //pick up middle character
   temp = temp + args[2].charAt(0);   //pick up first character
   System.out.println(temp);          //display result

This is highly repetitive and extremely restrictive. By using control structures we can make the code handle ANY number of command line arguments of ANY length in far less space :-

   String temp;    //variable to store string before printing
 
   //for all command line arguments

   for (int i = 0; i < args.length; i++) {

      // reverse and display argument

      temp = "";                                    //empty string
      for (int j = 0; j < args[i].length(); j++) 
         temp = temp + args[i].charAt(j);           //add in character
      System.out.println(temp);                     //display result

   } //end for

Similar benefits can be achieved by use of methods :-

   /* returns the string supplied as a parameter with the
      letters reversed
   */
   public static String reverse(String original) { 
      String temp = "";                          //declare local empty string
      for (int i = 0; i < original.length(); i++) 
         temp = temp + original.charAt(i);       //add in character
      return temp;                               //return result
   } //end reverse

   public static void main(String [] args) {
      //for all command line args, reverse and display
      for (int i = 0; i < args.length; i++)
         System.out.println(reverse(args[i]));
   } //end main      

Someone more familiar with the language will know that a StringBuffer already has this capability and might write :-

    StringBuffer sb;
    //for all command line args, reverse and display

    for (int i = 0; i < args.length; i++) {
       sb = new StringBuffer(args[i]);
       System.out.println(sb.reverse().toString());
    } //end for

The first solution is bad, the second and third acceptable for novice programmers and the last to be expected of a professional.

2.5. Use of language features

The example above clearly illustrates the importance of being aware of what the language can do and how it can be used most effectively to solve problems.

You need to browse the standard class libraries from time to time to build up an awareness of what is available. This will save a great deal of effort and re-invented wheels.

3. Program design

An important element of the program documentation is the design documents. On this course we will be concentrating on the use of pseudo-code to design programs and document those designs.

Later on when we come to consider object-oriented design we will be making use of some of the notation of the Unified Modelling Language (UML) which consists of a set of diagramming conventions.

3.1. Pseudo-code

Good pseudo-code should be :-

This can be difficult to achieve, but is well worth the effort.

Program structure is represented by sequences of statements, repeated sections of ccode and if - then - else alternatives. To this end, it is suggested that the following conventions are used :-

Repetition :-

   for  ...
     statements to be repeated
     are written here
   end for

   while ...
     statements to be repeated
     are written here
   end while

   do
     statements to be repeated
     are written here
   while ...   

As these conform closely to Java syntax, the final translation from pseudo-code to code is straightforward.

Selection :-

   if ... then
     statements for condition = true
     are written here
   else
     statements for condition = false
     are written here
   end if      

   if ... then
     statements for condition = true
     are written here
   end if

Note the following :-

Pseudo-code can be written at various levels of detail and in a typical design you would expect to see at least two levels od pseudo-code.

Individual statements, conditional expressions etc can be written in simple English, but the aim is to be concise without loosing meaning. Don't write long paragraphs and don't write code.

At times, particularly at lower levels of detail, variables need to be introduced to aid conciseness and to be able to describe conditions etc. Again, don't use data types for specific languages but rather more generic types such as :-

   integer   - for all integer types
   real      - for all floating point types
   character - for single characters
   boolean   - for truth values
   string    - for character strings

Variables should be defined and described at the head of the pseudo-code.

When decomposing designs into a set of modules (methods), the pseudo-code should be given separately for each module and the input parameters, output parameters and return types should be defined.

To make this clear, the following is an example of a pseudo-code design for a program which accepts a number of integer values (input being terminated by a negative value) and then sorts them into ascending order before displaying them.

First level design :-

   read in integer values
   sort in ascending order
   display sorted values

This clearly indicates three steps but doesn't take us very far towards a solution. The next level of design might be :-

   value : integer  * temporary store for input value
   data : array of integer  * store for data values

   * read in integer values
   prompt for and get value
   while value >= 0
      store value in data
      prompt for and get value
   end while
   
   * sort in ascending order
   for all elements (i) in data except last
      for all elements (j) in data starting from i + 1
         if data(j) < data(j-1) then
            swap array elements
         end if
      end for
   end for

   * display sorted values
   for all elements in data
      display element value
   end for

As a final step, recognizing that the sort routine might be needed on another occassion, we can separate it and the other two components into three methods and re-write the pseudo-code as follows :-

   * main application
   data : array of integer  * store for data values

   getdata(data)
   sort(data)
   display(data)


   * module - getdata
   output parameter - data : array of integer     * entered values
   value : integer    * temporary store for input value

   prompt for and get value
   while value >= 0
      store value in data
      prompt for and get value
   end while
   

   * module - sort
   input/output parameter - data : array of integer   * entered values

   for all elements (i) in data except last
      for all elements (j) in data starting from i + 1
         if data(j) < data(j-1) then
            swap array elements
         end if
      end for
   end for


   * module - display
   input parameter - data : array of integer    * sorted values

   for all elements in data
      display element value
   end for

This will now simply translate into Java code giving a main method and three other methods, getdata, sort and display.

3.2. Class diagrams

3.3. State charts

3.4. Sequence diagrams

4. Documentation

5. Test plans and logs

An important part of program documentation is the test plan and the test log - particularly the test plan. This describes the tests to be conducted to confirm that the program is working correctly and a good test plan provides a significant amplification of the program specification and can be used during the design process.

Test plans are invaluable when, during maintenance, revisions have to be made to the code as they define what testing is necessary to ensure bugs have not been introduced.

Test logs simply record the result of tests that have been carried out and are valuable in tracing the introduction of bugs into code during maintenance.

5.1. Test plans

These should be laid out in tabular form as follows :-

   +--------+--------------+------------------+----------------------+
   | Test   | Purpose of   | Input data to be | Expected output from |
   | number | test         | used in the test | the test             |
   +--------+--------------+------------------+----------------------+
   |  1     |              |                  |                      |
   |        |              |                  |                      |

Tests should be designed to cover normal program operation and explore all the programs variety of behaviour and to examine all error cases and special or unusual circumstances.

For instance, given the earlier program design above, test cases might include :-

5.2. Test logs

Test logs simply record, again using a tabular layout, the results of tests previously carried out. A layout as folows is suggested for this :-

   +--------+---------+------------------+--------------------------+
   | Test   | Date    | Results obtained | Corrective action taken  |
   | number | of test | from test        | or test OK               |
   +--------+---------+------------------+--------------------------+
   |        |         |                  |                          |
   |        |         |                  |                          |

The principle here is that if a test fails, once corrective action has been taken so that the test is successful, all previously passed tests must be re-run. In other words, all tests in the test plan must have been executed correctly without any changes having been made before program is deemed to be correct.