Измеряйте рост мертвого кода, пока AI-репозитории не замедлили вашу команду
Узнайте, как измерять рост мертвого кода по возрасту файлов, количеству вызовов и пробелам в ответственности, чтобы убирать малоценный код до того, как AI-heavy репозитории начнут разрастаться и путать команду.

Что мертвый код делает с AI-heavy репозиториями
AI-инструменты удешевляют код. Дорогим становится здравый смысл.
В AI-heavy репозитории десять файлов могут появиться раньше, чем кто-то успеет внимательно разобрать один. Эксперименты, вспомогательные модули, скопированные шаблоны и недоделанные попытки быстро накапливаются. Проблема не только в лишнем коде. Проблема в лишней неуверенности.
Старые файлы продолжают всплывать в поиске, автодополнении и pull request'ах даже после того, как продукт перестал их использовать. Разработчик видит аккуратно названный модуль и думает, что он по-прежнему важен. Потом он копирует его подход, спрашивает о нем на ревью или избегает правок, потому что файл выглядит рискованно.
Эта нагрузка незаметна, потому что приходит по чуть-чуть. Поиск становится шумным. По запросу показываются текущая реализация, две заброшенные версии и скрипт миграции из прошлого месяца. Ревью тоже замедляется по той же причине. Изменение затрагивает файл, никто не знает, кто за него отвечает, и команда начинает гадать, осталась ли где-то скрытая зависимость.
Пять минут здесь, десять там, несколько осторожных сообщений в чате — и один инженер решает оставить подозрительный файл в покое. Для занятой команды это превращается в часы каждую неделю.
Но главная цена — доверие. Репозиторий должен отвечать на простой вопрос: «Как этот продукт работает сегодня?» Когда неиспользуемый код остается на месте, ответ становится размытым. Люди перестают доверять кодовой базе как источнику правды и начинают опираться на память, старые тикеты или на того самого коллегу, который помнит, зачем существует папка.
Мертвый код — это не просто мусор. Он делает решения медленнее и менее надежными. В AI-heavy репозиториях, где код появляется быстро и стили сильно различаются, эта цена проявляется особенно рано.
Три сигнала, за которыми стоит следить
Команды обычно замечают мертвый код слишком поздно. AI-инструменты усугубляют это, потому что они быстро пишут код, копируют шаблоны и оставляют после себя файлы, которые все еще выглядят правдоподобно, хотя продукт уже ушел вперед.
Самый безопасный способ отслеживать рост мертвого кода — смотреть сразу на три сигнала: возраст файла, реальное использование и ответственность. По отдельности каждый из них может ввести в заблуждение.
Возраст файла
Файл, к которому никто не прикасался восемь или двенадцать месяцев, заслуживает повторной проверки, особенно если остальная часть этого участка продукта несколько раз менялась. Возраст сам по себе не доказывает, что файл мертв. Некоторые куски кода молчат просто потому, что они стабильны. Но старые файлы часто собирают заброшенные эксперименты, устаревшие хелперы и недоделанные интеграции, которые команда забыла убрать.
Количество вызовов и пробелы в ответственности
Использование показывает, доходит ли рабочий код до файла. Проверяйте импорты, хиты маршрутов, фоновые задачи, расписанные задания, CLI-команды и покрытие тестами. Файл с почти нулевым использованием в продуктивных путях и тестах — более сильный кандидат на очистку, чем старый файл, который по-прежнему запускается каждый день.
Ответственность отвечает на другой вопрос: кто сейчас чувствует себя хозяином этого кода? Когда у файла нет владельца, люди избегают его менять. Именно так лишний код живет месяцами. Это обычно видно по файлам без понятного недавнего автора, без стабильного ревьюера или по комментариям, из которых понятно, что никто не уверен, кто должен трогать этот участок.
Эти сигналы становятся полезнее вместе. Старый, неиспользуемый код без владельца часто можно безопасно удалить после проверки. Старый код, который все еще работает, но у него нет владельца, сначала требует четкой передачи ответственности. Новый код с низким использованием часто означает заброшенный эксперимент, а не долгоиграющий мертвый код. Старый код с низким использованием и активным владельцем обычно требует короткого разговора, а не PR на удаление.
Представьте внутреннюю AI-фичу, которую запустили шесть месяцев назад, а потом заменили. Старые prompt builders все еще лежат в репозитории. По логам видно, что вызовов нет. Изначальный инженер перешел в другой участок. Такой файл — сильный кандидат на удаление.
Постройте простой score для очистки
Cleanup score помогает перестать спорить на уровне интуиции. Дайте каждому файлу несколько баллов за возраст, использование и ответственность. Этот score не решает, что удалять. Он показывает, какие файлы стоит проверить в первую очередь.
Начните с возраста. Если файл не менялся 9–12 месяцев, добавьте баллы. Если он оставался нетронутым через несколько релизов, добавьте еще. Старый код не всегда мертв, но старый нетронутый код часто остается только потому, что никто не хочет тратить время на доказательство его полезности.
Затем снижайте score, если код реально работает. Если тесты часто его затрагивают, уменьшите риск. Если production-логи, трассировки или количество вызовов показывают стабильное использование, снизьте его еще раз. Файл может выглядеть забытым в Git, но при этом каждый день быть на горячем пути.
Пробелы в ответственности должны быстро повышать score. Добавляйте баллы, когда последний человек, который трогал файл, ушел, когда несколько людей правили его короткими всплесками и сейчас за него никто не отвечает, или когда никто в команде не может объяснить, зачем он вообще существует. В AI-heavy репозиториях это часто случается со старыми prompt runners, одноразовыми evaluation-скриптами и сгенерированными хелперами.
Достаточно простой модели:
risk score = age points + owner gap points - test usage points - runtime usage points
Сложная математика не нужна. Простая шкала отлично работает:
- Возраст: 0–4 балла
- Пробел в ответственности: 0–3 балла
- Использование в тестах: вычесть 0–2 балла
- Runtime-использование: вычесть 0–4 балла
Устаревший файл без владельца и без runtime-вызовов может получить 6 или 7 баллов. Двухлетний модуль, который по-прежнему активно вызывается в тестах и в production, может опуститься до 1 или 0, и это значит, что его лучше оставить в покое.
Отсортируйте файлы по score и сначала проверьте верхнюю группу. Для большинства команд достаточно топ-20 файлов или топ-5% репозитория. Так ревью остается достаточно небольшим, чтобы его реально завершить.
Одна продуктовая команда попробовала это на старых model adapters и background workers. Файлы с худшим score оказались не опасными для удаления. Это были остатки, которые только тормозили ревью и делали AI-сгенерированные правки менее надежными.
Проверяйте кандидатов шаг за шагом
Не начинайте со всего репозитория. Начните с топ-20 файлов из cleanup score. Так у вас будет маленький набор, который можно внимательно проверить. В AI-heavy кодовой базе старые обертки, дублирующие хелперы, недоделанные prompt chains и неиспользуемые API routes обычно быстро поднимаются наверх.
Откройте каждый файл и задайте прямой вопрос: кто еще его вызывает? Проверьте импорты, привязки маршрутов, планировщики задач, CLI-команды и ветки с feature flags. Если ничего напрямую не указывает на файл, посмотрите registries, reflection или записи в конфиге. AI-сгенерированный код часто прячет использование в местах, которые люди забывают проверить.
Потом проверьте три источника недавней жизни: логи, тесты и историю коммитов. Логи показывают, трогает ли production этот код. Тесты показывают, зависит ли от него еще какое-то поведение. Недавние изменения показывают, что разработчику он все еще важен, даже если количество вызовов мало.
Файл с нулем вызовов, но свежим исправлением бага, не мертвый. Файл со старыми коммитами, без активности в логах и без покрытия тестами — куда более сильный кандидат.
Простая метка помогает сохранять честность ревью:
- Оставить, если файл все еще поддерживает живой путь.
- Объединить, если он дублирует логику, которая уже есть в другом месте.
- Архивировать, если он нужен для справки, но не для активных путей.
- Удалить, если его никто не вызывает и за него никто не отвечает.
Пробелы в ответственности важнее, чем многие признают. Если никто не может объяснить, зачем существует файл, считайте это предупреждающим знаком. Но при этом не удаляйте код только потому, что ушел его автор. Сначала проверьте поведение в production.
Удаляйте небольшими партиями. Пяти файлов обычно достаточно за один проход. Выложите изменение, день-два следите за error tracking и логами, а потом двигайтесь дальше.
Такой темп кажется медленным, но он лучше, чем одна большая зачистка, которая ломает забытый рабочий процесс. Команды, которые выстраивают lean AI-driven engineering, обычно чувствуют пользу раньше, потому что небольшие кучи лишнего кода очень быстро превращаются в путаницу.
Реалистичный пример из растущей продуктовой команды
Небольшой SaaS-стартап быстро добавлял AI-функции. Сначала появился prompt wrapper для ответов поддержки. Потом команда добавила резервную обертку для второй модели. Через месяц другой инженер написал retry wrapper внутри background worker, чтобы сбои не блокировали приложение.
Через шесть месяцев в репозитории было три файла, которые выглядели по-разному, но делали почти одно и то же. Каждый собирал prompt, вызывал модель, логировал использование токенов и возвращал текст. Один жил в web app, один — в worker, а один — в старой папке экспериментов, которая все еще шла вместе с production-кодом.
Сложность была не технической. Никто не мог сказать, какая именно обертка все еще используется в production.
Тогда команда перестала гадать. Для каждого файла они проверили три сигнала: когда он менялся в последний раз, как часто его вызывают другие файлы и есть ли у него один понятный владелец. Так у них появился практический способ измерять рост мертвого кода вместо споров на памяти.
Их заметки были простыми:
prompt_wrapper.ts: менялся на прошлой неделе, 41 точка вызова, понятный владелецfallback_prompt.ts: менялся 4 месяца назад, 3 точки вызова, владельца нетsafe_ai_client.ts: менялся 6 месяцев назад, 1 точка вызова, бывший владелец ушел
Самый старый файл не был автоматически первым кандидатом на удаление. Тихие файлы были такими кандидатами. У одной обертки все еще было много точек вызова, поэтому команда оставила ее в покое. Два других файла почти не были связаны с остальной частью приложения, и инженеры отследили последних вызывающих их до retry-путей, которые уже не обрабатывали живой трафик.
Сначала они удалили файл с самым низким score и несколько дней следили за логами, алертами и обращениями в поддержку. Ничего не изменилось. Потом они удалили вторую тихую обертку и оставили небольшой rollback-патч на случай, если что-то скрытое все же ускользнуло.
Польза оказалась больше, чем просто несколько сотен удаленных строк. Новые инженеры перестали открывать три похожих файла и спрашивать, какой из них важен. Ревью ускорилось, потому что люди перестали сравнивать дублирующуюся логику. Обычно именно в этом и состоит реальная выгода очистки мертвого кода в AI-репозиториях: меньше шума, меньше неверных развилок и лучшее решение, когда появляется новый helper, agent или prompt layer.
Ошибки, которые приводят к плохим удалениям
Команды обычно удаляют не тот код по одной причине: они принимают слабые сигналы за доказательство. Файл с низким количеством вызовов все еще может защищать retry для биллинга, compliance export или recovery-путь, который запускается только когда что-то ломается. Редкое использование не значит отсутствие использования.
В AI-heavy репозиториях это становится еще хуже. Код, созданный агентами, часто делает обертки, адаптеры и вспомогательные файлы, которые выглядят тихими в обычном трафике приложения. Если считать только прямые вызовы, можно пропустить импорты, созданные на этапе сборки, background jobs или generated clients.
Еще одна частая ошибка — доверять только product traffic и игнорировать все остальное. Cron jobs, admin tools, migration scripts и команды только для поддержки могут простаивать неделями, а потом быть очень важными в один напряженный день. Удалите такой путь — и можете не заметить этого, пока не сломается пакет возвратов или не перестанет работать срочное исправление на on-call.
Shared helpers тоже могут обмануть. Помощник может выглядеть неиспользуемым в основной кодовой базе, хотя generated code все еще тянет его внутрь. Инструменты поиска часто не видят эту связь, когда импорты приходят из шаблонов или генерации кода. Прежде чем удалять shared helper, проверьте output генератора, артефакты сборки и любые внутренние SDK, которые от него зависят.
Небольшие партии лучше, чем массовые зачистки. Когда команда удаляет пятьдесят файлов сразу, ревью становится поверхностным, а история обвинений — запутанной. Позже никто не знает, был ли какой-то файл действительно мертвым или его просто зацепило во время чистки. Это замедляет откат и усложняет будущую очистку.
Более безопасное ревью обычно охватывает четыре зоны: расписанные задания, админ-панели, внутренние скрипты и fallback-пути. Если код касается хотя бы одной из них, замедлитесь. Также проверьте generated code, шаблоны и build output на скрытые импорты, прежде чем что-то удалять.
Одна продуктовая команда убедилась в этом на практике, когда удалила модуль экспорта с «низким использованием» перед закрытием квартала. Обычный трафик его никогда не трогал. Финансы использовали его раз в месяц. Удаление выглядело чисто, тесты прошли, а потом отчетный прогон сломался именно тогда, когда он был нужен.
Низкая активность — это подсказка, а не приговор. Хорошая очистка — это не столько скорость, сколько удаление кода, от которого никто не зависит, включая редкие пути, о которых вспоминают только тогда, когда они нужны.
Быстрые проверки перед удалением
Старый файл выглядит безобидно, пока его не использует какой-нибудь скрытый job. AI-heavy репозитории делают это хуже, потому что generated code, старые эксперименты и вспомогательные скрипты накапливаются быстрее, чем люди успевают их проверять. Прежде чем что-то удалять, попробуйте доказать, что это никому не нужно.
Начните с использования вне основного приложения. Проверьте cron jobs, CI-шаги, deploy-скрипты, загрузки данных, support-утилиты и admin-команды. Файл может не вызываться в продуктовом коде, но при этом запускаться каждую ночь в 2:00. Такая неожиданность стоит дороже, чем выгода от очистки.
Затем найдите человеческого владельца. Один человек должен уметь простыми словами объяснить, зачем файл существует и что сломается без него. Если никто не знает, файл поднимается выше в списке очистки. Если кто-то говорит: «ну, он может пригодиться», попросите реальный пример и примерное время, когда он последний раз запускался.
Хорошо работает короткая проверка:
- Спрячьте или переименуйте файл в ветке и запустите тестовый набор.
- Запустите задания, которые тесты часто пропускают, например migrations, exports и support-скрипты.
- Следите за логами и алертами полный цикл, а не только один локальный прогон.
- Подготовьте rollback, который возвращает старое состояние одним коммитом или одним revert.
Одних тестов недостаточно. У многих команд слабое покрытие setup-скриптов, внутренних инструментов и support-потоков. В быстро меняющихся AI-командах этот пробел становится еще больше, потому что люди быстро генерируют хелперы и почти не пишут для них глубокие тесты.
Поэтому rollback так важен. Очистку легче проводить, когда команда знает, что неудачное удаление можно отменить за минуты. Чистый revert снижает стресс и помогает принимать более хорошие решения.
Как не дать мусору вернуться снова
Беспорядок в репозитории редко появляется из-за одного плохого разработчика. Он растет потому, что маленькие временные решения так и не убирают. В AI-репозиториях это происходит еще быстрее. Команды пробуют prompt chain, оставляют старую обертку, копируют helper для одной модели, а через неделю забывают все три.
Несколько простых правил останавливают большую часть этого роста. Давайте каждому эксперименту дату окончания. Добавляйте метку владельца, когда команда создает новую папку. На ревью задавайте один вопрос о дубликатах: «У нас уже есть wrapper или helper, который делает то же самое?» И ведите cleanup debt рядом с продуктовой работой, а не прячьте его в бэклог, который никто не открывает.
Дата окончания важнее, чем кажется. AI-работа создает много короткоживущего кода: evaluation-скрипты, одноразовые agents, временные RAG-loaders, fallback prompts и привязки под конкретную модель. Если никто не ставит дату проверки, этот код начинает казаться постоянным. Хорошо работает простое правило: проверяйте эксперименты через 14 или 30 дней. Оставляйте, правильно объединяйте или удаляйте их.
Метки владельца решают другую проблему. Старые папки становятся рискованными, когда никто не знает, кто может сказать: «Да, это еще важно» или «Нет, мы заменили это в марте». Не нужен тяжелый процесс. Короткой заметки в метаданных папки, документации репозитория или командных документах достаточно, если люди поддерживают ее в актуальном состоянии.
Code review — лучшее место, чтобы ловить дублирующие обертки. AI-инструменты часто создают почти полные копии одного и того же client, parser или retry-логики. Ревьюеры должны воспринимать такие копии как стоимость поддержки, а не как безобидную экономию времени. Одна лишняя обертка кажется мелочью. Пятнадцать оберток позже никто уже не доверяет тому, что безопасно менять.
Cleanup debt тоже нужно иметь в реальном плане работ. Если команда отслеживает только фичи, беспорядок всегда проигрывает. Добавляйте небольшую задачу по очистке рядом с продуктовой работой в каждый спринт. Такая привычка полезнее, чем большая квартальная зачистка, потому что она не дает куче мусора вообще образоваться.
Что делать дальше
Начните с одной папки, которая уже замедляет ревью, например со старых prompt chains, вспомогательных скриптов или частично замененного service layer. Небольшой тест легче оценить, и он дает команде более безопасный способ отслеживать мертвый код до того, как трогать что-то большее.
Запускайте тот же score каждый месяц. Один отчет говорит очень мало. Два или три отчета показывают тенденцию. Если возраст файлов продолжает расти, количество вызовов остается низким, а владельца никто не называет, эта папка постепенно превращается в мусор.
Держите score простым. Возраста файла, количества вызовов и пробелов в ответственности достаточно для первого прохода. Вам не нужна идеальная модель. Вам нужна повторяемая модель, которая помогает людям согласиться, что заслуживает более внимательной проверки.
Также полезно держать результаты простыми. Оставляйте файлы, которые все еще поддерживают живой путь или текущий workflow. Объединяйте файлы, которые распыляют внимание, но делают одну и ту же работу. Архивируйте код, который еще может помочь как справка, но должен уйти из активного дерева. Удаляйте код, за который никто не отвечает, который никто не вызывает и от которого не зависит свежая работа.
Такие ярлыки снимают лишние споры. Они не дают очистке превращаться в битву мнений. Если файл попал в серую зону, отметьте его для короткой проверки вместо того, чтобы форсировать удаление.
Такой подход особенно хорошо работает для AI-команд, потому что эксперименты создают лишний код быстрее, чем большинство людей ожидает. Ежемесячный проход по очистке делает этот рост заметным и показывает пробелы в ответственности до того, как они станут серьезной проблемой.
Если вашей команде нужен второй взгляд, Oleg Sotnikov на oleg.is помогает стартапам и небольшим компаниям оценивать архитектуру, ответственность и безопасные планы очистки. Иногда внешний взгляд CTO — самый быстрый способ отделить реальный риск от шума в репозитории.
Часто задаваемые вопросы
Что считается мертвым кодом в AI-репозитории?
Мертвый код — это код, который больше не нужен ни одному живому пути, задаче, скрипту или члену команды. В AI-репозитории это часто старые prompt-обвязки, копированные хелперы, незавершенные эксперименты или замененные model clients, которые выглядят полезно, но уже ничего не делают.
Почему мертвый код сильнее мешает в AI-heavy репозиториях?
Потому что AI-инструменты создают код быстрее, чем люди успевают его проверять. Из-за этого лишние файлы засоряют поиск, путают ревью и заставляют инженеров сомневаться, какая версия еще важна.
Какие сигналы стоит проверять в первую очередь?
Начните с возраста файла, реального использования и ответственности. Риск растет, если файл не трогали месяцами, логи и тесты почти его не затрагивают, а никто не может объяснить, зачем он существует.
Как оценивать файлы для очистки?
Используйте простой, а не сложный score. Добавляйте баллы за возраст и отсутствие владельца, а затем вычитайте их за использование в тестах и в runtime, чтобы самые высокие значения показывали, что смотреть сначала.
Означает ли высокий cleanup score, что файл можно сразу удалить?
Нет, одно число само по себе не доказывает, что файл безопасно удалить. Считайте высокий score сигналом к проверке, а потом подтвердите импорты, jobs, логи, тесты и скрытые настройки, прежде чем что-то удалять.
Сколько файлов стоит проверять за один проход очистки?
Держите batch небольшим. Пяти файлов или топ-20 кандидатов обычно достаточно, чтобы продвинуться вперед и не превратить очистку в рискованную массовую зачистку.
Как проверить, что тихий файл все еще важен?
Сначала проверьте все вне основного приложения. Посмотрите cron jobs, admin tools, support-скрипты, migrations, generator output и build steps, а затем спрячьте файл в ветке и проверьте, что ломается в тестах и логах.
Какой код чаще всего удаляют по ошибке?
Команды чаще всего ошибочно удаляют редкие пути, которые запускаются только при сбоях или ежемесячной работе, например billing retries, exports и recovery-скрипты. Shared helpers тоже вводят в заблуждение, когда generated code или internal SDK по-прежнему их используют.
Когда лучше архивировать код, а не удалять его?
Удаляйте, когда файл никто не вызывает, у него нет владельца и от него не зависит свежая работа. Архивируйте, когда код нужен как справка, но не должен оставаться в активном дереве.
Как не допустить повторного накопления мертвого кода?
Давайте экспериментам дату завершения, назначайте владельца при создании новых папок и спрашивайте на ревью, не существует ли уже такой же helper или wrapper. Небольшая cleanup-задача в каждом спринте не дает мусору снова накапливаться.