If there is no reason otherwise, use common/external code conventions and guidelines by default.
The programming code should prioritize portability, adaptability, stability, performance and readability. This can be made by making it easy to refactor the code or to translate it to a completely other language.
Use double-entry bookkeeping for the inputs and the outputs of the program. This can be implemented via Logs. Inputs without any relation to the outputs of the program, should cause errors. Otherwise, the program's configuration and input gets hard to understand pretty quickly.
Minimize side effects, as it makes it harder to understand a program.
Avoid test configurations by default. The default configuration should be one, that connects with as few as possible external resources. In the best case, there are none and such a config is ideal for testing, as most of the time nothing needs to be configured for a test. When the program is deployed into production, one hopefully just needs to configure the external resources and their access. This approach will probably lead to minimal configuration costs.
It should be possible to execute the tests programmatically inside the program. An appropriate main method should be provided, so the tests can be executed as a program. This ensures that tests are nothing special and therefore independent of the build system.
Everything should be tested.
Any kind of error testing method like the `orElseThrow` method of Java's Optional class, should have a required error message argument. Otherwise, it is unnecessarily hard to debug errors of users, whose computer cannot be accessed. Such error messages or reports do not have to be statically typed, in order to make it easier to add error messages to code, which is often more important, than having easily processed error messages.
The goal of restrictive methods, is to encourage developers to use the restrictive methods over the more general methods by making these easier to write. These restrictive methods are less general, but are also less likely to be used incorrectly.
Methods like add
of the Set interface signal and
assume a required state of the Set object and the arguments.
In case of add
, the method requires,
that the Set initially does not already contain the argument.
The Set method ensureContains
does not consider,
if the argument is already present in the Set.
If it is the case, then the argument is just not added to the Set.
Therefore, successful executions of add
and
ensureContains
lead to the same result.
In this context add
is called a restrictive version of the method ensureContains
.
The usage of ensureContains
is discouraged,
because adding a thing multiple times to a Set is likely to be an error,
if the developer does not know this.
Additionally, moving a call from a restrictive method version to the unrestricted version
is likely to be easier, than the other way around.
Checking the conditions of restrictive methods are generally speaking optional and not part of the main interface contract. If the execution does not comply with the restrictive methods, the code causing the problem directly has undefined behaviour. The actual behaviour depends on the environment and configuration. In other words no code is allowed to rely on the fact, that it will be informed about such errors, when these are incorrectly used.
For instance, calling add
on a Set,
in order to get an error, and than to act accordingly is not an alternative to calling
contains
and act upon its result.
This is done, so that the practical best runtime performance can be measured, when the software's performance is compared to others. This way, there is less incentive's to omit writing certain runtime checks.
If such tests are required to be executed, their checks have to be enabled according to the config.
The code should be formatted in such a way that the required space is minimized and the readability and navigability of the text is maximized. Empty lines are omitted, if indentation is enough to easily separate code blocks.
Trailing special symbols like commas in lists are preferred to leading symbols, as this is the most common way. Thereby, generally speaking, the overall structure of the source code is visible on the left side, whereas the meaning of the structure is located on the right side.
If a body contains many variables, that are set procedurally, consider declaring all variables at the start of the body.
Automatic code styling/formatting should never remove already present new line characters, as otherwise it is hard to structure large code statements. The automatic formatting should also not add new line symbols, as this makes it harder to structure flowing text, where long lines are more acceptable. In XML/XSL automatically added new line symbols also create problems, as these may add new unintended meaning. In most cases, during automatic formatting only whitespaces (without new line symbols) between symbols should be normalized.
Maximize the replaceability of external dependencies. Minimize dependency on concrete versions of the dependencies. Prefer own interfaces and avoid accessing external things. Use dependency injection via static methods as this supports most paradigms and implementations. This also supports dependency injection of general objects like lists nicely.
Minimize the number of extern dependencies that are explicitly supported as these can cause a maintenance burden. Minimize side effects between dependencies. For example, in an ideal case transitive dependencies are not shared between dependencies.
If there are not enough resources or if it is not optimal to develop and maintain a piece of required functionality, then use a dependency in order to get this functionality and declare the functionality of the dependency as something that is out of scope of the project. The support, usage and extension of the dependency might still be part of the project.
Minimize direct dependencies between different things inside the project in order to easier analyse the effect of one piece of code to the rest of the project.
Prefer placing support documentation for errors and similar in program code, instead of documentation, as this is more stable regarding automatic code refactoring. This can be done by adding runtime checks with an extensive error message.
If a support documentation is needed, try to structure it in the form of a decision tree, that finds the appropriate problem and solution given a set of symptoms.
The following external code guidelines can be considered or are interesting for this project. The guidelines are ordered by descending priority: