Skip to content

Latest commit

 

History

History
179 lines (110 loc) · 12.5 KB

java-style.md

File metadata and controls

179 lines (110 loc) · 12.5 KB

Java Style Guide

http://broad.io/java-style

tl;dr

  • All Terra Java code should adhere to the Google Java Style Guide where possible.
  • All repositories should be set up with auto-formatting and static analysis.
  • For stylistic concerns that cannot be automatically enforced, see the guidelines below.

Java style addendums

None yet.

Static analysis and code formatting

We believe developers should strive to spend as little time as possible worrying about and discussing code style. Code formatting and static analysis programs can be helpful tools in pursuit of that goal, since automatic enforcement at compile-time relieves the team from discussing such issues in PR reviews.

All Terra repos should use the following tools:

We will continually evaluate additional static analysis tools (Error Prone and Codacy) for inclusion in the above list. We should err towards adopting any tool that can provide low-friction enforcement of the key conventions or best practices below.

Guidelines & best practices

The sections below summarize our teams’ collective wisdom regarding various Java coding topics. Some advice is meant to be stronger than others — look out for the following keywords:

  • always – always follow this practice.
  • should – strong guidance; should be followed with few exceptions.
  • prefer – softer guidance, with numerous exceptions.
  • may / optional / at your discretion – indicates a matter of taste or personal style.

To learn more about Java best practices, see Effective Java, 3rd edition. Many of the guidelines below are paraphrasing Effective Java chapters; look for explicit references to chapters from the book, with links to the https://github.com/david-sauvage/effective-java-summary notes repo.

Alphabetization

Unless there is a meaningful non-alphabetical order, prefer alphabetized variable lists, enum entries, etc. in order to make lists easier to visually scan. (And in cases where there is some meaningful alternate ordering, add an explicit comment so future editors can maintain that order.)

For example, these subheadings are alphabetized for lack of a meaningful non-alphabetic order.

Classes

We adopt a few general guidelines:

  1. Minimize accessibility of classes and members.
  2. Favor composition over inheritance.
  3. Design and document for inheritance or else prohibit it.
  4. Prefer interfaces over abstract classes.

See EJ3 #15-25 for more tips.

Closing resources

Code that uses Closeable resources (such as input streams or sockets) should use the try-with-resources pattern:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

Note that some Streams, such as those returned from the java.nio.file.Files API, may be bound to system resources and must be explicitly closed (docs). Take care to use the try-with-resources pattern in those cases.

Comments

Comments, as distinguished from Javadoc (see Javadoc section below), should be used to inform the reader when code cannot be self-explanatory.

A few scenarios deserving of a code comment:

  • When it's not obvious why a given line of code exists.
  • If a question or request for clarification might come up in code review (or if such a question did come up in code review).
  • If a future maintainer might reasonably undo this change or inadvertently break something non-obvious.
  • Where the structure or reasoning behind the code is well-explained by an external resource (e.g. StackOverflow link, Jira ticket, or design doc).

Dependency injection

For Spring-aware code (e.g. most service and terra-common-lib code), dependencies should be @Autowired via the class constructor. Manual instantiation of @Component classes should be rare.

Exception: Stairway is not Spring-aware, so it is a common pattern to create a dependency-injected class that wraps Stairway functionality.

Exceptions

