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. Asserts
It 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 Conditions
In 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 Methods
Each 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
For more Internet development resources, try Netscape TechSearch