-
Notifications
You must be signed in to change notification settings - Fork 604
Code Style
The Zeebe code style is a fork of the Google Java Style; it is essentially a direct copy with a few modifications; for anything not mentioned here, refer to their original guide.
Refer to https://github.com/camunda-cloud/zeebe/wiki/Logging for logging guidelines.
Top-level class/interface/enum contents should be ordered according to a slightly modified version of the Oracle Java Convention, that is:
- Static fields, in order of visibility
- Static initialization block
- Instance fields, in order of visibility
- Instance initialization block
- Constructors
- Methods
- Overridden methods must be grouped together
- Inner static classes, in order of visibility
- Inner interfaces, in order of visibility
- Inner enums, in order of visibility
- Inner classes, in order of visibility
Note that while we don't enforce an ordering for instance methods, it's recommended to group them together based on functionality.
Note that Atomix is a hard fork and the style guide is not applied comprehensively to the Atomix modules. We try to improve the situation step-by-step.
To be consistent and to make it easy, we decided to mark everything as final, if possible. This includes concrete classes, fields, parameters, local variables. For classes, we prefer composition over inheritance. For fields/parameters/variables, we prefer immutability over mutability.
We consider var
a useful keyword. Use it according to the recommended guidelines.
We don't use this
when it is not required.
We consider default (package-private) visibility of classes as useful to limit the visibility within a module and from other modules (as long as we find something better like Java's Jigsaw).
Be careful when using the default visibility for testing purposes. It can couple tests too close to the implementation.
When generating the Equals/Hashcode implementations make sure to choose the java.util.Objects.equals() and hashcode() (java 7+)
template. This exists in IntelliJ IDEA but also in Eclipse since 4.9.
Important
If you encounter issues with checkstyle, make sure that you have set up the Save actions plugin properly in Intellij IDEA, such that it generates brackets on safe. There is currently no other way of reformating, until google-java-format#51 is implemented.
Favor maintenance over performance. In the beginning of the project, Zeebe followed a garbage-free approach (pre-allocating objects and re-using these). With the evolution of Java and garbage-collection, we realized this is no longer necessary. Since, we've stepped back from this approach. However, we still do this for heavy objects (i.e. it takes a long time to create these objects, e.g. Record objects, big buffers, etc).
Favor mature well-maintained solutions over homegrown code. Historically, Zeebe tried to be dependency-free. This is hard to maintain and takes focus away from what matters. When we find well-maintained mature solutions, we deprecate our home grown solution and document how to replace it.
We favor a functional programming style in the engine. To support this, we implemented our own Either
type.
If we need more operators for the type, we can always enhance it or switch to a library.
We favor Java's text blocks over string concatenations for multi-line strings or strings that are longer than our usual column length. For example, JSON representations or error/rejection messages.
A new line in the text block results in a string with a new line. The new line can be suppressed by adding a trailing \
at the end of the line.
final String message =
"""
First line \
continue on the same line.
Second line."""
These practices are specific to the tests. The practices above also apply here.
We structure our tests according to Given-When-Then. See: https://martinfowler.com/bliki/GivenWhenThen.html
Carefully consider assertion failure messages when writing tests. AssertJ supports adding custom failure messages to assertion statements to help with this.
With the BPMN Model API it's easy to create a process using code. This is preferable over adding BPMN files to the resources. With the model API it's easy to see in a test case what the process under test looks like.
Focus on the piece of a process that you want to test. Extract this piece and only include this in the test. This keeps the test cases simple and readable. If there are multiple parts of a process that need to be tested, extract this into separate test cases.
When writing a test write it using JUnit5 where possible. If the test class is using JUnit4, where JUnit5 is supported, refactor the test class to JUnit5 is this is reasonable.
Tests using the EngineRule cannot use JUnit5 at this time.
For IntelliJ-IDEA users, some configurations are tracked in version control to assist in applying a consistent code style:
- the code style scheme is pre-configured and enabled
- the google-java-format plugin is pre-configured and required
- the save-actions plugin is pre-configured and required (requires IntelliJ-IDEA 2023.1+ build 231+)