Java Programming
Style, Design and Marking Guidelines
CS1101 (AY2008/9 Semester 1)
School of Computing, National University of Singapore


1 Introduction

This handout describes the programming style and design standards expected of your lab program submissions. This guide contains two main sections: Design (section 4) and typographical style (sections 2, 3). Design considerations are more serious than typographical issues and include issues such as applying object-oriented concepts in structuring your program. Usually, problems with design require some overhaul to your program to improve. Program design also includes the appropriateness of your choice of Java statements, syntax, and algorithms.

Typographical issues on the other hand are problems with presentation or appearance of your program which impair readability. The style recommendations here are based on the author's experience as well as suggestions given in Sun's Java's coding conventions. Until you develop your own programming style, you should adhere to the guidelines described in this document. You may choose to deviate if you so prefer, as long as your style is consistent and acceptable. Discussion leaders - henceforth called the graders - have been briefed to be flexible when grading for style.

Your programs will also be graded by an autograding software CourseMarker, henceforth called the autograder. Subjecting your programs to an autograder and a human grader provides the best of both worlds, with the autograder performing easily automated tasks such as checking the correctness of your programs, hence freeing the graders with more time to perform in-depth study of your programs. Your grader can refer to the autograder's scores and he/she can override its scores. The scores given by your grader are final.

During grading, your grader will manually read your program, highlight, and penalize marks for design and stylistic issues. Unless otherwise stated, the correctness of your program (from the autograder, where applicable) constitutes 60% of the marks while design/style constitutes 40% (more details in section 5 below).


2 Typographical Style - Program Layout

The main goal of the recommendations here is to improve readability and thereby the understanding and maintainability of the code. Violations to this guide are allowed if they enhance readability.

2.1 Organize the parts of your classes with our CS1101 convention

Improve readability by making the location of each class element predictable. In addition, include a program description and the author's identity in the header section of the main .java file.

/**
 * Program: CS1101 Lab 1, <program name>
 *
 * <program description>
 *
 * <comments to grader, if any>
 *
 * @<matric number>
 */

public class <name> 
{
	// Static variables declarations

	// Instance variables declarations

	// Constructors

	// Methods (no specific order)

	// public static void main(...)
}

2.2 Variables should be declared with smallest scope possible

Keeping the operations on a variable within a small scope, it is easier to control the effects and side effects of the variable. Furthermore, when reading the program, referring to the type declaration of the variable is also made easier.

For example,

// AVOID
double x,y;
...
... <many lines of statements unrelated to x,y>
...
...
x = 0;
y = 1;

Variables should be declared at the point where they first become relevant:

// PREFERRED
...
... <many lines of statements unrelated to x,y>
...
...
double x = 0;
double y = 1;

As another example, loop variables should be declared and initialized immediately before the loop:

// PREFERRED
boolean done = false;
while (!done) {
	...
}

Where there are deeply nested blocks, variables which only apply to the inner block(s) should be declared within, for example:

// PREFERRED
for (i=...) {
    for (j=...) {
        for (k=...) {
            double tmp = computeResult(i,j,k);
        }
    }
}
// tmp not needed here...

Counter variables of for statements which are not used outside the loop should be declared within the for statement.

// PREFERRED
for (int i=0; i<100; i++) {
    ...
}

2.3 Declare related variables of the same time in a common statement

For example,

// PREFERRED
double x,y,z;   // Coordinates of a particle

As opposed to:

// AVOID
double x;
double y;
double z;

2.4 Use named constants (final) for magic numbers

Avoid direct use of magic numbers. Constant literals which have special meanings should be named and its named identifier should be used in its place. The exception to this rule is the use of numeric constants in well-defined mathematical formulas (for instance, 4/3*Math.PI*r*r).

Example:

// AVOID
for (int i=0; i<100; i++) {
    ...
}

// PREFERRED
final public static int MAX_LEN = 100;  // static class variable
...
for (int i=0; i<MAX_LEN; i++) {
    ...
}

2.5 Use consistent indentation to emphasize block structure

Code should be properly and neatly indented to emphasize the nested logical structure of the program. Following Sun's convention, an indentation of 4 spaces is recommended (8 is too wide and 2 is too cramp).

Every method block and statement block that follows a for, while, if/else, switch, do/while statement must be indented from its enclosing block.

Comments within a block should follow the indentation level of its enclosing block.

For example,

