Development Guidelines

Please be aware that contributing code to this repo requires following several opinionated rules. Pull requests that ignore the guidelines are unlikely to be accepted.

These development guidelines will be updated whenever we need to clarify missing rules or adjust existing guidance.

This project consists of both Python and C++ code, so the guidelines cover expectations for each language.

Both humans and AI contributors should follow these guidelines.

Common Guidelines

Naming

Names should be crystal clear within the code context. That context can be a function, module (file), or library. In general, prefer the most specific name unless a conventional name is already established.

Bad examples:
  • data1, data2

  • a, b, c, d, e

  • df

  • function1

  • array

Avoid abbreviations whenever possible. Abbreviations make the code harder to read and debug unless the term is widely known or an industry standard.

Numbers

Magic numbers are not allowed. Every constant should be assigned to a well-named variable that explains its purpose.

Object-Oriented Programming (OOP)

OOP is available in both C++ and Python. Use classes to encapsulate related behavior and data when those pieces belong together.

We allow subtyping, but we do not allow inheritance.
  • Subtyping: allowed - override member functions that have no implementations (interfaces in C++).

  • Inheritance: disallowed - do not override functions that already provide implementations.

Class and static methods are allowed in Python. Remember that class methods provide no benefit over module-level functions unless the behavior is tied to class-level state. Place the function in the scope that matches its responsibility.

Functions

  • Please refactor aggressively, except in test cases where limited duplication can aid readability. Shared test helpers should still live in utility functions.

  • Express complex conditional filtering logic with guard clauses to improve readability.

Python Guidelines

  • We follow PEP 8 closely, with the exception of a 120-character line width. Refer to PEP 8 for the remaining details.

  • Python type hints are mandatory for all function arguments and return types, and mypy will check them.

  • We use the Black formatter; run black -l 120 -C.

  • All Python imports must be absolute.

  • We do not allow any content in __init__.py files unless a special case (such as the project root) requires it for user convenience.

Test Cases

  • Python test cases should use the standard unittest module, and each test class should live in its own Python file named with the test_*.py prefix.

  • Mirror the unit-test directory structure to the code structure because the tests directory lives at the repo root.

C++ Guidelines

Naming

Please use PascalCase for namespaces and classes. Capitalize the first character, for example:
  • SomeClass

  • LongNameClass

Use all capital letters for global variables or macros. System or third-party library definitions are exempt from this rule:

  • GLOBAL_VARIABLE

Use camelCase for variable and function names, with the first character lower case:
  • addSomeValue

  • deleteSomeValue

Keep abbreviations uppercase, for example:
  • TCPAcceptor instead of TcpAcceptor

  • IOSocket instead of IoSocket

File names should use snake_case. Use the .h extension for headers and .cpp for source files:
  • header files: message_connection.h

  • source files: message_connection.cpp

Formatting

Please use the .clang-format file in the repo root for code formatting.

Namespaces

  • Do not add using namespace directives like using namespace std;.

  • Always use fully qualified names such as std::cout.

Includes

  • Remove include files when none of their symbols are used.

  • Always include the header that defines the symbols you rely on; avoid depending on transitive includes. For example: * There are files common.h, some_module.h, and application.cpp. * At the top of common.h, there is #include <cstring>. * At the top of some_module.h, there is #include “common.h”. * At the top of application.cpp, there is #include “some_module.h”. * Even though application.cpp compiles because <cstring> is indirectly included through common.h, explicitly

    include <cstring> in application.cpp.

Struct/Class

In C++, structs and classes are the same except for default access. Use struct for passive data structures with minimal helpers. Use class for stateful types, and do not expose fields directly. Provide setters and getters instead.

struct Address {
    std::string domain;
    int port;
};

// If a data structure has internal state that consumers should not mutate directly, provide methods to modify that
// state instead of exposing the members.
class Client {
public:
    void send(const std::vector<uint8_t>& buffer);

    int getMessageCount() const;

private:
    int messageCount;
};

Code Layout

For any header or source file, order elements as follows:
  • system library includes

  • standard library includes

  • third-party library includes

  • in-library includes

  • global variables

  • API classes and functions

  • internal functions that are not meant to be used outside the file

Class definitions should follow this order:

// List public members first, then protected, then private sections.
// Place using declarations at the top, followed by constructors, copy/move constructors, and the destructor.
// Declare member functions before member variables.
class Foobar {
public:
    // Using types should go first.
    using Type = some_namespace::SomeType;

    Foobar();
    Foobar(const std::string& foobar) : _foobar(foobar) {}
    ~Foobar();

    const std::string& getCurrentFoobar() const;

protected:
    void someProtectedMethod();

    int _someProtectedVariable;

private:
    void somePrivateMethod();

    std::string _foobar;
    int _somePrivateVariable;
};