The Nuxeo Platform exposes a huge and diversified API which must be kept stable, properly maintained and bug-free, including documentation. The following are some required coding style rules about code and Javadoc.
Formatting
No Tabs, No Trailing Spaces
This avoids changes in diffs when invisible characters change. In Eclipse, you can install the Marketplace package AnyEdit Tools which has tab-related options.
Indent and Format According to Our Formal Rules
The format rules are the Eclipse formatting configuration. See Code Templates and Formatter configurations for more.
This also applies to organizing imports.
It allows the same automatic formatting for everyone, to avoid gratuitous reformattings every time someone commits.
No Automatic Formatting on Save
This avoids mixing cleanups with other code changes.
The only allowed exception is for trailing whitespaces, which may be automatically removed at save time. In Eclipse, go to Preferences > Java > Editor > Save Actions. Check Perform the selected actions on save, and only check Additional actions, that should only list Remove trailing white spaces on all lines (configure it in Configure > Code Organizing).
Readability
The Code Must Be Clear, and Commented to Explain why It Does Things
What the code does should be self-explanatory through proper code organization, method/field/variable naming, etc. A comment with a summary of what some code does can still be useful before a code block.
No Wildcard Imports
They make searches more difficult, make actual packages difficult to discover for readers outside an IDE, and can cause a problem when imported packages have new classes added that are also in another wildcard import.
Use Static Imports for Common, Well-Known Things
Some common constants or static methods have names that are unique enough so that it's worth having a shorter code when they're used:
Boolean.TRUE
,Boolean.FALSE
StandardCharsets.UTF_8
Collections
static methods (emptyList
,singletonList
, etc.)Collectors
static methods (toList
,toMap
,groupingBy
, etc.)
No final
Method Parameters or Local Variables
They are eyesores for readers, don't bring much safety if the code is already clear enough, and IDEs often provide enough warnings.
You Can Reassign Method Parameters
It's ok to reassign a method parameter (to "normalize" it on method entry for instance) if it makes the code more readable. Some style guides disallow updating parameters, but that's overly strict.
Use i++
Our standard is i++
(not ++i
) for simple increments. This does not apply when the increment is inside another expression, because the semantics are then different.
Use All-Caps for static final
Fields
These fields are constants, and their use should be immediately identifiable as such.
Maintainability
Always Use Braces
Always use {
}
and a separate line for if
/else
blocks. This avoids hard-to-find bugs and is our formatting style.
Use Objects.requireNonNull
For null
Checks
It's better to use this standard method than having custom code. Use a message specific to the checked code.
No Final Methods or Classes
This hinders reusability. Nuxeo is a platform and we never know when it'll be useful to subclass something.
This rule, and the one below about private
, does not apply to private projects that are not part of the Nuxeo Platform (like Nuxeo Studio and Nuxeo Connect) where private
helps with cleanups and there is no third-party compatibility or subclassing issue.
No private
or Package-Private Methods or Fields.
This hinders reusability, for the same reason as above.
Two exceptions are log
and serialVersionUID
which must be private
because we want subclasses to redefine them.
Testability
Always Write Unit Tests
Tests help for development (TDD), and for non-regression.
Structure Code for Testing
Don't hesitate to layer your code between different levels of complexity and have internal SPIs to ease testing and mocking.
Your code may have internal hooks to facilitate testing on mock objects if needed and if this doesn't have a significant impact on efficiency. However callings things like Framework.isTestModeSet()
and having different code paths in test mode is not acceptable.
Debuggability
Logging
Use logging at critical points in your code.
ERROR
logs for incorrect configuration stuff, or unexpected exceptions.INFO
logs for rare diagnostics, like startup and initial configuration information.DEBUG
logs for additional light diagnostics during execution.TRACE
logs for heavy diagnostics when the expected output is more than a few lines per request.
In particular, DEBUG
logs are essential when interacting with external systems.
Use if (log.isDebugEnabled())
except if the logged value is a constant string
(we hope to improve this in the future by switching to slf4j
for the logging facade).
Monitoring
Maintain counters about important allocated resources and expose them through the standard monitoring facilities.
Javadoc
Follow the Oracle Javadoc best practices: http://www.oracle.com/technetwork/articles/java/index-137868.html#styleguide
In particular the first sentence of the Javadoc should be a short verb phrase, using 3rd person (Gets the foobar) and not 2nd person (Get the foobar), and end with a period.
Also the @param
and @return
tags are followed by a sentence fragment which is not capitalized and not ending with a period.
Add @since
annotations on new public classes, methods or constants.
Do not use the @author
tag. It is not included when generating the API specification. There's very rarely a single author for a file and the version history (git blame
) can be used to determine the contributors.
Additionally, the copyright header (not Javadoc but a simple comment) includes a dedicated zone that you can use to highlight your contribution and knowledge on a class.
You should configure your IDE to raise warnings on malformed Javadoc comments and to validate tag arguments but to ignore missing Javadoc tags and comments.
FAQ About @since
in Javadoc
Q: I'm backporting a new API from 10.2 to the 9.10 maintenance branch, should I put @since 10.2
or @since 9.10-HF08
?
A: Use @since 10.2
, otherwise backports are a pain when cherry-picking. JIRA fix version is the reference to understand why a @since 10.2
is visible on a 9.10 maintenance branch.
Q: When should I add @since
in other places besides new classes and methods?
A: Wherever it helps. Marking fields or static constants is sometimes useful, especially XMap descriptor fields, event names, or other well-known public values (configuration parameters, options, etc.). And please think of your fellow Studio developers who will need to easily know what is acceptable for a given target platform version.
General Java Best Practices
No finalize()
Method
They have a huge impact on GC times.
Avoid Using an Array []
If a List
Can Be Used
Lists have many more methods, and the JIT will optimize things anyway.
Use Streams If It Makes the Code More Readable or Less Error-Prone
Intermediate loop variables or tests add complexity.
Always Use Explicit Charsets
Always use an explicit Charset
in byte[]
to String
and String
to byte[]
conversions. This applies to code like new String(byte[], Charset)
, String.getBytes(Charset)
, IOUtils.toString(InputStream, Charset)
, etc.
The default charset depends on the platform, so code that uses it is not predictable.
Deprecation
When changing an API, forward and backward compatibility must be maintained over multiple versions. Javadoc @deprecated
and Java @Deprecated
annotations must both be used.
/**
* ...
* @since 8.1
* @deprecated since 9.10. Use {@link #newMethod()} instead.
*/
@Deprecated
public void oldMethod() { }
Always indicate the version since when deprecation happens. This will be used for later removal and help deprecated API users to guess the refactoring priorities. Point to the new API and usage.