Rules

Naming#

Use lowerCamelCase for variables and functions.

int userAge {};
int maxAttempts {};
int totalScore {};

int readNumber();
int calculateTotal();
void printResult(int value);

Variables should usually be nouns.

int number {};
int result {};
int attempts {};
std::string name {};

Functions should usually start with verbs.

readNumber()
calculateScore()
printResult()
isEven()
hasInput()

Names should explain intent.

// Bad
int data {};
int thing {};
int temp {};

// Better
int userAge {};
int finalScore {};
int selectedOption {};

Use short generic names only in tiny scopes.

for (int i { 0 }; i < 10; ++i)
{
}

Use descriptive names when the variable lives longer than a few lines.

for (int studentIndex { 0 }; studentIndex < studentCount; ++studentIndex)
{
}

Boolean names should read like yes/no questions.

bool isValid {};
bool hasInput {};
bool shouldPrint {};
bool canMove {};

Avoid negative boolean names when possible.

// Harder to read
bool isNotValid {};
bool hasNoInput {};

File names should be lowercase with underscores.

main.cpp
io.cpp
math.cpp
user_input.cpp
score_calculator.cpp
game_state.cpp

Use one word for a simple concept.

main.cpp
io.cpp
math.cpp

Use underscores for descriptive names with multiple words.

user_input.cpp
score_calculator.cpp
game_state.cpp

Name files after what they contain or the responsibility they handle.

user_input.cpp         reading input from the user
score_calculator.cpp   score calculation logic
game_state.cpp         game state data and helpers

Avoid vague file names.

utils.cpp
helpers.cpp
stuff.cpp

Functions#

One function should do one job.

- read input
- calculate result
- print output

Keep main() simple.

int main()
{
    int number { readNumber() };
    int result { doubleNumber(number) };

    printResult(result);

    return 0;
}

Use parameter names that explain the role.

int doubleNumber(int number);
int calculateArea(int width, int height);

Avoid meaningless parameter names.

// Bad
int calculateRectangleArea(int x, int y);

// Good
int calculateRectangleArea(int width, int height);

// Fine for coordinates
int calculateDistance(int x1, int y1, int x2, int y2);

If a function returns a value, use the returned value.

int number { readNumber() };

Do not call a function and expect an argument to change unless it was designed to do that.

// Bad
readNumber(number);

Function names should make side effects obvious.

int calculateResult(int number);
void printResult(int result);
int readNumber();

Avoid hidden side effects inside calculation functions.

// Bad
int calculateResult(int number)
{
    std::cout << "Calculating...\n";
    return number * 2;
}

Variables#

Use brace initialization by default.

int number {};
int maxAttempts { 3 };
std::string name {};

Declare variables close to where they are used.

int number { readNumber() };
int result { doubleNumber(number) };
printResult(result);

Do not create variables before they are needed.

// Bad
int number {};
int result {};

// many lines later...

Use const when a value should not change.

const int maxAttempts { 3 };

Use constexpr for true compile-time constants.

constexpr int maxAttempts { 3 };

Use named constants instead of unexplained numbers.

constexpr int maxAttempts { 3 };

if (attempts >= maxAttempts)
{
    return;
}

Comments#

Do not comment what the code already says.

// Bad
// add 1 to count
++count;

Comment why something exists.

// User gets three attempts before program exits.
constexpr int maxAttempts { 3 };

Do not use comments to excuse bad names.

// Bad
int d {}; // user age

// Better
int userAge {};

Files#

Do not include .cpp files.

// Bad
#include "io.cpp"

// Good
#include "io.h"

Include only what the file uses.

#include "io.h"

#include <iostream>