Перейти к основному содержимому

4.06. Неиспользуемый код и технический долг

Разработчику Архитектору Инженеру

Неиспользуемый код и технический долг

Мёртвый код: переменные, методы, классы, импорты

Мёртвый код — фрагменты программы, которые никогда не выполняются в процессе работы приложения.

Типы мёртвого кода:

ТипПримерПоследствия
Недостижимый кодКод после return или в ветке if (false)Загромождает кодовую базу
Неиспользуемые переменныеОбъявленные, но не читаемые переменныеВводит в заблуждение при чтении кода
Неиспользуемые методыМетоды без вызововУвеличивают размер сборки
Неиспользуемые классыКлассы без ссылокУсложняют навигацию по коду
Неиспользуемые импортыПодключённые, но не используемые модулиЗамедляют сборку и загрузку

Пример мёртвого кода:

public class OrderService
{
private readonly ILogger _logger;
private readonly int _unusedField = 42; // Неиспользуемое поле

public OrderService(ILogger logger, IEmailService emailService)
{
_logger = logger;
// emailService не используется — неиспользуемый параметр
}

public void ProcessOrder(Order order)
{
ValidateOrder(order);
return; // Ранний возврат

// Мёртвый код — никогда не выполнится
SaveOrder(order);
SendConfirmation(order);
}

private void UnusedMethod()
{
// Метод без вызовов
}
}

Как его находить: статический анализ, coverage

Статический анализ — проверка кода без его выполнения для обнаружения потенциальных проблем.

Инструменты статического анализа:

ЯзыкИнструменты
C#Roslyn Analyzers, ReSharper, SonarQube
JavaSonarQube, PMD, SpotBugs
Pythonpylint, flake8, vulture
JavaScriptESLint, SonarJS
Gogo vet, staticcheck

Пример конфигурации ESLint для обнаружения неиспользуемого кода:

{
"rules": {
"no-unused-vars": "error",
"no-unreachable": "error",
"no-unused-expressions": "error",
"no-unused-private-class-members": "error"
}
}

Покрытие кода (code coverage) — метрика, показывающая долю кода, выполненного при тестировании.

Инструменты измерения покрытия:

ПлатформаИнструмент
.NETcoverlet, dotCover
JavaJaCoCo, Cobertura
Pythoncoverage.py
JavaScriptIstanbul/nyc

Пример анализа покрытия в Python:

# Запуск тестов с измерением покрытия
coverage run -m pytest
coverage report --show-missing
coverage html # Генерация HTML-отчёта

Пример отчёта покрытия:

Name             Stmts   Miss  Cover   Missing
----------------------------------------------
order_service 50 5 90% 23-25, 42, 47
payment_gateway 30 15 50% 12-18, 25-32

Строки 23-25, 42, 47 в order_service и большая часть payment_gateway не покрыты тестами — возможный мёртвый код или недостаточное тестирование.


Последствия: усложнение поддержки, рост времени сборки

Последствия мёртвого кода:

  1. Усложнение понимания кода Разработчики тратят время на анализ кода, который не влияет на поведение системы.

  2. Рост размера сборки Каждый неиспользуемый метод и класс увеличивает размер итогового артефакта.

  3. Замедление сборки Компилятор обрабатывает весь код, включая мёртвые участки.

  4. Ложные срабатывания при рефакторинге Инструменты рефакторинга могут предлагать изменения в мёртвом коде.

  5. Риск случайной активации Мёртвый код может быть случайно задействован при изменении логики.

Пример влияния на размер сборки:

# С мёртвым кодом
-rw-r--r-- 1 user staff 15M app-with-dead-code.dll

# Без мёртвого кода
-rw-r--r-- 1 user staff 12M app-clean.dll

# Экономия: 3 МБ (20%)

Удаление и комментирование

Комментирование мёртвого кода — практика закомментировать, а не удалить неиспользуемый код.

Пример плохой практики:

public void ProcessOrder(Order order)
{
ValidateOrder(order);
// SaveOrder(order); // Закомментировано 2023-05-15, не нужно временно
// SendConfirmation(order); // Закомментировано 2023-05-15
// LogToLegacySystem(order); // Старая система, убрать позже
NotifyCustomer(order);
}

Проблемы закомментированного кода:

  1. Загрязнение кодовой базы Комментарии с кодом занимают место и отвлекают внимание.

  2. Неопределённость срока хранения "Временно" превращается в "навсегда". Через год никто не помнит, зачем код был закомментирован.

  3. Отсутствие версионного контроля Закомментированный код дублирует функциональность системы контроля версий (Git).

  4. Сложность поддержки При изменении сигнатуры методов закомментированный код становится некорректным, но остаётся в файле.

Правильный подход — удаление с сохранением в истории версий:

# Удаляем мёртвый код
git rm dead-code.cs

# Фиксируем изменение с описанием
git commit -m "Удалён неиспользуемый класс LegacyProcessor"

# При необходимости код можно восстановить из истории
git log --all --full-history -- "**/LegacyProcessor.cs"
git checkout <commit-hash> -- path/to/LegacyProcessor.cs
Когда допустимо оставлять закомментированный код

Закомментированный код допустим в редких случаях:

  • временные отладочные фрагменты в процессе разработки (до коммита)
  • альтернативные реализации с явным указанием причины выбора
  • документирование намерений через примеры использования

Во всех случаях требуется подробный комментарий с датой и причиной.