for (int i=0;i<3;i++) {   // Trailing open-braces is OK

    // Comments should be indented too

    while (true)     // Leading open-braces OK as well
    {
        // More indented comments
        System.out.println("Hello");
    }
}

2.6 Comment major code segments adequately

Major segments of code should have explanatory comments. A major segment may be an iteration block or a method block. Major classes that contain substantial code in it should have a header comment.

2.7 Comment complicated logic, expressions, or algorithms

An "if" block with a complex condition or an expression that's hard to understand should have explanatory comments. For example,

// Check and reject out-of-bounds indices
if (k < 0 || k >= MAX_LEN) { 
	return -1;
}

2.8 Comment instance and class variables

Instance and class variables whose purpose are not immediately clear should be trailed with a brief comment at its point of declaration:

class DelayedPriorityQueue {
    int nsize;    // length of queue
    int npending; // number of nodes awaiting insertion
    ...
}

Collection variables should have a trailing comment stating the common type of the elements of the collection:

ArrayList pointList;  // Variable array of Point objects
Set shapeSet;         // Unorder set of Shape objects

2.9 Avoid superfluous comments

A comment such as:

    i++; /* add one to i */

serves no purpose, adds clutter to a program and does more harm than good.


3 Typographical Style - Identifiers

3.1 Classes must be nouns and written in mixed case starting with uppercase.

Line, LabProgram1, EmployeeRecord, Point, ColoredPoint, TaxCheatException

Naming convention by Sun and used by all Java core packages. Uses typographic conventions to distinguish identifier types.

3.2 Methods must be verbs and written in mixed case starting with lowercase

debitAccount(), binarySearch(), isValid(), getName(), setName(), computeScore()

Naming convention by Sun and used by all Java core packages.

3.3 Variable names must be in mixed case starting with lowercase

line, inputLine, i, j, currNode, prevNode, nextNode, lastName

Naming convention by Sun and used by all Java core packages.

3.4 Final variables (constants) must be all uppercase using underscore to separate words

MAX_ITERATIONS, MAX_LEN, GOLDEN_RATIO, COLOR_DEFAULT, PI

Naming convention by Sun and used by all Java core packages.

3.5 Variables with large scope should have descriptive names

The scope of class and instance variables spans all methods in the class. It is best to use descriptive names for them so that their meanings are immediately clear when they appear within a method. For example, "Node currNode;" is an appropriate instance variable but not "Node n;". The latter, however, is perfectly appropriate if it is a transient variable (see 3.6).

For a similar reason, class names should also have descriptive names (nouns).

3.6 Variables with short scope should have short names

In contrast to the above (3.5), transient variables such as loop counters, temporary references, iterators etc, should have short and easy to recall names as their usage is frequent and their purpose is usually clear.

For example,

// AVOID
for (int theElementIndex=0; theElementIndex<numberOfElements; theElementIndex++) {
    array[theElementIndex] = theElementIndex;
}

is much less readable than:

// PREFERRED
for (int i=0; i < nelems; i++) {
    array[i] = i;
}

3.7 Shorten variable names with naming conventions

Despite the recommendation for descriptive names, identifiers can be short yet descriptive by using abbreviations and/or common naming conventions. For example,

// AVOID
MAXIMUM_LENGTH, numberOfElements, currentNodePointer, tableNumber

can be shortened without losing their descriptive form:

// PREFERRED
MAX_LEN, nElems, pcurr, tableNo

3.8 The name of the object is implicit and should not be repeated in the method name

For example,

line.getLineLength();
matrix.getMatrixElement(i,j);

contains superfluous words whose noun/verb action is more succinctly expressed in:

line.getLength();
matrix.getElement(i,j);

3.9 Use a "get/set" prefix for direct accessors and mutators

For example,

employee.getName();
employee.setName("Tom");

3.10 Use a "is/has/can/should" prefix for boolean variables and methods

For example,

isVisible, isFinished, isFound, isOpen, hasLicense
shouldAbort(), canEvaluate(), isInsideBounds(), isValid()

3.11 Avoid negated variable or method names

Negated variables often results in hard-to-read double-negatives in an expression like !isNotError.

// AVOID
isNotError, isNotFound, isNotValid, cannotOpenFile

// PREFERRED
isError, isFound, isValid, canOpenFile

3.12 Exception classes should be suffixed by Exception

This convention is the standard in Sun's Java core packages.

class OutOfBoundsException {
	...
}


4 Design Considerations

