Skip to content

Latest commit

 

History

History
229 lines (157 loc) · 6.69 KB

HACKING.rst

File metadata and controls

229 lines (157 loc) · 6.69 KB

So you want to help the developent of TEG? cool!

How to send changes

The easiest way to get your changes included is to fork the project, and let us know about your changes with a pull request. If you don't like to have an account on github, you still can clone our repository (via https), and push your changes to a different service.

You also can use git format-patch to create a patch series. But we strongly prefer to have a "real" git repository to deal with, since it is much easier to work with than patches.

First steps

If you want to join the development of the software, you need to install the development packages of the used libraries. For Debian based environments, you can use the list in the file docker/debian

When you have the requirements, you can run ./build in the root directory.

Warning

This script always erases the build directory first.

This script

  • creates the autotools build infrastructure
  • creates a local build directory (bd), which is ignored by git
  • configures this build directory
    • With autotools maintainer mode (so you don't have to manually re-run autoconf/automake/... whenever you touch the build configuration)
    • Turns compiler warnings into errors
    • installs the software into bd/DD
  • build the software an run the unit tests

Once the build script finished, you can "install" the software with make -C bd install, and then run it with bd/DD/bin/tegclient.

Coding style

This code style describes how the code should look at the end. We know that at the moment the current code does not look like it. When you change existing code, or write new functionality, please try to follow this style.

Whitespaces and braces

We use the K&R-Style with tabs for block indentation, and spaces for continuation indentation.

Braces are set unconditionally, even if there is only one statement in your if/while/for block. See the famous "goto fail" bug why this is a good idea.

You can use scripts/style to format your sources according to the common style. When you use an IDE, you probably can also set it up that it will reformat on every save.

General style rules

Functions and code blocks

Limit the size of your functions. Every function spanning more than one page or is deeply nested is hard to comprehend. You should split those functions into smaller ones and give them appropriate names.

Try to write algebraic functions, which don't rely on global state. This kind of function is much easier to test. Also when you use such a function, you can be sure that it behaves always the same way when you give it the same parameters.

Comments

Good comments can make the code better understandable. But bad comments can make everything worse. In case of doubt try to clean up your code and introduce little helper functions. It is better to have easy to understand code than to have good comments which explain bad code.

General quality

Don't introduce new compiler warnings, they usually point to underlying problems. This is especially true for C code, where the compiler can do very bad things if it does not see a function declaration.

Language

New code uses C++20. We don't try to support ancient compilers.

Built in data types

Use the correct data type for each fact. When you have something which can be expressed as boolean, use bool (use #include <stdbool.h> in C code to get this type). If the thing can't be negative, use unsigned. If you need an integer of a defined width use the types from <stdint.h> / <cstdint>. When you iterate through an array by index, use std::size_t (or unsigned for some legacy code).

Prefer enumerations over integer or boolean types. Especially when they appear in function calls, enumerations can make the situation easier to understand.

frobnicate(23, true, false);

frobnicate(first_thing_from_left, with_foo, without_bar);

Use class enums in C++ code.

Error handling

Use assert() to check conditions in the code which are pre and postconditions (like that an output pointer is not NULL). Don't use assert on functions with side effects (assert calls can be disabled by configuration).

// do

const bool ok=frobnicate();
assert(ok);

// don't: the call to frobnicate can be eliminated in non-debug builds
assert(frobnicate());

Variables

Const

Const is your friend. Use it wherever possible.

Initialization

Try to avoid split variable definition and initialization. Especially don't put variable definitions at the top of functions. The time when compilers needed this is gone.

Scope and variable reuse

Limit the scope of variables to the most inner block possible. This make the code more readable and reduces the possibility to introduce errors.

Good:

for(std::size_t i=0; i<(sizeof(array)/sizeof(*array)); i++) {
    // for C code
}

for(std::size_t i=0; i<std::extent<decltype(array)>::value; i++) {
    // for C++ code
}

Better:

for(auto const& value: array) {
    // when you don't need the array position you can just iterate over the
        // fields
}

Bad:

int i; // no initialization

...

for(i=0; i<(sizeof(array)/sizeof(*array)); i++) { // signed loop variable
    ...
}

for(i=0; i<N_ARRAY_COUNT; i++) { // limit not calculated from the array
    ...
}

for(i=0; i<23; i++) { // magic number and variable recycling
    ...
}

Return values

Don't use TEG_STATUS for new code. This type is a dependency magnet, and does all kind of harm in different parts of the code.

When your function can't return anything, then don't return anything. This rule ensures that the calling function does not have to cope with error handling. When you return a constant in this case, it is very likely that the error handling in the calling code either does not exist, or is defect.

If the function only can fail or pass, use bool, and make your function sound natural to this. Like can_start_game() or is_human_player().

Objects in global space

Avoid global space. The code right now uses much of it, and this makes it very painful to work with.

Tests

New functionality has to be accompanied with unit tests.

Documentation

Put doxygen comments into the header for newly added parts (should the day come, and parts of teg wander into a library, the header are the parts which are available, while the sources are not).

Write down what the reason for this function is, together with pre and post conditions.