When developing FeatJAR code, we recommend to respect the following coding conventions to ensure consistency and high-quality code.
-
Rule of thumb: Prefer good naming (without documentation) over bad naming (with documentation).
-
Most classes are
- things, which actors operate on (e.g.,
Tree
), - actors, which operate on things (e.g.,
TreeVisitor
), or - buckets, which loosely collect related methods (e.g.,
Trees
).
This should be reflected in their naming.
- things, which actors operate on (e.g.,
-
Prepend names of abstract classes with
A
and interfaces withI
, so there is room for a canonical implementation (e.g.,ITree
and its primary implementationTree
). Avoid using inner classes and interfaces - if using them, do not prepend their names. -
Abbreviations should be capitalized (e.g., prefer
ComputeCNFFormula
overComputeCnfFormula
). Only use well-known abbreviations. -
We recommend to move complex algorithms for manipulating a data structure
<Struct>
into a class with static methods<Struct>s
(e.g.,Trees
manipulatesITree
instances). For common algorithms, consider adding a convenience method to<Struct>
to ensure obvious visibility for API consumers (e.g.,ITree#traverse(TreeVisitor)
as a shorthand forTrees#traverse(ITree, TreeVisitor)
). The rationale is to keep the data structure class free from algorithm details (e.g., traversal iterators) and make better use of generic types. -
The same naming convention is also applied for extensions (e.g.,
Thing
) and their extension points (e.g.,Things
).
-
All Java classes in FeatJAR should be documented with a JavaDoc comment above the class, including the purpose of the class and its author(s).
-
Depending on the subjective importance of the class, either
- all attributes and methods should be documented, or
- all public and protected attributes and methods should be documented (recommended), or
- no attributes and methods should be documented.
That is, avoid documenting an arbitrary selection of methods. The rationale is to keep the documentation clear, concise, and correct.
-
Use the JavaDoc tags
@author
(for classes),@param
,@return
,@throws
, and@inheritDoc
(when extending documentation). For further guidelines, see here. -
When documenting a method, consider its most important usage example and typical failure modes.
-
As an example for appropriate documentation, refer to the
base
module. -
Tests need not be documented using JavaDoc. Instead, write small tests with telling names.
TODO
- Avoid global mutable state (i.e., non-final
static
fields). When it cannot be avoided, implement anIExtension
and register it (e.g., inInitializers
). This way, global mutable state is at least encapsulated in a singleton and its lifetime is limited by the (un-)installer inExtensions
. - Avoid
private
fields and methods. Useprotected
instead to allow API extensions. - How To Design A Good API and Why it Matters
- Do not implement
Object.clone
, which cannot be used reliably for all classes. Instead, write copy constructors. - Implement
Object.equals
andObject.hashCode
where necessary (e.g., for objects cached in computations), but always in pairs. serialVersionUID
,toString
format:TODO
- Avoid returning
null
and throwing exceptions. Instead, return aResult
for planned or erroneous absence of values. Exceptions to this rule:- You can return
null
when implementing an optional feature in an extension (i.e., a default method in an interface that inheritsExtension
). If you do so, still document it ({@return ..., if any}
). - You can throw (preferably checked) exceptions in
void
methods to avoid introducing a necessarily empty return value. If you do so, document it, especially for unchecked exceptions (@throws ... when ...
).
- You can return
- Concrete implementations of
IComputation
,IAnalysis
, andITransformation
should be namedCompute*
,Analyze*
, andTransform*
, respectively. - Variables of type
IComputation
should be named withoutcomputation
suffix. Use the helpers inComputations
to convert between (a)synchronous computation modes. - Use
LinkedHashMap
andLinkedHashSet
instead ofHashMap
andHashSet
to preserve order and guarantee determinism.