Java Software Coding Standards Guide
NETSCAPE'S SOFTWARE CODING STANDARDS GUIDE FOR JAVA Christie Badeaux, Technology Evangelist
INTRODUCTION
In August 1997, Marc Andreesen announced that Netscape would be releasing a
100% Pure Java Navigator in 1998. At that time the client product
engineers were already well into coding applications with Java. Along the
way, the engineers had created a set of Java coding guidelines to be used in
creating this next generation Communicator product. What follows is a
subset of those guidelines that I thought you might be interested in using for
your own Java development.
GOALS OF THESE STANDARDS
First of all there is the need to recognize the purpose of these guidelines
and set some goals. Following are three basic, but very important goals:
- The use of these guidelines should result in readable code and should
encourage adherence.
- The resulting documentation should be easy to maintain.
- This document should be a living document in that as we discover better
ways to do things, it gets reflected here.
In order to write great
software, you have to write software greatly. Vague? Well, the point is that
before you can produce great code, you have to have developed a process for
writing great code. And that is what these standards are intended to help with.
Some amount of standardization is especially important in a large development
organization writing component software. Everybody will be in everybody
else's code, and that code must be clear. It must be clear what the code
does, how it should be used, how it can be extended, etc. The standards
within this document have been written to balance the group need for
standardization with the individual's desires to code in the ways they feel most
efficient.
SCOPE AND APPLICATION OF THESE STANDARDS
It is very important to note that this document is divided into two distinct
areas -- Rules and Guidelines. It is very important
to recognize the following....
- Rules are those coding standards that are "necessary and
required" coding practices that have been agreed upon by members of the
Java Communicator team. Everyone is expected to follow these "rules".
- Guidelines are "suggested" coding practices that have
been written to recognize the need for individuality AND for common coding
practices. The purpose of the guidelines is to provide a framework upon which
we can all create better code. However, the guidelines are not meant to
impede engineering efforts when these guidelines are found to be in direct
conflict with an individual's preference, so long as that preference is
implemented consistently and is well documented. Finally, because we recognize
that this opens the code upon to individual stylist coding habits, it is
important that these habits are well documented and will then become the basis
for all other updates within the affected files, i.e. when in someone else's
code do as they do.
What is expected of everyone...
- Everyone should read these guidelines.
- Everyone should understand them.
- Everyone should use them.
- Then and only then should anyone begin to challenge them*.
*Ultimately, everyone is expected to help refine the
rules embodied in this document.
OVERVIEW OF THE DEVELOPMENT DOCUMENTATION
General
Coding Rules
Naming
Conventions
Commenting
Code
General
Coding Guidelines
Source
Code Style Guidelines
Naming
Guidelines
Layout
of Source (.java) Files
Documentation
for Methods and Functions
GENERAL CODING RULES
Rules are those coding standards that are "necessary and
required" coding practices that have been agreed upon by members of the Java
Communicator team. Everyone is expected to follow these "rules".
NAMING
CONVENTIONS
Package Names
- Package names should be single lowercase words.
Class Names
- Concrete classes should use natural descriptive names, begin with a
capital, and have mixed case: FooBarReader
Member Function Names
- Method ("member function") names should begin with a lowercase letter
with each subsequent new word in uppercase, and subsequent letters in each
word in lower case.
- Methods for debug-only implementation should begin with "mortMortMort".
(Alternatively they can begin with the word "debug").
- Static methods should begin with a capital letter with each subsequent
new word in uppercase, and subsequent letters in each word in lower case.
- example
public class MyClass
{
void doSomethingNeat(int aValue); void
debugDumpToScreen(); static void
SomeClassMethod(int aValue); };
COMPONENT FACTORY NAMES
A component factory is a public class that implements only static methods.
These static methods are "Factory functions" or "component constructors".
Factory class names should include the word "Factory". Factory method
names should start with the word "Make." For example,
- public class WidgetFactory
- {
- static Button MakeButton(int aButtonType);
- static ListBox MakeListBox();
- };
Function Naming Patterns
- Getters and setters should begin with "get" / "set" and return the
appropriate object type.
- Boolean getters should use "is" or "can" as a prefix, such as
"isUndoable()" rather than "getUndoable()"
COMMENTING CODE
All interfaces and public classes should have JavaDoc comments. See the JavaDoc
documentation available from JavaSoft.
GENERAL CODING GUIDELINES
Guidelines are "suggested" coding practices that have
been written to recognize the need for individuality AND for common coding
practices. The purpose of the guidelines is to provide a framework upon which we
can all create better code. However, the guidelines are not meant to
impede engineering efforts when these guidelines are found to be in direct
conflict with an individual's preference, so long as that preference is
implemented consistently and is well documented. Finally, because we recognize
that this opens the code upon to individual stylist coding habits, it is
important that these habits are well documented and will then become the basis
for all other updates within the affected files, i.e. when in someone else's
code do as they do.
JAVA GRAMMAR
Wherever appropriate, avoid code that embeds many operations in a single
line. For example, avoid: someObject.doThis(i++,
otherObject.someField.doThat(), x?y:z). This kind of code is
error prone, difficult to decipher, and hard to maintain. PARENTHESES
Parentheses are recommended for Boolean expressions to ensure proper
evaluation .
if (((someValue<foo(theParm)) &&
anotherValue) || todayIsMyBirthday) TIP: Place
constants on the left side of your expressions; assignment, boolean and
otherwise. This technique can catch assignment (versus equality) errors, as
well as promote constant factoring for poor quality compilers. CONSTANTS
Constants will use mixed case and begin with lowercase k. They offer
compile time type checking.
example
- static final float kPi = 3.14159;
- static final int kDaysInWeek = 7;
"MAGIC" NUMBERS
Literal ordinal constants embedded within source should almost
never be used. Whenever possible, use constants instead of literal ordinal
constants:
example
- int totalDays = 10 *
DAYSINWEEK; //boo, hiss!
- static final int kDaysInWeek =
7; //hooray! hooray!
DEBUGGING
- First and foremost, understand how to write solid code. Then go back and
reread the java programming language reference documentation from
JavaSoft to refresh you memory on the precedence order of operators.
- Now go read the internal document on abnormal condition handling.
- Make sure every path of execution through your code has been
thoroughly tested. You can never do enough coverage testing. Here's a neat
idea: try actually stepping through each line! While you're hard at work
testing your code, be sure to throw invalid inputs at every public interface
you provide. The last thing we want to do is crash because your routine
didn't handle invalid inputs from ours. Never ever break
the build.
- Want to know the secret to fast code? Calculate those comparison values
once: reuse them often. Avoid global variables too, since they can wreak havoc
with the pre-fetch instruction queue.
- Don't forget to adhere to our Orthodox Canonical Form. This is a template
that, when followed, guarantees that you have all the default methods your
class needs to be a good java citizen. It is our policy to produce code that
can test itself to the greatest extent possible. To that end, we encourage the
use of three debugging techniques: asserts, pre/post conditions and self
testing methods.
1. AssertsIt is highly recommended that
assert methods (warnings/errors) be used to aid in debugging, especially to
verify assumptions made in code. This will be the technique used for reporting
run-time errors and warnings.
2. Pre and Post ConditionsIn order to
bulletproof your code, you should use asserts to test all boundary conditions.
You're not doing any favors for anyone by "defensive" programming practices
that allow clients of your code to make improper calls. In other words,
it is better to blow up in debug builds if you are given bad data rather than
trying to "fix" the data and hide bugs.
example
- String copyString(String aOtherString)
- {
- Assert.PreCondition(NULL !=
aOtherStr, "Null string given");
- ...
-
Assert.PostCondition(fSelfString.length()
>=aOtherString.length(),
-
"lengths don't match after copy.");
- }
We do not want debug
code to be included into release builds. Therefore, all assertions are removed
by the compiler (the java equivalent of #defines) by flipping the debug flag
in the Assert class.
3. SelfTest MethodsEach package will
include a SelfTest class. This class should have routines to thoroughly
unit test every class in the package. If appropriate, the SelfTest class
may also contain methods for test integration between the classes in this
package, and between the classes in this package and their dependencies in
other packages.
Here is the rule for using SelfTest Methods: When you design your
class, you should design its unit test. When you design your package,
you should design your integration test. You are NOT done with the
implementation of a class until its unit test is implemented and can be run
successfully. You are NOT done with your package implementation until
all unit tests are coded and run successfully, and the integration tests (if
appropriate) are coded and run successfully.
SOURCE CODE STYLE GUIDELINES
LINE SPACING
- Line width should not ordinarily exceed 80 characters. Use your best
judgment.
- Tab sizes should be set equal to 2 spaces and set to be expanded to
spaces.
BRACES
- The starting brace can be optionally at the end of the conditional or on
the next line aligned with the conditional. The ending brace must be on a
separate line and aligned with the conditional. It is strongly recommended
that all conditional constructs define a block of code for single lines of
code.
- We give some options below to accommodate the vast majority of
programmer's styles. HOWEVER, be consistent! When
you pick a style, stick to it. When editing another person's code,
respect the code, copy the style. (When in Rome, do as the Romans do).
IF / ELSE
Place the IF keyword and conditional expression on the same line.
examples:
if (expression)
{
statement;
}
else
{
statement;
}
or
if (expression) {
statement;
} else {
statement;
}
WHILE
The WHILE construct uses the same layout format as the IF construct. The
WHILE keyword should appear on its own line, immediately followed by the
conditional expression. The statement block is placed on the next line. The
curly braces may optionally be indented by up to 1 tab character. (1 TAB=2
spaces).
examples:
while (expression)
{
statement;
}
or
while (expression) {
statement;
} DO..WHILE
The DO..WHILE form of the while construct should appear as shown below:
do {
statement;
} while (expression);
or
do {
statement;
} while (expression);
SWITCH
The SWITCH construct uses the same layout format as the if construct. The
SWITCH keyword should appear on its own line, immediately followed by its test
expression. The statement block is placed on the next line. The curly braces
may optionally be indented by up to 1 tab character.
examples:
- switch (expression)
- {
- case n:
- statement;
- break;
- case x:
- statement;
- // Continue to default case
-
default:
//always add the default case
- statement;
- break;
- }
- or
- switch (expression) {
- case n:
- statement;
- break;
- case x:
- statement;
- // Continue to default case
-
default:
//always add the default case
- statement;
- break;
- }
TRY/CATCH/FINALLY
The try/catch construct is similar to the others. TRY keyword should
appear on its own line; followed by the open brace (optionally on the same
line); followed by the statement body; followed by the close brace on its own
line. Any number of CATCH phrases are next consisting of the CATCH
keyword and the exception expression on its own line; followed by the CATCH
body; followed by the close brace on its own line. The FINALLY clause is
the same as a CATCH.
examples:
- try
- {
- statement;
- }
- catch (ExceptionClass e)
- {
- statement;
- }
- finally
- {
- statement;
- }
- or
- try {
- statement;
- }
- catch (ExceptionClass e) {
- statement;
- }
- finally {
- statement;
- }
NAMING GUIDELINES
GENERAL All type declarations should follow
standard java package naming.
- Package : All projects need to pick a prefix (we usually choose 2
letters). The project may split itself into any number of packages below
this prefix. All package names are entirely lower case. Remember, java
tools are case sensitive, and as of this writing somewhat inconsistent across
platforms concerning package names.
- Interface : Everyone is encouraged to use the prefix "I" in
your interface classes, such as IPart. This is optional, but strongly
encouraged.
- Constants : begin with k: kMyConstant
- Global Types : begin with g: gDays (or
"globalDays" is ok.)
MEMBER DATA NAMES
All member data will begin with a lowercase f, and then follow the
normal naming convention for other identifiers (mixed case, each word
beginning with uppercase). Keep in mind that providing publicly visible member
data reflects negatively on your family. Use access functions instead.
Respect the Java Beans coding patterns for member access unless you have a
good reason not to.
example
public class CxMyClass {
public void setMyOrdinalValue(int
aValue);
public int
getMyOrdinalValue();
private int
fMyOrdinalValue;
}; PARAMETER NAMES
Parameter names should be constructed like identifiers, and include the
type in the name if the type is not explicit. They begin with lowercase
letters, and they typically start with the letter "a". Some may
feel "an" is more readable for parameters that start with a vowel, such
as "anObject."
example
public boolean numberIsEven(int aValue, Object
anObject) {
...
}
LAYOUT OF SOURCE FILES (*.java)
The layout for a class will be broken up into the following main sections:
Copyright Notice, File Description; Package Name,
Imports, Constants, Methods, protected and private members. Each section
will be prefaced by an appropriate header block defining the section.
-
COPYRIGHT NOTICE
- This will be the standard "legalese" copyright notice.
- /* Copyright Notice
=====================================*
- * This file contains proprietary information of
Netscape Communications.
- * Copying or reproduction without prior written
approval is prohibited.
- * Copyright (c) 1997
=====================================* /
- FILE DESCRIPTION
- This is a brief description of what the file is, does and represents. It
should describe the overview of how to use the file (or classes therein).
JavaDoc compatible commenting style is required. See the JavaDoc
documentation available from JavaSoft.
/* Description * Appropriate Description. * Description */
-
PACKAGE NAME
- Package names should occur on the first non-commented line of the source
file and should following the naming
conventions defined in this document.
-
IMPORTS
- Immediately following the package name should be the imported class names.
-
CONSTANTS
- See the naming
conventions defined in this document.
-
METHOD DECLARATIONS
- Each method is preceded by a description in JavaDoc format. Public methods
MUST have a standard javadoc comment header. These must be
professionally commented. Remember, you never know what code will
eventually be made public outside of Netscape.
Standard access methods may be grouped without a description (access
methods assign or return an object attribute). Optionally, methods may be
grouped within logical groupings. Here are some suggestions...
- Factory
- Private
- Protected
- Interfaces
- Accessor
- Temporal (fickle)
- I/O
- Debugging
example
/* ======================================================= *
CONSTRUCTOR/DESTRUCTOR METHODS *
======================================================= */
public CkSomeClass();
public CkSomeClass(CkSomeClass
aSourceToCopy);
/* ======================================================= *
FACTORY METHODS (usually static) *
======================================================= */
/** brief description */
public CkSomeClass createSomeClass(void){ }
/*
======================================================= *
ACCESSOR METHODS *
======================================================= */
public int getState(void);
public void setState(int aNewValue);
/* ======================================================= *
STANDARD METHODS *
======================================================= */
//...whatever these might be...
/* ======================================================= *
DEBUGGING METHODS *
======================================================= */
void DoUnitTest(void);
- CLASS DEFINITIONS
- This section is the actual implementation of the class. Each method (and
private function) will be prefaced by the standard documentation header. Read
the Documentation
for Methods and Functions defined in this document.
DOCUMENTATION FOR METHODS AND
FUNCTIONS
The following standard has been established for the documentation of methods
and functions. Optional items are to be included only where applicable. A
complete description of each section in the routine documentation follows.
The header is designed to be easy to use. Many items are optional, and may be
omitted where they are not applicable. Each line item begins with an asterisk,
and ends with blank space. You do not place an asterisk next to each line in a
multiline component, only the topmost, next to the title. All subsequent lines
in multiline component are to be indented so that they line up vertically with
the previous line.
example
/** * <Detailed
description of method.> *
* @param
<Description of each parameter> *
@return <explain each return
type> * @exception
<explain each exception> *
@author <your name>
<04-22-97 3:57pm> **/ DESCRIPTION
Provide a detailed description. This may include:
- intent of method
- pre and post conditions
- side effects
- dependencies
- implementation notes
- who should be calling this method
- whether the method should or should not be overridden
- where to invoke super when overriding
- control flow or state dependencies that need to exist before calling
this method.
PARMS SECTION
Describes the type, class, or protocol of all the method or routine
arguments. Should describe the parameters intended use (in, out, in/out)
and constraints.
example
- * @param aSource - the input source string.
Cannot be 0-length.
RETURNS SECTION
This section is used to describe the method/routine return type.
Specifically, it needs to detail the actual data type returned, the range of
possible return values, and where applicable, error information returned by
the method. Also note that if the return value is self, you do not have to
specify a type (defaults to ID). All other cases require an explicit return
type specification.
example
- * @return Possible values are 1..n.
EXCEPTION SECTION
The purpose section is a complete description of all the non-system
exceptions that this method throws. A description about whether the
exception is recoverable or not should be included. If applicable, a
recovery strategy for the exception can be described here. Remember,
when you throw a recoverable exception, you MUST reset the class state for
re-entrancy!
*
@exception ResourceNotFoundException. recoverable, try another resource
|