Checked exceptions place a burden on the users of an API. They are a tool best used when both of the following are true: (1) the exception cannot be prevented by proper use of the API, and (2) the user can take some meaningful action when encountering the exception. Unless both conditions are met, checked exceptions should be avoided. (See EJ3 #71 for more discussion.)

Guidance for unchecked exceptions:

  • More specific exceptions should be thrown instead of generic RuntimeExceptions.
    • For example: IllegalArgumentException, ConcurrentModificationException, UnsupportedOperationException are commonly reused exceptions from the Java library.
    • Other Terra-specific runtime exceptions should be centralized in terra-common-lib.
  • Service repos may also house application-specific exceptions (WSM example).
  • In many cases, exceptions are explicitly associated with an HTTP status code (example) and used to auto-generate an appropriate response (example).

Final

  • Classes – unless a class has been designed and documented for inheritance, it should be marked as final.
  • Function parametersprefer not marking as final, due to the noisiness of the “final” keyword. Use where necessary for occasional semantic emphasis.
  • Instance variablesalways mark as final if it is never reassigned.
  • Local variables – use of final is optional. Short and simple methods can help avoid inappropriate variable reassignment.
  • Static variables – almost always mark as final.

Immutability

Quoting from Effective Java: "immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure." See recommendations from Effective Java on how to minimize mutability.

Developers may consider using a library for auto-generating immutable data transfer objects (DTOs). Autovalue is actively used within Workspace Manager and Resource Buffer. Immutables is another popular option.

For constructing immutable collections, prefer Guava immutable collections.

Java 8 features

Use Java 8 features where helpful. See https://leanpub.com/whatsnewinjava8/read and https://www.oracle.com/java/technologies/javase/8-whats-new.html for more details.

Here is a quick run-down of Java 8 topics:

  • *java.time. – **the JavaTime library should be used for date-time manipulation. Duration is especially common. For non-core extensions, consider the https://www.threeten.org/threeten-extra/ library.
  • Lambda expressionsprefer lambda expressions for short and simple bits of code. If a lambda gets too complex, extract it into a named method.
  • Method referencesprefer method references where possible (e.g. someStream().map(MyClass::getBar)).
  • Streamsprefer using Streams for operations that can be framed as a simple, compact stream expression. On the other hand: streams can interfere with exception handling, and complex streams may be more difficult to reason about than equivalent non-stream code, so judgement is required.

Javadoc

Javadoc comments (/** … */) are meant to explain the intended purpose of the element they are attached to. See the style guide for a canonical list of when Javadoc is required.

Some guidelines for writing good Javadoc:

  • Spend more time documenting classes that will be frequently used or updated. Documentation mitigates against the risk of future misinterpretation.
  • Block tags (@param and @return) are generally considered optional:
    • Use @param block tags when detail is required to clearly convey the meaning of each function parameter.
    • Use a @return block tag if the main text cannot clearly express the meaning of the returned value in a natural way.

Methods

Some guidelines around Java methods:

  • Keep methods short and simple.

  • Avoid unwieldy parameter lists.

  • Beware of accepting or returning null.

  • Prefer specifying more general types for method parameters (e.g. List) and more specific types for return values (e.g. ImmutableList). For return types, think about the most specific type which (1) you are comfortable committing to and (2) captures important semantics (i.e. immutability).

  • Avoid output parameters (i.e. parameters whose main purpose is to store function output). Prefer a method signature like

    Answer foo(args...)

    instead of

    void foo(args..., Answer mutableAnswer)

See EJ3 #49-56 for more tips.

Null

Avoid null wherever possible! Of course, this isn’t always possible, but null checks and @Nullable annotations should always be viewed with healthy skepticism.

Nullable annotations

@Nullable may be used to indicate parameters or return values where null values are expected. When used, this annotation should be in addition to (but not instead of!) Javadoc comments indicating where and when null values are expected.

@NotNull and @Nonnull can be noisy; they should not be used, unless there is a particular reason that readers might otherwise expect an argument to be nullable.

Optional

Optional is... optional :)

java.util.Optional is often a good alternative to a null reference, especially as a method return type (ref). It is not a cure-all, however, and its use is neither required nor disallowed in Terra.

Guidelines:

  • Optional should not be used as a function parameter (see this post for some discussion on the topicref).
  • Usage within function bodies and as a return value is a matter of preference.
  • Optional usage patterns should be consistent within a class (and ideally throughout a service repo).

Visibility

A class should expose only the minimum-required set of methods and classes for use by clients. This is especially critical for common library developers, but service-level code also benefits from package-level visibility control.

Always use the @VisibleForTesting annotation on methods which are made public or package private just for testing purposes.