Clean Code на C++: принципы написания читаемого кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clean Code на C++: как писать код, который не стыдно показать коллегам

Каждый разработчик C++ рано или поздно сталкивается с ситуацией, когда собственный код через месяц превращается в "тёмный лес". Переменные вроде int a, функции длиной в 300 строк и магические числа по всему проекту — знакомо? В этой статье мы разберём принципы Clean Code применительно к C++, чтобы ваш код был не только рабочим, но и понятным для других (и для вас в будущем).

1. Именование переменных, функций и классов

Хорошее имя — половина дела. В C++ принято использовать camelCase для переменных и функций, PascalCase для классов и UPPER_CASE для констант (хотя в современном C++ предпочитают constexpr).

Плохой пример:

int d; // elapsed time in days
float x; // salary multiplier
bool fl; // is file loaded?

Хороший пример:

int elapsedDays;
float salaryMultiplier;
bool isFileLoaded;

Правило простое: имя должно отвечать на вопрос "что это?" или "что делает?". Избегайте сокращений (кроме общепринятых, например idx для индекса). Для булевых переменных используйте префиксы is, has, can.

2. Функции должны быть маленькими и делать одну вещь

Классический принцип Clean Code — функция должна выполнять ровно одну задачу. Если вы не можете придумать короткое и понятное имя для функции — скорее всего, она делает слишком много.

Плохой пример:

void processData(std::vector<int>& data) {
    // сортировка
    std::sort(data.begin(), data.end());
    // удаление дубликатов
    data.erase(std::unique(data.begin(), data.end()), data.end());
    // расчет среднего
    double sum = 0;
    for (int val : data) sum += val;
    double avg = sum / data.size();
    // вывод
    std::cout << "Average: " << avg << std::endl;
}

Хороший пример:

std::vector<int> sortAndUnique(std::vector<int> data) {
    std::sort(data.begin(), data.end());
    data.erase(std::unique(data.begin(), data.end()), data.end());
    return data;
}

double calculateAverage(const std::vector<int>& data) {
    if (data.empty()) return 0.0;
    double sum = std::accumulate(data.begin(), data.end(), 0.0);
    return sum / data.size();
}

void printAverage(const std::vector<int>& data) {
    auto processed = sortAndUnique(data);
    double avg = calculateAverage(processed);
    std::cout << "Average: " << avg << std::endl;
}

Каждая функция решает одну задачу, легко тестируется и переиспользуется. Длина функции не должна превышать 20-30 строк — это хороший ориентир.

3. Избегайте магических чисел и дублирования

Магические числа — это числа, значение которых непонятно из контекста. Вместо них используйте именованные константы.

Плохой пример:

double calculatePrice(double base) {
    return base * 1.2 + 5.0;
}

Хороший пример:

constexpr double TAX_RATE = 1.2;
constexpr double DELIVERY_FEE = 5.0;

double calculatePrice(double basePrice) {
    return basePrice * TAX_RATE + DELIVERY_FEE;
}

То же самое касается дублирования кода. Если вы копируете блок кода более одного раза — выносите его в функцию. Правило DRY (Don't Repeat Yourself) — основа поддерживаемого кода.

4. Комментарии — это не оправдание плохому коду

Лучший комментарий — это хорошо написанный код, который не требует пояснений. Комментарии должны объяснять почему код делает что-то неочевидное, а не что он делает.

Плохой пример:

// Увеличиваем i на 1
i = i + 1;

Хороший пример:

// Используем побитовый сдвиг для оптимизации умножения на 2
int doubled = value << 1;

Избегайте комментариев-заглушек, закомментированного кода и излишних пояснений. Если код требует длинного комментария — возможно, его стоит рефакторить.

5. Принципы SOLID для C++ (кратко)

Хотя SOLID чаще применяют в ООП-языках вроде Java, для C++ эти принципы тоже актуальны:

  • Single Responsibility — класс должен иметь только одну причину для изменения.
  • Open/Closed — классы открыты для расширения, но закрыты для модификации (используйте виртуальные функции и наследование).
  • Liskov Substitution — производные классы должны заменять базовые без изменения поведения.
  • Interface Segregation — не заставляйте классы реализовывать методы, которые им не нужны.
  • Dependency Inversion — зависите от абстракций, а не от конкретных реализаций.

Пример нарушения Interface Segregation:

class IWorker {
public:
    virtual void work() = 0;
    virtual void eat() = 0; // не все работники едят (например, робот)
};

Лучше разделить интерфейсы:

class IWorkable {
public:
    virtual void work() = 0;
};

class IFeedable {
public:
    virtual void eat() = 0;
};

Заключение

Clean Code на C++ — это не про идеальный синтаксис, а про уважение к себе и коллегам, которые будут читать ваш код. Начните с малого:

  • Давайте переменным осмысленные имена.
  • Дробите длинные функции на маленькие.
  • Убирайте магические числа и дублирование.
  • Пишите комментарии только там, где это действительно нужно.

Помните: код читается гораздо чаще, чем пишется. Инвестируйте время в его чистоту —

Блоги

Рекомендаций по книгам