Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

Introduction

Development guidelines are written here to help CAS developers maintain consistency and quality in the source that we write. The product is Java source code or artifact resources. Stiff process is not required, however guidelines are helpful in the act of quality compliance. Software among team members should reflect no individual authorship. These guidelines will help with this goal.

Analysis and Requirements

Requirements for this release will generally be very dynamic due to multiple customer (university) needs. The requirements should be clearly documented, however readers should accept that they may change throughout the life of the release cycle. Analysis may not be so public but actionable requirements will be drafted and maintained in this Confluence space.

Development

CAS development has been managed using the Apache Maven product. Maven can be used to create Eclipse project files to complement the SVN checkout. We recommend that the Eclipse IDE is used during this development cycle. If Eclipse can be approved by the CAS Steering Committee, it would provide a common IDE and allow the use of new file templates. This would do an excellent job of maintaining a quality source format and consistency.

Coding Standards

Java coding standards should follow the guidelines set forth by Sun Microsystems. These guidelines are titled Code Conventions for the Java Programming Language and found here. Other clarifications should be noted in addition to those found above.

Naming Conventions

packages
lowercase

Consider using the recommended domain-based conventions described in the Java Language Specification, page 107 as prefixes. (For example, edu.oswego.cs.dl.)

files
The java compiler enforces the convention that file names have the same base name as the public class they define.

classes
CapitalizedWithInternalWordsAlsoCapitalized
Exception class
ClassNameEndsWithException
Interface
Name the entity as it would generally be named:
MyService
Class
When necessary to distinguish from similarly named interfaces:
MyServiceImpl
constants (finals):
UPPER_CASE_WITH_UNDERSCORES
*private or protected:_
firstWordLowerCaseButInternalWordsCapitalized
static private or protected:
firstWordLowerCaseButInternalWordsCapitalized
local variables:
firstWordLowerCaseButInternalWordsCapitalized
methods:
firstWordLowerCaseButInternalWordsCapitalized()
factory method for objects of type X:
newX
converter method that returns objects of type X:
toX
method that reports an attribute x of type X:
X x() or X getX().
method that changes an attribute x of type X:
void x(X value) or void setX(X value).

Recommendations
  • Minimize * forms of import. Be precise about what you are importing. Check that all declared imports are actually used. Do not leave imports that are not used. If we use an IDE such as Eclipse it is easy to manage imports.
  • When it makes sense, consider writing a main for any complex classes that would benefit from an example use case. This should not be the norm. Unit tests should be written for all classes. This would be for the casual source code browser's understanding.
  • We do not recommend the use of multiple classes in a single Java file. The only exception to this would be something very natural such as a Comparator.
  • Declare a class as final only if it is a subclass or implementation of a class or interface declaring all of its non-implementation-specific methods. (And similarly for final methods). Making a class final means that no one ever has a chance to reimplement functionality. Defining it instead to be a subclass of a base that is not final means that someone at least gets a chance to subclass the base with an alternate implementation. Which will essentially always happen in the long run.
  • Never declare instance variables as public.
  • Minimize statics (except for static final constants). Static variables act like globals in non-OO languages. They make methods more context-dependent, hide possible side-effects, sometimes present synchronized access problems. and are the source of fragile, non-extensible constructions. Also, neither static variables nor methods can be overridden in any useful sense in subclasses.
  • We generally prefer Long over long, long over int, and double over floats. But use int for compatibility with standard Java constructs and classes (for the major example, array indexing, and all of the things this implies, for example about maximum sizes of arrays, etc). Arithmetic overflow and underflow can be 4 billion times less likely with longs than ints; similarly, fewer precision problems occur with doubles than floats. On the other hand, because of limitations in Java atomicity guarantees, use of longs and doubles must be synchronized in cases where use of ints and floats sometimes would not be.
  • Use final and/or comment conventions to indicate whether instance variables that never have their values changed after construction are intended to be constant (immutable) for the lifetime of the object (versus those that just so happen not to get assigned in a class, but could in a subclass). Access to immutable instance variables generally does not require any synchronization control, but others generally do.
  • We generally prefer protected over private. Unless you have good reason for fixing a particular strategy to use a variable or method, you might as well plan for change via subclassing. On the other hand, this almost always entails more work. Basing other code in a base class around protected variables and methods is harder, since you you have to either loosen or check assumptions about their properties. (Note that in Java, protected methods are also accessible from unrelated classes in the same package. There is hardly ever any reason to exploit this though.)
  • We always believe in getter/setter methods. While we've borrowed much of Doug Lea's guidelines, all instance variables should have a get and set method. It is not important to document these methods. We know what they represent.
  • Avoid giving a variable the same name as one in a superclass. This is usually an error. If not, explain the intent.
  • Use Java 1.5 features and type-safety
  • Name methods with logical action verbs
  • Always set returns to false if that what's expected. Return the local variable and not the result.
  • Do not return "this".
  • Declare all public methods as synchronized; or if not, describe the assumed invocation context and/or rationale for lack of synchronization. In the absence of planning out a set of concurrency control policies, declaring methods as synchronized at least guarantees safety (although not necessarily liveness) in concurrent contexts (every Java program is concurrent to at least some minimal extent). With full synchronization of all methods, the methods may lock up, but the object can never enter in randomly inconsistent states (and thus engage in stupidly or even dangerously wrong behaviors) due to concurrency conflicts. If you are worried about efficiency problems due to synchronization, learn enough about concurrent OO programming to plan out more efficient and/or less deadlock-prone policies.

These recommendations are rules of thumb and may not be followed in all cases. They are here for guidance only.

Code Reviews

After source files are checked in, periodic code reviews should be done as a group or peer-to-peer as development begins. Depending on the skill level of the team members, group or peer-to-peer should be chosen. Code reviews are necessary and should not be avoided.

Testing

All classes and methods should have corresponding JUnit tests. JavaBeans are exempt. If team members were to pick and choose what is tested, quality will suffer.

Delivery

  • No labels