Уйдёт лидер — до 97% файлов без автора: считаем truck factor по git
Всем привет, меня зовут Сергей Прощаев, я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech & E‑commerce и преподаю на курсах разработки и архитектуры в ОТУС.
В этой статье расскажу, почему руководитель команды обычно узнаёт о концентрации знаний в день заявления об уходе, как посчитать её заранее по истории git и что в этом расчёте меняют коммиты, сделанные вместе с агентом.
Знакомая картина. Сильный разработчик кладёт на стол заявление, впереди две недели отработки. Руководитель открывает файл владельцев кода: модулей у человека три, у каждого записано ещё по два ответственных, всё выглядит спокойно.
Через месяц в одном из модулей падает интеграция со сторонним API, и выясняется, что два «ответственных» видели этот код только в списке изменённых файлов на ревью. Команда неделю разбирается в проблеме по логам и комментариям в коде.
Обычное объяснение звучит так: «не успели передать дела». Я с ним не согласен. Две недели здесь ни при чём: знания собирались в одной голове годами, а измерить это можно было в любой день, просто никто не смотрел.
Что я посчитал
Чтобы не спорить на ощущениях, я взял метод из работы Авелино и соавторов, представленной на конференции ICPC в 2016 году. Они предложили считать truck factor, то есть bus factor, автоматически по истории git.
Для каждого файла считается степень авторства разработчика (DOA): создал ли он файл, сколько раз менял и сколько правок внесли другие. Величина нормируется по максимуму для файла, и автором считается тот, у кого нормированный DOA выше 0,75, а абсолютный не ниже 3,293.
Авторов у файла может быть несколько. Затем по одному исключают автора с наибольшим числом файлов, пока оставшиеся авторы покрывают хотя бы половину файлов. Число исключённых разработчиков и есть оценка truck factor по этой модели.
Ядро расчёта занимает несколько строк:
import math
def doa(is_first_author: bool, own_changes: int, other_changes: int) -> float:
# Avelino et al., ICPC 2016: первое авторство весит больше всего,
# свои правки добавляют, чужие правки медленно отнимают
return (3.293 + 1.098 * int(is_first_author) + 0.164 * own_changes
- 0.321 * math.log1p(other_changes))
В исходной работе 65% из 133 популярных проектов GitHub имели truck factor не больше двух. Я применил эту методику к шести открытым проектам на JVM и Python по зафиксированным коммитам от 29 сентября до 23 октября 2026 года. Это не полное воспроизведение: файлы кода я отбирал по расширению и без каталогов вроде vendor и build, а не через Linguist, как авторы.
Кроме того, я добавил две величины, которых в исходной работе нет. «Ничьё сейчас» — доля файлов, у которых по расчёту не осталось ни одного автора, коммитившего за последний год. «Ничьё без лидера» — та же доля, если из активных уйдёт один человек с наибольшим числом файлов.
Авторство считается по всей истории, а «активные» — это авторы с коммитами за 365 дней до зафиксированного коммита, DOA по одним свежим правкам я не пересчитывал. Обе метрики оценивают авторство по истории правок, а не знание кода. Их ограничения разберу в конце.
|
Проект |
Файлов кода |
Truck factor по всей истории |
Truck factor среди активных |
Ничьё сейчас |
Ничьё без лидера |
|---|---|---|---|---|---|
|
fastapi |
1220 |
1 |
1 |
3,6% |
78,6% |
|
javalin |
372 |
1 |
1 |
16,4% |
97,0% |
|
kotlinx.coroutines |
1105 |
2 |
1 |
29,7% |
73,2% |
|
ktor |
2631 |
4 |
1 |
26,4% |
62,6% |
|
okhttp |
690 |
1 |
1 |
1,6% |
62,5% |
|
spring‑petclinic |
50 |
4 |
1 |
46,0% |
74,0% |
Открытый проект не равен команде в компании, об этом ниже. Но механика ошибок одна и та же, и шесть из них я разберу по порядку.
Перед схемой коротко о том, как файл становится ничьим. На схеме ниже путь от истории правок до вывода.
Главная мысль схемы: история git помнит авторов, но не знает, кто из них ещё в команде и кто на самом деле читал код, который принял от агента. Обе проверки руководителю приходится делать самому.
Ошибка 1. Считать устойчивость команды по всей истории
-
Симптом. Отчёт показывает у модуля четырёх авторов, и руководитель спокоен.
-
Неверное объяснение. «Раз авторов несколько, уход одного переживём».
-
Настоящая причина. Git помнит всех. В ktor и spring‑petclinic truck factor по всей истории равен четырём, а среди тех, кто коммитил за последний год, — единице. Остальные авторы больше не коммитят, но расчёт продолжает на них опираться.
-
Последствие. Риск недооценён ровно в тот момент, когда его можно было снять дёшево.
-
Исправление. Считать truck factor только по активным людям и смотреть на долю ничьих файлов. Я проверил, не держится ли вывод на выбранном окне в 12 месяцев: при окне в 6 и 24 месяца доля ничьих файлов в пяти проектах из шести меняется на 0,3–3,7 процентного пункта. Сильно сдвигается только маленький spring‑petclinic: 56% при окне в полгода и 30% при двух годах.
-
Когда возникает. В проектах, где команда успела смениться хотя бы наполовину.
Ошибка 2. Верить файлу владельцев кода
-
Симптом. У каждого модуля в файле владельцев записаны два‑три человека, ревью без них не проходит.
-
Неверное объяснение. «Владельцы назначены, значит, знания распределены».
-
Настоящая причина. Файл владельцев решает, кого звать на ревью, а обязательность одобрения задают правила защиты ветки. Ни то ни другое не говорит, кто знает код. Сам файл заполняют один раз при создании модуля и почти не обновляют. Совпадает ли владелец по файлу с автором по истории, проверяется за минуту: достаточно положить рядом два списка.
-
Последствие. Руководитель планирует уход человека по документу, который уже не отражает реальность.
-
Исправление. Раз в квартал сверять файл владельцев с картой авторства. Если расчёт не приписывает владельцу ни одного файла в модуле, это повод проверить, знает ли он модуль на деле: дать ему небольшую задачу там или разобрать с ним последний инцидент.
-
Когда возникает. Когда файл владельцев завели при запуске модуля, а состав с тех пор менялся.
Ошибка 3. Ревью одним и тем же человеком
-
Симптом. Любой PR в модуль одобряет один и тот же старший разработчик, потому что «он лучше всех знает этот код».
-
Неверное объяснение. «Ревью и есть передача знаний: все видят изменения».
-
Настоящая причина. Ревьюер не становится автором. В расчёте степени авторства одобрение вообще не участвует, и это честно: прочитать чужой дифф и уметь чинить модуль ночью — разные навыки. Ревью одним человеком к тому же закрепляет его роль единственного знатока.
-
Последствие. Модуль держится на одном человеке, хотя через него проходят все.
-
Исправление. Ротация в паре: второй ревьюер выбирается из тех, у кого в модуле нет файлов, первые ревью проходит вместе с автором и разбирает не только дифф, но и ограничения модуля, а следом получает там свою задачу. Я бы предложил начинать с модулей, где «Ничьё без лидера» выше половины, а не со всей кодовой базы сразу.
-
Когда возникает. В командах, где ревью назначается вручную и по привычке достаётся самому опытному.
Ошибка 4. Считать документацию страховкой
-
Симптом. После тревожного разговора команда пишет страницу в вики с описанием модуля, и тема закрыта.
-
Неверное объяснение. «Всё записано, новый человек прочитает».
-
Настоящая причина. Документация переносит описание, но не умение. Пока человек сам не поменял код и не довёл изменение до продакшена, он не знает, где в модуле острые углы. Поэтому в расчёте степень авторства растёт только от собственных правок.
-
Последствие. В день инцидента страница есть, а того, кто по ней что‑то делал, нет.
-
Исправление. Страница остаётся, но к ней добавляются задачи. Каждый квартал по одной небольшой задаче в чужом модуле на человека, с ревью от текущего автора. Мой вариант — брать для этого технический долг: он всё равно нужен, а риск ошибки невысокий.
-
Когда возникает. После разговора о рисках, когда хочется закрыть тему быстро и без перестройки планов.
Ошибка 5. Передавать дела за две недели отработки
-
Симптом. Заявление подано, уходящий проводит три созвона по своим модулям, запись лежит в облаке.
-
Неверное объяснение. «Главное — успеть выгрузить знания из головы».
-
Настоящая причина. Двух недель не хватает на то, что копилось годами. Таблица выше показывает масштаб: если завтра уйдёт самый крупный из активных авторов, без автора останется от 62,5 до 97% файлов проекта.
-
Последствие. Передача дел превращается в лекцию, а лекция быстро забывается.
-
Исправление. Готовиться к уходу до заявления. Карта ничьих файлов «если уйдёт лидер» считается заранее, и по ней видно, кому и какие задачи давать уже в этом квартале. Когда заявление всё‑таки придёт, две недели уйдут на остаток, а не на всё сразу.
-
Когда возникает. Всегда, когда о концентрации знаний вспоминают только в момент ухода.
Ошибка 6. Записывать код агента на автора коммита
-
Симптом. За год в модуль вошли десятки коммитов, сделанных вместе с агентом. Автором коммита везде числится человек, а на вопрос «почему здесь так» он отвечает «так предложил агент».
-
Неверное объяснение. «Человек принял изменение, значит, он его понимает».
-
Настоящая причина. Расчёт берёт из git поле Author, и правка с агентом засчитывается человеку, который в нём стоит. В ktor за последний год 43 коммита с агентом затронули 198 файлов, и в 128 из них расчёт считает автором этого человека. Агента расчёт распознаёт по двум признакам: по трейлеру, служебной строке вида
Co-authored-by:в конце сообщения коммита, или по имени и адресу самого автора коммита. Это эвристика: агент без таких следов останется незамеченным, а служебную учётку правило может принять за агента. Код, принятый из чата без следов, неотличим от написанного руками. -
Последствие. Карта авторства показывает человека там, где он, возможно, только принял дифф. Насколько это сдвигает цифры, я проверил пересчётом: в нём ни один коммит с распознанным агентом за всю историю, а не только за год, не засчитывается человеку ни как создание файла, ни как правка, но из истории не удаляется и остаётся чужой правкой файла. Состав активных я оставил прежним. Сценарий нарочно жёсткий: даже правку, которую человек переписал сам, он не считает человеческой. Это проверка чувствительности, а не оценка доли кода, написанного агентом. Truck factor не изменился ни в одном проекте, ни по всей истории, ни среди активных. А вот ничьих файлов в ktor стало 29,7% вместо 26,4%, и без лидера 65,5% вместо 62,6%, в javalin 16,7% вместо 16,4%. Агент уже прячет часть ничьих файлов: в ktor больше трёх процентных пунктов, и это только те случаи, которые удалось распознать по метаданным git.
-
Исправление. Договориться в команде подписывать коммиты с агентом трейлером и считать такие правки отдельно. Для файлов, которые за год затронули коммиты с агентом, второй ревьюер обязателен, а автор изменения на ревью объясняет решение своими словами.
-
Когда возникает. В командах, где агентом пользуются давно, а правила ревью остались прежними.
История: проект с одним мейнтейнером
Самая известная история про проект, который держался на одном человеке, случилась с XZ Utils, библиотекой сжатия, которая стоит почти в каждом дистрибутиве Linux. В июне 2022 года в рассылке проекта, в ветке про XZ for Java, один из участников написал, что прогресса не будет, пока не появится новый мейнтейнер, и отдельно упрекнул XZ for C в редких коммитах.
Мейнтейнер Лассе Коллин ответил, что его возможности сильно ограничены из‑за долгих проблем со здоровьем, что это неоплачиваемый проект и что он уже немного работал с Jia Tan, у которого в будущем может быть роль больше.
Роль действительно выросла. В 2024 году в архивах релизов 5.6.0 и 5.6.1, собранных и подписанных Jia Tan, нашли бэкдор, уязвимость получила номер CVE-2024-3094. Truck factor проекта я здесь не считал, это не пример цифры.
Для руководителя это история не про личные качества мейнтейнера, а про сочетание трёх вещей: ресурсов на сопровождение мало, полномочия сосредоточены у одного‑двух людей, а независимая проверка критичных изменений и релизных архивов не поймала подмену до релиза.
Механика та же и в команде, где все добросовестны: когда всё держится на одном, преемника выбирают не по плану, а по обстоятельствам, а проверка изменений нужна при любой репутации.
Что делать: план на квартал
Ниже на схеме исправления из шести ошибок собраны в один цикл. Он повторяется раз в квартал.
Что важно на схеме: исправления запускаются не по поводу ухода человека, а по графику, и каждое следующее начинается с цифры, а не с ощущения.
Сводная таблица
|
Ошибка |
Признак |
Что проверить |
|---|---|---|
|
Устойчивость по всей истории |
Авторов много, но часть давно не коммитит |
Truck factor только по активным |
|
Вера файлу владельцев |
Владелец без своих файлов в модуле |
Сверка с картой авторства |
|
Ревью одним человеком |
Все PR модуля одобряет один |
Доля ревью у второго ревьюера |
|
Документация как страховка |
Вики есть, задач в модуле у других нет |
Число людей с правками за квартал |
|
Передача дел за две недели |
Созвоны вместо задач |
Карта «если уйдёт лидер» заранее |
|
Код агента на авторе коммита |
Автор не может объяснить решение |
Файлы, затронутые коммитами с агентом |
Чек‑лист
1. Посчитать truck factor и долю ничьих файлов по активным авторам.
2. Посчитать ту же долю на случай ухода самого крупного автора.
3. Сверить файл владельцев с картой авторства.
4. Назначить второго ревьюера в модули, где без лидера ничьей станет больше половины файлов.
5. Дать каждому по задаче в чужом модуле на квартал.
6. Ввести трейлер для коммитов с агентом и считать их отдельно.
7. Повторить замер через квартал и сравнить.
Где это не сработает
Авторство по git — приближение. Человек мог разобраться в модуле на дежурствах и ни разу не менять код, и расчёт его не увидит. «Активный» значит коммитил в репозиторий за год, а не работает в команде сегодня.
Считаются файлы, а не строки, и большой модуль весит столько же, сколько маленький. Псевдонимы склеиваются по адресу и по имени с отличием в одну букву, и на похожих именах склейка может ошибиться.
В открытых проектах много разовых участников, а в команде компании ушедший часто сидит в соседнем отделе и отвечает в чате. Поэтому цифры из таблицы не стоит переносить на свою команду напрямую: их нужно посчитать на своей истории.
Вывод
Эта группа ошибок проверяет навык руководителя видеть риск в цифрах до того, как он стал инцидентом. Truck factor не меняется от совещаний и страниц в вики: он меняется, когда другие люди правят код в чужих модулях.
А с агентами появилась новая слепая зона: git хранит автора коммита, но не знает, кто на деле написал код и понял ли его автор, поэтому понимание надо проверять отдельно.
Ссылка на мой репозиторий с экспериментом: https://github.com/sproshchaev/bus‑factor‑from‑git
Начать стоит с expected.txt: там все четыре таблицы, на которые опирается статья, включая проверку при окне активности 6 и 24 месяца и пересчёт без правок с агентом. Как считается авторство и truck factor, видно в bus_factor.py, выгрузки истории шести проектов лежат в data/, а пересчёт со сверкой запускается командой ./run.sh.
Источники:

Если критичные знания сосредоточены у нескольких разработчиков, а распределение ответственности существует только на бумаге, важно не просто зафиксировать риски, но и изменить подход к управлению командой.
Разобраться в управлении знаниями и командой помогут открытые уроки:
-
5 ноября, 20:00. «Knowledge‑centered service и подходы к структурированию баз знаний». Записаться
-
9 ноября, 20:00. «Качество без микроменеджмента: что должен контролировать CTO». Записаться
Больше актуальных материалов по разработке, управлению и ИТ-архитектуре — в дайджесте ноября.
Важное напоминание
Автор: sproshchaev

