Coding Guidelines - OpenSlides/OpenSlides GitHub Wiki

Following these guidelines will let writing readable and maintainable code and developing a resilient software.

Primary goal

The goal when developing software is to achieve high cohesion and loose coupling.

High cohesion

Cohesion is the degree of expediency. "High cohesion" means a very useful class. A high cohesion can be achieved by the Single Responsibility Principle. Build one class for one use-case.

Also,

  • mark every function and variable as private, unless another instance has to use it (information hiding)
  • mark every variable as constant, unless it will be changed
  • bundle shared data and classes for the same concern into a module. Each module should interact with another module only in one way.

Loose coupling

Coupling is the degree of dependencies of a class. "Loose coupling" can be achieved by these things, among others:

  • Make use of several patterns (publish-&-subscribe-, message-exchange-pattern)
  • Use interfaces to expect and use functions (port-adapter-pattern)
  • Separate the construction of classes to a dedicated mechanism, like dependency injection, the usage of the builder-pattern or singletons

Composition over inheritance

Inheritance is an anti-pattern. So, to avoid the usage of inheritance, implement classes, which fulfill a use-case and make use of their functions. Do never use multi-inheritance and try to inherit only one time.

Classes

To fulfill the single responsibility principle, every class must do only one thing. To know, if a class does only one thing, try to describe the functionality of the class. If there is an "and" in the description, it is a clue, that the class does more than one thing.

Structuring of functions

Implementation

When implementing a function, follow these steps:

  • Each function should have a maximum of twenty lines. If this maximum will be exceeded, it is an indication that a part of the function could be extracted as an additional function, which can be called. However, it is not bad, if a function have more than twenty lines, but hold it readable.
  • Each function should do only one thing. Sometimes, to achieve a feature, multiple things have to be done. Then, there can be a function, which makes use of multiple functions and delegates data between them.
  • Each operation block should have a maximal depth of two. This means, a block (of an if, for, etc.) should be surrounded only one time by another block. If more blocks are needed, extract these blocks into another function and call it.
  • Work on class variables. If it is necessary, that a function takes parameters (for example in case of a builder-/factory-function), try to use one or maximal two parameters. If it is necessary, that a function takes more than two parameters, use for example an object that share data.

Return values & errors

Do not try to return any error codes. Something like { isValid: false } is an anti-pattern. Instead, throw an error. The best way is to create custom error-classes, which will be thrown. Thus, code can be executed depending on the class.

Naming of variables, functions & classes

Use descriptive names for every variable, function and class. Try to describe the usage of a variable, function or class by its name. For example, use for variables of the type boolean or functions, which returns a boolean, something that suggests, that it can be asked. E.g. ask yourself "If it ...".

An overview of language specific guidelines:

⚠️ **GitHub.com Fallback** ⚠️