Метрики качества кода: за какими следить
Покрытие тестами, сложность, дублирование и дефекты не работают как универсальная оценка качества. Разбираем, какие метрики связать с рисками, как читать их в динамике и почему один высокий процент покрытия сам по себе не показывает качество.

Команда может поднять покрытие тестами с 58 до 85% и при этом не сделать код надёжнее: тесты проверяют простые геттеры, а критический платёжный сценарий остаётся без защиты. Поэтому качество кода нельзя свести к одной цифре. Для проекта на SonarQube Server 10.x и аналогичных анализаторах полезнее связать метрики со стоимостью изменений, риском дефекта и скоростью поставки, а затем смотреть не только абсолютное значение, но и его изменение от релиза к релизу.
Сначала отделите качество кода от скорости команды
Метрики вроде покрытия, цикломатической сложности и дублирования описывают сам код. Частота релизов, время восстановления и доля неудачных изменений говорят уже о процессе поставки. Смешивать эти группы опасно: команда может выпускать часто, но с большим числом откатов, либо иметь аккуратный код и слишком длинный цикл согласований.
Для ежедневного контроля достаточно собрать небольшой набор из четырёх слоёв:
- корректность — дефекты, уязвимости, ошибки статического анализа;
- изменяемость — сложность, размер функций, связность и дублирование;
- проверяемость — покрытие и результаты тестов;
- результат в продакшене — откаты, инциденты и время восстановления.
Измерять всё подряд не нужно. У каждой метрики должен быть владелец, источник данных и действие на случай ухудшения.
Хорошая метрика не доказывает, что код качественный. Она показывает, где следующий дефект обойдётся дороже всего.
Четыре метрики, с которых стоит начать
1. Дефекты и уязвимости статического анализа
Статический анализатор ищет проблемы без запуска приложения: недостижимые ветки, потенциальные ошибки работы с null, небезопасные конструкции, подозрительные преобразования типов и нарушения правил проекта. В отчёте разделяйте как минимум три типа сигналов:
- ошибка — вероятный дефект, который может изменить поведение программы;
- уязвимость — потенциальный риск для безопасности;
- запах кода — конструкция, усложняющая поддержку, но не обязательно содержащая ошибку.
Первым делом закрывайте новые ошибки и уязвимости в изменённых файлах. Старый технический долг можно разбирать отдельно. Если поставить запрет на весь легаси-код, команда быстро начнёт отключать правила или добавлять исключения без обсуждения.
Смотрите не только количество предупреждений, но и возраст открытых проблем, долю повторных нарушений и время от появления до исправления. Число замечаний само по себе плохо сравнивает сервисы: в большом модуле их почти всегда будет больше.
2. Покрытие тестами
Покрытие показывает, какая часть исполняемого кода была затронута тестами. В зависимости от инструмента это может быть покрытие строк, ветвлений, функций или условий. Эти показатели нельзя считать взаимозаменяемыми: тест может выполнить строку, но не проверить обе ветки условия.
Практичнее отслеживать три значения:
- общее покрытие проекта;
- покрытие изменённых строк;
- покрытие критических сценариев: авторизация, деньги, права доступа, удаление данных.
Для нового кода порог часто полезнее, чем требование повысить среднее значение по всему репозиторию. Например, проект может сохранить общий показатель на прежнем уровне, но не пропустить pull request, если изменённая логика не получила тестов. Конкретный порог выбирайте по типу системы, а не переносите из чужого проекта.
Покрытие не проверяет качество утверждений. Тест, который вызывает функцию и ничего не проверяет, увеличивает процент, но почти не снижает риск.
3. Цикломатическая сложность и размер изменений
Цикломатическая сложность приближённо показывает, сколько независимых путей выполнения есть в функции или методе. Условные операторы, циклы и обработчики исключений увеличивают число вариантов, которые нужно понять и протестировать. Метрика особенно полезна вместе с размером функции и покрытием ветвлений.
Не превращайте порог сложности в автоматический приговор. Большой диспетчер состояний может быть сложнее короткого метода с запутанными побочными эффектами. Тревожный сигнал — сочетание высокой сложности, низкого покрытия и частых изменений одного и того же участка.
Размер pull request тоже относится к качеству процесса. Чем больше файлов и логических решений в одном изменении, тем труднее его проверить и локализовать дефект. Для этой метрики не существует универсального числа строк: сравнивайте команды с их собственной историей и отдельно учитывайте механические изменения, например массовое форматирование.
4. Дублирование
Дублирование — это не только одинаковые строки. Два похожих блока с разными именами переменных могут расходиться после исправления бага, а копирование бизнес-правила в нескольких сервисах создаёт разные источники истины.
Сначала ищите дублирование в коде, который часто меняется. Удалять повторение в стабильном адаптере иногда дороже, чем оставить его. При рефакторинге проверьте, не появится ли слишком общий модуль: сокращение строк может увеличить связанность и затруднить независимые релизы.
Сноска. Технический долг — накопленная стоимость решений, которые ускорили поставку сейчас, но увеличили будущие расходы на изменение, тестирование или поддержку. Это не обязательно «плохой код»: долгом становится то, что уже мешает работе и требует осознанного погашения.
Как читать метрики вместе
Одна и та же цифра получает смысл только в контексте. Ниже — рабочая матрица для ревью и планирования.
| Сочетание сигналов | Вероятная проблема | Первое действие |
|---|---|---|
| Высокая сложность, низкое покрытие | Критическая логика трудно проверяется | Разбить изменение на части и добавить тесты на ветвления |
| Высокое покрытие, много дефектов | Тесты выполняют код, но не проверяют результат | Проверить утверждения и добавить негативные сценарии |
| Много дублирования, частые конфликты | Общее правило копируется в несколько мест | Найти источник истины и оценить безопасный рефакторинг |
| Низкий технический долг, много откатов | Проблема может быть в интеграции, окружении или релизном процессе | Сопоставить отчёты анализа с инцидентами и изменениями |
| Мало предупреждений, долгие ревью | Автоматические правила не покрывают архитектурные решения | Добавить чек-лист ревью и разбор крупных изменений |
Что измерять на уровне поставки
Для связи кода с реальными последствиями добавьте четыре процессных показателя: частоту развёртываний, время от изменения до поставки, долю неудачных изменений и время восстановления после сбоя. В разных командах их считают по-разному, поэтому зафиксируйте определения заранее.
Например, «неудачное изменение» должно означать не только полный откат. В него можно включить горячее исправление, ручное восстановление данных или инцидент, вызванный релизом. Если в одном сервисе считают только откаты, а в другом — все аварийные исправления, сравнение будет ложным.
Сопоставляйте процессные метрики с конкретными изменениями: какие участки кода менялись, были ли тесты, сколько предупреждений закрыли, возник ли инцидент. Так вы увидите не абстрактное падение качества, а цепочку «решение — риск — последствие».
Пороги, которые не превращают метрики в игру
Жёсткие границы полезны для очевидных нарушений: сборка не должна проходить с новой критической уязвимостью или падающими тестами. Для сложности, дублирования и общего покрытия лучше использовать постепенные правила.
- Снимите базовые значения за несколько релизов. Не начинайте с чужих порогов.
- Запретите ухудшение на изменённых файлах, если инструмент умеет считать «новый код».
- Для критических модулей установите отдельные правила и владельцев.
- Раз в месяц разбирайте исключения: временное ли это решение или правило слишком шумное.
- Связывайте метрику с действием: тест, рефакторинг, изменение архитектуры или расследование инцидента.
Порог, который команда научилась обходить, перестаёт быть контролем. Если разработчики добавляют бессмысленные тесты ради процента, цель выбрана неверно или проверка слишком примитивна.
Что ломается чаще всего
Среднее значение скрывает опасный модуль
В большом репозитории показатель 80% может складываться из хорошо покрытых утилит и одного платёжного модуля с покрытием 25%. Разрезайте отчёт по сервисам, каталогам и критическим сценариям.
Автоматический анализ создаёт шум
Если правило срабатывает сотни раз и почти никогда не приводит к исправлению, команда перестаёт читать отчёт. Настройте правила на язык и архитектуру проекта, а спорные случаи документируйте, а не скрывайте молча.
Метрика не учитывает контекст изменения
Массовое переименование и новая бизнес-логика могут добавить одинаковое число строк, но иметь разный риск. Отделяйте механические изменения от поведенческих и обсуждайте последнюю группу внимательнее.
Данные из разных инструментов не совпадают
Покрытие локального запуска и покрытие в CI может отличаться из-за версии рантайма, набора тестов, флагов компиляции или исключённых файлов. Зафиксируйте команду запуска, версию анализатора и источник отчёта.
Что делать дальше
Начните с одного репозитория и соберите историю за несколько релизов: новые дефекты, покрытие изменённых строк, сложность изменяемых участков, дублирование и последствия релизов. Затем выберите один показатель, который команда реально может улучшить в ближайшие две недели. Для продакшена добавьте связь с инцидентами и откатами. Через месяц проверьте не только цифры, но и поведение команды: стало ли ревью точнее, снизилось ли число повторных дефектов, быстрее ли локализуются проблемы.
Инвалидация старых предупреждений, выбор тестового фреймворка и архитектурные метрики — отдельные темы. Здесь важнее не собрать длинный дашборд, а превратить несколько сигналов в понятные инженерные решения.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: SonarQube Server: определения метрик кода, DORA: четыре ключевые метрики поставки программного обеспечения
Частые вопросы
Какое покрытие тестами считать хорошим?
Нужно ли блокировать сборку из-за любой проблемы статического анализа?
Что важнее: сложность или дублирование?
Можно ли сравнивать качество двух команд по одному дашборду?
Что делать, если метрики улучшаются, а инцидентов меньше не становится?
Какие версии инструментов учитывать?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.