|
| 1 | +# Java Style Guide |
| 2 | +Like many style guides, this Java style guide exists for two primary reasons. |
| 3 | +The first is to provide guidelines that result in a consistent code style across |
| 4 | +all of the Enso codebases, while the second is to guide people towards a style |
| 5 | +that is expressive while still easy to read and understand. |
| 6 | + |
| 7 | +In general, it aims to create a set of 'zero-thought' rules in order to ease the |
| 8 | +programmer burden; there is usually only _one way_ to lay out code correctly. |
| 9 | + |
| 10 | +<!-- MarkdownTOC levels="2,3" autolink="true" --> |
| 11 | + |
| 12 | +- [Code Formatting](#code-formatting) |
| 13 | + - [Naming](#naming) |
| 14 | +- [Commenting](#commenting) |
| 15 | + - [Documentation Comments](#documentation-comments) |
| 16 | + - [Source Notes](#source-notes) |
| 17 | + - [TODO Comments](#todo-comments) |
| 18 | + - [Other Comment Usage](#other-comment-usage) |
| 19 | +- [Program Design](#program-design) |
| 20 | + - [Testing and Benchmarking](#testing-and-benchmarking) |
| 21 | + - [Warnings, and Lints](#warnings-and-lints) |
| 22 | + |
| 23 | +<!-- /MarkdownTOC --> |
| 24 | + |
| 25 | +## Code Formatting |
| 26 | +This section explains the rules for visually laying out your code. They provide |
| 27 | +a robust set of guidelines for creating a consistent visual to the code. |
| 28 | + |
| 29 | +Primary code formatting is done using the [Google Java Format](https://github.com/google/google-java-format) |
| 30 | +tool, which enforces a clear and consistent style. This is a zero configuration |
| 31 | +tool, and hence there is no project-level configuration for this tool. It should |
| 32 | +be used for all new Java projects. |
| 33 | + |
| 34 | +All files must be formatted using this tool before being committed, and this |
| 35 | +should be set up as either a precommit hook, or using an integration in your |
| 36 | +IDE. |
| 37 | + |
| 38 | +### Naming |
| 39 | +Enso has some fairly simple general naming conventions, though the sections |
| 40 | +below may provide more rules for use in specific cases. |
| 41 | + |
| 42 | +- Types are written using `UpperCamelCase`. |
| 43 | +- Variables and function names are written using `camelCase`. |
| 44 | +- If a name contains an initialism or acronym, all parts of that initialism |
| 45 | + should be of the same case: `httpRequest` or `makeHTTPRequest`. |
| 46 | +- Short variable names such as `a` and `b` should only be used in contexts where |
| 47 | + there is no other appropriate name, and should _never_ be used to refer to |
| 48 | + temporary data in a function. |
| 49 | +- Names should be descriptive, even if this makes them longer. |
| 50 | + |
| 51 | +## Commenting |
| 52 | +Comments are a tricky area to get right, as we have found that comments often |
| 53 | +expire quickly and, in absence of a way to validate them, remain incorrect for |
| 54 | +long periods of time. That is not to say, however, that we eschew comments |
| 55 | +entirely. Instead, we make keeping comments up to date an integral part of our |
| 56 | +programming practice, while also limiting the types of comments that we allow. |
| 57 | + |
| 58 | +When we write comments, we try to follow one general guideline. A comment should |
| 59 | +explain _what_ and _why_, without mentioning _how_. The _how_ should be |
| 60 | +self-explanatory from reading the code, and if you find that it is not, that is |
| 61 | +a sign that the code in question needs refactoring. |
| 62 | + |
| 63 | +Code should be written in such a way that it guides you over what it does, and |
| 64 | +comments should not be used as a crutch for badly-designed code. |
| 65 | + |
| 66 | +### Documentation Comments |
| 67 | +One of the primary forms of comment that we allow across the Enso codebases is |
| 68 | +the doc comment. These are intended to be consumed by users of the API, and use |
| 69 | +the standard Javadoc syntax. Doc comments should: |
| 70 | + |
| 71 | +- Provide a short one-line explanation of the object being documented. |
| 72 | +- Provide a longer description of the object, including examples where relevant. |
| 73 | +- Explain the arguments to a function where relevant. |
| 74 | + |
| 75 | +They should not reference internal implementation details, or be used to explain |
| 76 | +choices made in the function's implementation. See [Source Notes](#source-notes) |
| 77 | +below for how to indicate that kind of information. |
| 78 | + |
| 79 | +### Source Notes |
| 80 | +Source Notes is a mechanism for moving detailed design information about a piece |
| 81 | +of code out of the code itself. In doing so, it retains the key information |
| 82 | +about the design while not impeding the flow of the code. |
| 83 | + |
| 84 | +Source notes are detailed comments that, like all comments, explain both the |
| 85 | +_what_ and the _why_ of the code being described. In very rare cases, it may |
| 86 | +include some _how_, but only to refer to why a particular method was chosen to |
| 87 | +achieve the goals in question. |
| 88 | + |
| 89 | +A source note comment is broken into two parts: |
| 90 | + |
| 91 | +1. **Referrer:** This is a small comment left at the point where the explanation |
| 92 | + is relevant. It takes the following form: `// Note [Note Name]`, where |
| 93 | + `Note Name` is a unique identifier across the codebase. These names should be |
| 94 | + descriptive, and make sure you search for it before using it, in case it is |
| 95 | + already in use. |
| 96 | +2. **Source Note:** This is the comment itself, which is a large block comment |
| 97 | + placed after the first function in which it is referred to in the module. It |
| 98 | + uses the java block-comment syntax `/* ... */`, and the first line names |
| 99 | + the note using the same referrer as above: `/* Note [Note Name]`. The name(s) |
| 100 | + in the note are underlined using a string of the `~` (tilde) character. |
| 101 | + |
| 102 | +A source note may contain sections within it where necessary. These are titled |
| 103 | +using the following syntax: `== Note [Note Name (Section Name)]`, and can be |
| 104 | +referred to from a referrer much as the main source note can be. |
| 105 | + |
| 106 | +Sometimes it is necessary to reference a source note in another module, but this |
| 107 | +should never be done in-line. Instead, a piece of code should reference a source |
| 108 | +note in the same module that references the other note while providing |
| 109 | +additional context to that reference. |
| 110 | + |
| 111 | +An example, based on some code in the GHC codebase, can be seen below: |
| 112 | + |
| 113 | +```java |
| 114 | +{ |
| 115 | +public SimplM<SimplEnv, OutExpr> prepRHS(SimplEnv env, OutExpr outExpr) { |
| 116 | + var ty1 = coercionKind(env); // Note [Float Coercions] |
| 117 | + |
| 118 | + if (!isUnliftedType(ty1)) { |
| 119 | + var newTy1 = convertTy(ty1) // Note [Float Coercions (Unlifted)] |
| 120 | + |
| 121 | + ...more code defining prepRHS... |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +/* Note [Float Coercions] |
| 126 | +~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 127 | +When we find the binding |
| 128 | + x = cast(e, co) |
| 129 | +we'd like to transform it to |
| 130 | + x' = e |
| 131 | + x = cast(x, co) // A trivial binding |
| 132 | +There's a chance that e will be a constructor application or function, or |
| 133 | +something like that, so moving the coercion to the usage site may well cancel |
| 134 | +the coercions and lead to further optimisation. |
| 135 | + ...more stuff about coercion floating... |
| 136 | +
|
| 137 | +== Note [Float Coercions (Unlifted)] |
| 138 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 139 | + ...explanations of floating for unlifted types... |
| 140 | +*/ |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +A source note like this is useful whenever you have design decisions to explain, |
| 145 | +but can also be used for: |
| 146 | + |
| 147 | +- **Formulae and Algorithms:** If your code makes use of a mathematical formula, |
| 148 | + or algorithm, it should note where the design element came from, preferably |
| 149 | + with a link. |
| 150 | +- **Safety:** Sometimes it is necessary to use an unsafe API in a context where |
| 151 | + it is trivially made safe. You should always use a source note to explain why |
| 152 | + its usage is safe in this context. |
| 153 | + |
| 154 | +### TODO Comments |
| 155 | +We follow a simple convention for `TODO` comments in our codebases: |
| 156 | + |
| 157 | +- The line starts with `TODO` or `FIXME`. |
| 158 | +- It is then followed by the author's initials `[ARA]`, or for multiple people |
| 159 | + `[ARA, WD]`, in square brackets. |
| 160 | +- It is then followed by an explanation of what needs to be done. |
| 161 | + |
| 162 | +For example: |
| 163 | + |
| 164 | +```java |
| 165 | +{ |
| 166 | +// TODO [ARA] This is a bit of a kludge. Instead of X it should to Y, accounting |
| 167 | +// for the fact that Z. |
| 168 | +} |
| 169 | +``` |
| 170 | + |
| 171 | +### Other Comment Usage |
| 172 | +There are, of course, a few other situations where commenting is very useful: |
| 173 | + |
| 174 | +- **Commenting Out:** You may comment out code while developing it, but if you |
| 175 | + commit any commented out code, it should be accompanied by an explanation of |
| 176 | + why said code can't just be deleted. |
| 177 | +- **Bugs:** You can use comments to indicate bugs in our code, as well as |
| 178 | + third-party bugs. In both cases, the comment should link to the issue tracker |
| 179 | + where the bug has been reported. |
| 180 | + |
| 181 | +## Program Design |
| 182 | +Any good style guide goes beyond purely stylistic rules, and also talks about |
| 183 | +design styles to use in code. |
| 184 | + |
| 185 | +### Testing and Benchmarking |
| 186 | +New code should always be accompanied by tests. These can be unit, integration, |
| 187 | +or some combination of the two, and they should always aim to test the new code |
| 188 | +in a rigorous fashion. |
| 189 | + |
| 190 | +- We tend to use ScalaTest, but also make use of ScalaCheck for property-based |
| 191 | + testing. |
| 192 | +- Tests should be declared in the project configuration so they can be trivially |
| 193 | + run. |
| 194 | +- A test file should be named after the module it tests. |
| 195 | + |
| 196 | +Any performance-critical code should also be accompanied by a set of benchmarks. |
| 197 | +These are intended to allow us to catch performance regressions as the code |
| 198 | +evolves, but also ensure that we have some idea of the code's performance in |
| 199 | +general. |
| 200 | + |
| 201 | +- We use Caliper for our benchmarks. |
| 202 | +- We measure time, but also memory usage and CPU time where possible. |
| 203 | +- Where relevant, benchmarks may set thresholds which, when surpassed, cause the |
| 204 | + benchmark to fail. These thresholds should be set for a release build, and not |
| 205 | + for a development build. |
| 206 | + |
| 207 | +_Do not benchmark a development build_ as the data you get will often be |
| 208 | +entirely useless. |
| 209 | + |
| 210 | +### Warnings, and Lints |
| 211 | +In general, we aim for a codebase that is free of warnings and lints, and we do |
| 212 | +this using the following ideas. |
| 213 | + |
| 214 | +#### Warnings |
| 215 | +New code should introduce no new warnings onto master. You may build with |
| 216 | +warnings on your own branch, but the code that is submitted as part of a PR |
| 217 | +should not introduce new warnings. You should also endeavour to fix any warnings |
| 218 | +that you come across during development. |
| 219 | + |
| 220 | +Sometimes it is impossible to fix a warning (often in situations involving the |
| 221 | +use of macros or code-generation). In such cases, you are allowed to suppress |
| 222 | +the warning locally, but this must be accompanied by a source note explaining |
| 223 | +why you are doing so. |
0 commit comments