zeek/auxil/broker/CONTRIBUTING.md
Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

276 lines
7.9 KiB
Markdown

This document specifies the coding style for Broker. The style is based on
[CAF's][caf-style] and [VAST's][vast-style] style guidelines.
Git Workflow
============
Broker's git workflow follows [Zeek's development process][zeek-dev-proc]. In a
nutshell, this means:
- The `master` branch reflects the latest state of development and should
always compile.
- For new features and non-trivial fixes, use *topic branches* that branch off
`master` with a naming convention of `topic/description` or
`topic/your-name/description`. After completing work in a topic branch, check
the following steps to prepare for a merge back into `master`:
+ Squash your commits into a single one if necessary
+ Create a pull request to `master` on the [Broker github][broker-github]
+ Ask a maintainer to review your work
+ Address the feedback articulated during the review
+ A maintainer will merge the topic branch into `master` after it passes the
code review
Commit Messages
---------------
When writing commit messages, use the following style:
- The first line succinctly summarizes the changes in no more than 50
characters. It is capitalized and written in and imperative present tense:
e.g., "Fix bug" as opposed to "Fixes bug" or "Fixed bug".
- The first line does not contain a dot at the end. (Think of it as the header
of the following description.)
- The second line is empty.
- Optional long descriptions as full sentences begin on the third line,
indented at 72 characters per line.
Coding Style
============
General
-------
- Use 2 spaces per indentation level.
- No tabs, ever.
- No C-style casts, ever.
- 80 characters max per line.
- Minimize vertical whitespace within functions. Use comments to separate
logical code blocks.
- Namespaces and access modifiers (e.g., `public`) do not increase the
indentation level.
- The `const` keyword preceeds the type, e.g., `const T&` as opposed to
`T const&`.
- `*` and `&` bind to the *type*, e.g., `const T& arg`.
- Always use `auto` to declare a variable unless you cannot initialize it
immediately or if you actually want a type conversion. In the latter case,
provide a comment why this conversion is necessary.
- Never use unwrapped, manual resource management such as `new` and `delete`.
- Never use `typedef`; always write `using T = X` in favor of `typedef X T`.
- Keywords are always followed by a whitespace: `if (...)`, `template <...>`,
`while (...)`, etc.
- Leave a whitespace after `!` to make negations easily recognizable.
```cpp
if (! sunny())
stay_home()
```
- Opening braces belong onto the same line:
```cpp
struct foo {
void f() {
}
};
```
- Do not use the `inline` keyword unless to avoid duplicate symbols. The
compiler does a better job at figuring out what functions should be inlined.
Header
------
- Header filenames end in `.hh`, implementation filenames in `.cc` and files for
unit tests end in `.test.cc`.
- All header files should use `#pragma once` to prevent multiple inclusion.
- Don't use `#include` when a forward declarations suffices. It can make sense
to outsource forward declarations into a separate file per module. The file
name should be `<MODULE>/fwd.h`.
- Include order is from low-level to high-level headers, e.g.,
```cpp
#include <sys/types.h>
#include <memory>
#include <3rd/party.hpp>
#include "broker/endpoint.hh"
```
Within each section the order should be alphabetical. Broker includes should
always be in double quotes and relative to the source directory, whereas
system-wide includes in angle brackets.
- As in the standard library, the order of parameters when declaring a function
is: inputs, then outputs. API coherence and symmetry trumps this rule, e.g.,
when the first argument of related functions model the same concept.
Classes
-------
- Use the order `public`, `proctected`, `private` for functions and members in
classes.
- Mark single-argument constructors as `explicit` to avoid implicit
conversions.
- The order of member functions within a class is: constructors, operators,
mutating members, accessors.
- Friends first: put friend declaration immediate after opening the class.
- Use structs for state-less classes or when the API is the struct's state.
- Prefer types with value semantics over reference semantics.
- Use the [rule of zero or rule of
five](http://en.cppreference.com/w/cpp/language/rule_of_three).
- When providing a move constructor and move-assignment operator, declare them
as `noexcept`.
Naming
------
- Class names, constants, and function names are lowercase with underscores.
- Template parameter types should be written in CamelCase.
- Types and variables should be nouns, while functions performing an action
should be "command" verbs. Getter and setter functions should be nouns. We do
not use an explicit `get_` or `set_` prefix. Classes used to implement
metaprogramming functions also should use verbs, e.g., `remove_const`.
- All library macros should start with `BROKER_` to avoid potential clashes
with external libraries.
- Names of (i) classes/structs, (ii) functions, and (iii) enums should be
lower case and delimited by underscores.
- Put non-API implementation into namespace `detail`.
- Member variables have an underscore (`_`) as suffix, unless they constitute
the public interface. Getters and setters use the same member name without
the suffix.
- Put static non-const variables in an anonymous namespace.
Breaking Statements
-------------------
- Break constructor initializers after the comma, use two spaces for
indentation, and place each initializer on its own line (unless you don't
need to break at all):
```cpp
my_class::my_class()
: my_base_class{some_function()},
greeting_{"Hello there! This is my_class!"},
some_bool_flag_{false} {
// ok
}
other_class::other_class() : name_{"tommy"}, buddy_{"michael"} {
// ok
}
```
- Break function arguments after the comma for both declaration and invocation:
```cpp
a_rather_long_return_type f(std::string const& x,
std::string const& y) {
// ...
}
```
- Break before binary and ternary operators:
```cpp
if (today_is_a_sunny_day()
&& it_is_not_too_hot_to_go_swimming()) {
// ...
}
```
Template Metaprogramming
------------------------
- Use the `typename` keyword only to access dependent types. For general
template parameters, use `class` instead:
```cpp
template <class T>
auto f(typename T::type dependent) {
// ...
}
```
- Use `T` for generic, unconstrained template parameters and `x` for generic
function arguments. Suffix both with `s` for template parameter packs:
```cpp
template <class T, class... Ts>
auto f(T x, Ts... xs) {
// ...
}
```
- Break `using name = ...` statements always directly after `=` if they do not
fit in one line.
- Use one level of indentation per "open" template and place the closing `>`,
`>::type` or `>::value` on its own line. For example:
```cpp
using optional_result_type =
typename std::conditional<
std::is_same<result_type, void>::value,
bool,
optional<result_type>
>::type;
```
- When dealing with "ordinary" templates, use indentation based on the position
of the last opening `<`:
```cpp
using type = quite_a_long_template_which_needs_a_break<std::string,
double>;
```
Comments
--------
- Doxygen comments start with `///`.
- Use Markdown instead of Doxygen formatters.
- Use `@cmd` rather than `\cmd`.
- Use `//` or `/*` and `*/` to define basic comments that should not be
swallowed by Doxygen.
[caf-style]: https://github.com/actor-framework/actor-framework/blob/master/CONTRIBUTING.md
[vast-style]: https://github.com/mavam/vast/blob/master/CONTRIBUTING.md
[zeek-dev-proc]: https://www.zeek.org/development/howtos/process.html
[broker-github]: https://github.com/zeek/broker