Styles and Guidelines

Yanzheng Li edited this page Jan 6, 2015 · 13 revisions

This page defines a set of coding styles and guidelines that are recommended to be followed when contributing to code changes in this repository.

File Names and Paths

  • File names should be succinct, yet descriptive and should be able to reflect the meaning of the file. File names should be composed of alphanumerical character all in lower cases(in most cases), with words joined by underscores.
  • Header files should end with the suffix .h, while source files should end with the suffix .cc.
  • All header files should be included in the include/ directory, and all source files should be included in the src/ directory.

Coding Styles and Practices

Include Guards

  • Include guards should begin with SNEAKER_, followed by the name of the file or class in capital letters, and followed by _H_. For example, the header file that defines the standard_alloc_policy class has the include guard name of SNEAKER_STANDARD_ALLOC_POLICY_H_.
  • In most cases, include guards must start at the beginning of the file before any other macros, include directives and definitions. Also, they must be in the standard #ifndef, #define, #endif order.

Include Directives

  • Include directives must be listed in the following order, with each section separated by a blank line:

    • corresponding header
    • necessary project headers
    • 3rd party libraries headers
    • standard libraries headers
    • system headers

Namespaces and Declarations

  • Namespaces must begin with the most outer namespace of sneaker, followed by an inner namespace for one of the main areas in the project, such as algorithm, threading, io, etc. No third level namespaces are allowed.
  • Class, struct and function declarations must be included in header files, under the proper namespaces. All definitions must be placed in source files.

Classes

  • Use the keyword explicit for constructors that take one argument.
  • Only do work related to initialization/destruction of resources inside constructors and destructors respectively. Do not throw exceptions in constructors and destructors.
  • Implement copy constructor and assignment operator only if needed.
  • Make a class support move semantics if it is expected that instances of that class are often passed as rvalues.
  • Avoid multi-inheritance if possible, as it often introduces unnecessary code complexities and maintenance overheads.
  • Nested classes should be avoided if possible, as they force tight coupling between components and introduce overhead over management of classes.
  • Have the proper access modifier over class members.
  • Only inline functions that are short and have constant time runtimes.
  • Use the const modifier on member types, parameters, and function signatures where appropriate.
  • Mark function declarations with the throw keyword to specify the types of exceptions that are expected be thrown from a function.
  • Use structs only for passive data wrapper, otherwise use classes instead.

Resource Management

  • Follow the RAII (Resource Allocation Is Initialization) idiom where possible, this helps reduce a lot of complexity associated with resource managements.
  • Use smart pointers where there's complex delegation, sharing and relinquishment on ownership of resources. However, it's advised to use smart pointers from the standard template library or boost.
  • Have good comments and documentations at places where the ownership of resources are not obvious, or the ways resources are passed around are not clear. Specially, the places where a particular resource is initialized and destroyed should be mentioned.

Testing

  • Every component introduced should have the associated tests implemented. Tests live in the top level directory tests/.
  • Test files should be named with the name of the associated file, followed by either the suffix _unittest.cc or _test.cc.
  • It's a good practice to include a line of comment at the top of the test file to specify which definition that this test is written for.
  • Each test should have a test class defined, which inherits either directly or indirectly from ::testing::Test defined in libgtest.a. A test class should define any test fixtures needed as members, and may have the void Setup() and void TearDown() members implemented to do the appropriate setup and teardown work.
  • Each test class may have one or more test cases associated. Each test case should be named with the prefix Test, followed by a combination of words that form a sensical definition that can reflect the meaning of that particular test case. For example, a particular test case that tests the allocation of an allocator on empty memory should be named to something similar to TestAllocationOnEmptyMemory.
  • Each test should have sufficient test cases to cover all cases of a definition implementation. It's advised to follow the 3-times rule of thumb of testing, which essentially means that the amount of code in the test should be at least 3 times of the amount of code in the actual implementation being tested.
  • Commits that can only be considered to be pulled in into the master branch if all associated tests of a particular definition pass.

Commits

  • Commit messages should be properly written. The first line of the message should be a short line of text that can succinctly describes the changes made. An additional commit body message can be included if needed. Commits with non-sensical or incomplete commit messages may be rejected.
  • The first lines of commit messages must begin with a legitimate ticket/issue identifier in square brackets, followed by a short sentence. For example: [SNEAKER-45] Implement Tarjan's Strongly Connected Graph Algorithm.
  • Commits must have the correct author name and e-mail.
  • Commits must be as atomic as possible, meaning they should only include the changes for a particular implementation or bug fix, and should not include anything unrelated.
  • Commits should not include merged changes from other branches that are not already in master.
  • If a commit is already being pulled into master, do not amend that commit. Push a separate commit.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.