-
[Top]
In general, all package, class, method and variable
names should be as descriptive as possible.
Descriptive code is often referred to as self documenting.
The name of a thing should always give one some idea as to the
purpose or function of that thing.
One need not worry about the length of a name (within reason).
After the compilation process, all variable names are
converted to a symbol table reference or offset or some such
thing.
Hence the often used argument that
short variable names make for faster code really only
demonstrates a shocking lack of knowledge of the fundamental
principles of computing!!
For example a variable that holds the user ID number for a
project administrator might be declared as
int projectAdminUserID = 0.
This name is very descriptive; there is little doubt as to the
intended use of this variable.
Conversely, one may declare the same variable as
int pauid=0.
As most individuals will not be able to read
the original author's mind, this variable
name will give few clues as to it's intended use or
the possible values it may hold.
Most of the cost of a given bit of software is incurred in the
maintenance/modification phase.
Hence poorly named entities only serve to escalate this cost and
in many cases serve as a vector for the introduction of new bugs!
-
Class names
[Top]
Classes should be named in Mixed Case, with the
initial letter of each word being in Upper Case.
Class names should not contain any underscore characters.
The name of the class should be descriptive, but not too long.
Abbreviating within class names is discouraged
except when it shortens an already long name.
For example, a few examples of good class names would be:
public class SessionFactory { ... }
public class DocStorageDirectoryException extends Exception { ... }
An few examples of poorly named classes would be:
public class doc_str_dir_class { ... }
public class BIGCLASSTHATDOESLOTS { ... }
-
Method names
[Top]
Method names should also be of mixed case. The name of a method
should be descriptive, contain multiple words (if necessary)
and should not contain abbreviations.
The first word in the method name should be entirely lower case
while subsequent words should have the first letter
capitalized.
For example, a few good method names would be:
public getChildDirectories() { ... }
public addDocumentFromFile( File theFile ) { ... }
-
Variable names
[Top]
Variable naming must follow the same convention as
that proscribed for methods.
Method parameters must follow this naming convention as
well because they are really just locally scoped variables
at the end of the day!!
An example of some good variable names would be:
private int myObjectTypeID = -1;
private Vector myChildDirectoryVector = null;
An example of some poor variable names would be:
int wphc;
boolean ifsoe;
BigDecimal iifsoe;
The above variable names are not very descriptive.
I have noted that
the widespread use of such variable names makes debugging
and/or future modifications a hellish endeavor!!
Consider the last two variables above; they are so
similar syntactically as to make any code difficult to follow.
Poorly named variables such as this must be avoided at all costs!!
In my humble opinion there is simply no good reason to use
variable names of this non-descriptive and obfuscated form.
-
Constant variable names
[Top]
Constants should be entirely in uppercase with
underscores between each word.
It is also worth noting that constants should be declared
final as their values should not
change.
If the constants are
intended to be used outside of their containing class, they
should be declared as static.
An example of some good constant variable declarations would
be as follows:
private final int STATE_QUIT = 0;
public static final int MAX_USERS = 250;
-
Package names
[Top]
Package names must be in entirely lower case.
If a package name is made up of multiple words, run them
together without changing case.
It is preferred that package names consist of single
words such as
webinfo.webdocs.servlet
rather than
webinfotools.webdocsservlets.
It is important to remember that package names have a direct
mapping to a file-system directory structure. Hence, if
the OS one uses has limitations in directory naming schemes,
one should adhere to such limitation when naming packages
as well.
-
[Top]
There is really no easy way to regulate code appearance since
no two developers have the same coding style or preferences.
However, there are some fairly straightforward rules that one
should adhere to.
-
Use indentation in your code. This is usually done
automatically if you
are using an editor such as emacs or xemacs operating in
C++ or Java mode.
The recommended style is old-K&R or KNF, which is:
if ( foo ) {
bar();
} //end if
-
Don't place multiple statements on one line.
One statement per line is the maximum!!
Lines that have to be wrapped on an 80 column xterm are hard
to read and even harder to print
What not to do:
if ( lifeIsShort ) { playHard(now); return; } );
The following is the preferred format:
if ( lifeIsShort ) {
playHard(now);
return;
}
-
Avoid overly lengthy code.
Declaring many temporary variables for substitutions
is usually unnecessary and does not add to the readability
of your code.
On the same token, trying to accomplish too much in one line
can be confusing to others that read your code.
Use your best judgment.
-
Grouping similar constructs in a class will greatly aid the readability
and maintainability of one's code.
It is recommended that class/instance variable declarations, constructors,
public methods, protected methods and private methods be grouped in
sections.
It is also a good idea to place a visual separator of some sort between
these blocks of similar methods.
As an example of this practice, please have a look at
this sample class file.
-
Inserting white space between distinct sections of one's code
is a good idea.
The whitespace helps to provide a physical separation between
logical entities and improves the overall readability of the code.
For example, a few blank lines between methods helps a reader
to quickly determine where one method ends and another one
begins.
However, do not go overboard with this!! Too much white space
can be distracting as well. Placing 15 blank lines between
methods is unnecessary; one or two blank lines would suffice.
-
It is a good practice to comment the end of blocks of code.
It is very easy to misplace a brace or to place code within
the wrong enclosing block. Commenting the end of a block
helps greatly to improve the readability of the code.
Consider the following example:
if ( foo ) {
while ( this.myList.hasMoreThings() ) {
...
if ( somethingElseHappened ) {
...
} //end if ( somethingElseHappened )
...
} //end while ( this.myList.hasMoreThings() )
...
} //end if ( foo )
-
[Top]
Thou shalt use Javadoc comments - end of story.
Sun's reference for Javadoc comments may be found here.
Learn it - live it - love it.
-
Comments ( in-line documentation )
|
[Top]
There is always a good chance that another developer
will have to read your code in either the distant or not so
distant future.
In-line documentation should be included as much as possible to
explain in plain English what the code is doing.
As maintenance duties are most often relegated to junior
programmers (who have little experience) anything that can
make the code easier to understand will be a net benefit.
The level of in-line documentation included is up to a developer's
personal discretion. If the variable and class names are
very descriptive, sometimes additional comments are superfluous.
At a minimum, one should include Javadoc style comments at the
top of each method and class.
-
[Top]
Every bug fix should be documented either at the head of the main
body or in-line.
For example:
// 04-Apr-2002 SR 43820383 darrenh
// Fix bug where X happened instead of Y
// This was caused by the following input: ...
No coder in the world has enough time to read all the ClearCase
history and try to reverse engineer why that line is there from
the 400 merges it's gone through. The consequences of corrective
actions should be stated right in the code.
-
A method should perform one and only one concrete function
|
[Top]
A method should perform one and only one concrete task.
This heuristic is a best practice not only for Java developers
but is a good rule of thumb for all programming languages.
Methods that perform more than one concrete task almost
always increase the difficulty in debugging or modifying code.
Methods that perform more than one task always raise the complexity
and hence decrease maintainability of source code.
Some may argue that observing this best practice results in a
larger than necessary code base. This is true.
However as most of the cost of any software is incurred in the
maintenance/modification phase of its life cycle it would make
sense to adopt coding practices that lessen this cost.
Single purpose methods make for easier debugging and easier
modification by junior programmers (who are most often saddled
with maintaining and/or modifying legacy code).
-
[Top]
Predicate methods (those that return a boolean) should be named
in the form of a question; words such as is or has
should be used as the first word in the method name.
Predicate method names should have the general form
isSomethingTrue() or
hasSomethingHappened().
Adoption of this practice makes code much easier to read.
Consider the following example:
if ( myOrder.isOrderComplete() ) {
...
} else {
...
}
It is quite clear that the predicate method
isOrderComplete() will return
true when the order is in fact complete and false otherwise.
Conversely, consider the following code snippet:
if ( myOrder.completeOrder() ) {
...
} else {
...
}
Here it is not clear what the method is doing. Is it completing
the order and returning true if all is well? Is it merely
determining if the order has been completed?
The method name doesn't really describe it's intended function.
-
Always initialize variables
|
[Top]
When declaring a variable, it is a good idea to always provide
an initial value for that variable. Different JVM's treat
uninitialized variables in different ways.
As it is a good practice to check the value of a variable
(particularly with user supplied data) it is very helpful
to have a known default value for that variable.
A few examples of variable declarations with initial values would
be as follows:
private boolean orderIsFinished = false;
private int quantitySelected = -1;
private Vector purchasedProducts = null;
private Vector backorderedProducts = new Vector();
-
Accessor and mutator methods
|
[Top]
Accessor and mutator methods should be provided
for all publicly scoped values instead of explicitly
declaring them as public.
In general, class and instance variables should never be
declared public.
An accessor method is one that returns a value while a mutator
method is one that sets a value.
These methods should be named
getVariableName()
and
setVariableName().
An example of accessor and mutator methods would be as follows:
public class foo {
private int numberItemsSold = 0;
...
/**
* Return the number of items sold.
*/
public int getNumberItemsSold () {
return ( this.numberItemsSold );
} //end getNumberItemsSold
/**
* Set the number of items currently sold.
*/
public void setNumberItemsSold ( int theValue ) {
if ( theValue > 0 ) {
this.numberItemsSold = theValue;
} //end if
} //end setNumberItemsSold
...
} //end class foo
-
Referencing instance variables using the this keyword
|
[Top]
The convention of using
this.myVar
to refer to an instance variable is strongly encouraged.
I have found this practice greatly increases the readability of
the code and makes further modifications or debugging a lot less
painful.
The this
keyword may only be used with instance variables; it won't
work with class variables because it is a non-static reference.
Some developers however do not agree with the use of the
this keyword
(it's almost a religious war on par with sh versus csh).
However, the appearance of the keyword easily allows one to
note instance variables versus local method variables - thus
making the code much easier to read, maintain and debug.
public class foo {
private int myCounter = 0;
...
/**
*
*/
public void doSomething () {
...
//these two statements do the same thing
this.myCounter++;
myCounter++;
...
} //end doSomething
/**
*
*/
public void doSomethingElse () {
...
int myCounter=42;
...
//these two statements do NOT do the same thing
this.myCounter++;
myCounter++;
...
} //end doSomething
...
} //end class foo
-
[Top]
The use of inner classes should be avoided unless absolutely
necessary.
The use of inner classes often makes the task of the junior
maintenance programmer much more arduous.
The one exception where inner classes make sense is in
the implementation of action handler classes (in GUI code).
-
Place variables on the right side of relational operators
|
[Top]
One should place variables on the right
side of relational operators.
The use of this style guideline will not only help to make the code
easier to read (because in North America we tend to scan text
left to right) but it also serves to aid one in detecting
when = and == have been confused.
If the wrong operator is used, the compiler will flag the
error if the variable is on the right as the expression
0 = myVar
represents a semantic error.
However, if the variable is placed on the left side of the expression,
the expression myVar = 0 will compile
and execute successfully. This assignment operation will return
true if successful thus trapping one in the = versus == death spiral.
Confusion of the = and == operator is an all too common error
of which both junior and senior developers are potential victims.
if ( 0 == myVar ) //good
if ( myVar == 0 ) //bad
-
[Top]
Under certain circumstances, you may wish to define a method
that does something, but does not really perform a function
upon any specific object.
For example, you wish to write a method that trims
leading and trailing whitespace from a string.
In such a situation, you should define the method as static.
Do not write a constructor for a class which will contain a group
of methods that should be static as there is no need.
-
Primitive types vs. objects
|
[Top]
It is strongly recommended that one use primitive types
(eg. int, float or boolean) instead of object types
(eg. BigDecimal or Integer).
One should only use object types when absolutely necessary.
For example, Map
or Hashtable
keys require an object type.
When returning more than one thing from a method, they should
be returned using a Java collection class(Vector for example).
If no items are to be returned, one should return an empty
collection object (an empty Vector for example).
In general, one should not ever return a null value from a method
that is expected to return a collection.
-
Alternatives to Hard-Coding Values
|
[Top]
One should not ever even consider hard coding configuration values.
Hard coding is a practice that is frowned upon in all disciplines
of computing.
Hard coded values can spawn very difficult debugging if one's code
is run in an different environment or on another host.
Hard coding is just plain bad so don't do it!!
As an alternative to hard coding, one is encouraged to retrieve
configuration values from a data file. Access to these
configuration values may be facilitated by a class using the
GoF singleton pattern.