As programs get more complex, program design becomes increasingly important. Decomposing a complex program into smaller, more manageable units and the design of the interfaces between the units are fundamental to good programming. Generally, the constituents of a program unit should be highly cohesive (4.1), and the coupling between program units should be clean and minimal (4.2). Algorithmic logic should be easy to understand (4.4). The program should also be easy to setup and its usage should be intuitive (4.3).

4.1 Build program units which are highly cohesive

Each method or class should consist of closely related elements. If a class or method consists of a mixed-bag of unrelated elements, it often indicates a need to modularize the code into further cohesive program units.

As a general rule, each function/method should do only one thing. This should be done so that the conceptual unit can be understood easily. Sometimes it will be convenient to do two things in a function because you're working on the same data. Try to resist this temptation. Make two functions if you reasonably can.

Often the naming of the method indicates its cohesiveness. Does the method only do what its name says, or does it do more than that? If you find that a complete name for one of your method is like openInputAndReadVectorAndComputeSum(..), it is time to break the multitasked method into sub-constituents.

Segments of code which are repeated should be abstracted into a method. This not only results in shorter programs but also makes it easier to maintain and read. The abstracted method then forms a cohesive unit by itself.

(Grader note: Use this marking criteria only after Lecture #7.)

4.2 Avoid tight coupling between program units

If changing one class in your program requires changing another class, then a coupling exists between the two classes. One indicator of program quality is the amount of coupling between your program units.

Coupling indicates a dependency between source codes. Reducing this dependency improves the quality and maintainability of your program. If your application consists of more than one class, some coupling must exists; otherwise the objects can't communicate with one another. The rule of thumb in building Java programs with multiple classes is for each class to provide a minimal and well-defined set of public methods while limiting the accessibility of everything else (using the private modifier).

(Grader note: Use this marking criteria only after Lecture #7.)

4.3 User-unfriendliness

Is the program particularly difficult to use?

4.4 Unnecessarily complicated logic

Simplicity is a virtue. Wherever possible, your program should be simple, compact, and easy to read. For example, long chains of nested if/else statements can often be replaced with a more compact form for evaluating the logic. If you find that the logic in your code is getting very unwieldy, rethink and rewrite it.

4.5 Use of Forbidden Syntax

Some labs may expressly disallow the use of certain syntax. Generally, using syntax, statements or Java classes which are not yet covered either in class or in the lab handouts is strongly discouraged. The lab assignments are designed such that you should not need to do so. If the objective of the assignment is undermined, the penalty for using such forbidden syntax will be heavy.

4.6 Use of inappropriate syntax or data types

For instance, if all the inputs to a problem are integers, the program should refrain from introducing any variables of floating-point type. Similarly, it should refrain from invoking any methods which involve floating-point types.

Other examples including using while instead of for when the number of iterations is easily determined before the loop.

4.7 Gross Inefficiency

Although in CS1101 we are not too concerned about order-of-growth efficiencies, any obvious inefficiencies which can easily be avoided must not be present, or they will be penalised.

4.8 Checking for Data Validity

It is not easy to write fool-proof and robust programs from the start. Unless otherwise stated, you may assume that the input data used to test your programs are all valid and are according to the problem specification. Hence, you do not need to write extra code to check for data validity unless otherwise stated. As we go along, we may include such requirement, especially after topics such as exceptions are covered.

5 Grading Guidelines

Each program has a maximum score of 100%. The correctness of a program constitutes certain portion of the score while design and style constitutes the remaining of the score. For example, if correctness constitutes 60% and design and style 40%, the final score computation would be:

\begin{displaymath}
Correctness (60\%) + Design/Style (40\%) = Total (100\%)
\end{displaymath}

5.1 Correctness

Where an autograder is used, the correctness score will be provided by the autograder. The autograder determines program correctness by feeding a set of test data into the program and comparing the output with a set of model answers. The test cases have equal weightage. Therefore, if $N$ test cases were used, and correctness constitutes 60% (which might vary from task to task), then the correctness score is computed by:

\begin{displaymath}
Correctness = (60/N) * PASS
\end{displaymath}

where $PASS$ is the number of cases with correct output. If the autograder is not used, the grader will manually award marks for correctness.

5.2 Appeals

Should any discrepancy, dispute or queries arise in grading, the student should first approach the grader for any explanations. Grader should exercise his/her good judgment in granting appeals, bearing in mind the marking consistency among other programs with similar issues. If the appeal cannot be resolved with the grader, the lecturer shall be the final arbiter in deciding an appropriate resolution.





CS1101
Thu Jul 31 07:28:55 SGT 2008