Code review, сведённый к ритуалу "ждём одобрения senior разработчика", не обеспечивает контроль качества — только растрачивает время. Когда процесс review не измеряется — нет отслеживания time-to-review, плотности комментариев, размера PR — процесс становится узким местом, основанным на личных предпочтениях. В Roibase за 8 лет мы применяем систему с измеримыми метриками review: одобрение или открытый вопрос в течение 24 часов, PR свыше 300 строк отклоняются, плотность комментариев отслеживается на sprint retro.
Измеримые основы культуры review
Выход из ловушки "senior одобрит — и готово" — связать процесс с конкретными критериями. Time-to-review — время от открытия PR до первого комментария или одобрения — это самый честный индикатор дисциплины команды. В Roibase это 24 часа максимум: PR открыт, за 24 часа либо review завершён, либо пришёл уточняющий вопрос ("Можешь объяснить эти три момента?"). 48 часов молчания недопустимо — это основное правило async workflow.
Comment density — отношение числа комментариев к количеству изменённых строк — показывает глубину review. Слишком низкий показатель (менее 0,01) означает поверхностный просмотр, слишком высокий (свыше 0,15) указывает на чрезмерную сложность PR или плохое планирование scope. Оптимальный диапазон: 0,03–0,08 — то есть на PR из 300 строк приходится 9–24 комментария. Эту цифру отслеживают в конце спринта, можно сделать вывод: "в этом спринте глубина review упала".
Правило размера PR простое и жёсткое: свыше 300 строк изменений в одну PR не влезает. Исключение: обновление зависимостей или автогенерируемая миграция. Это правило поддерживается автоматически — бот оставит комментарий на PR из 350 строк: "Превышен лимит размера, раздели на несколько." Крупная фича разбивается на три PR: backend API + интеграция frontend + полировка UI. Каждая PR должна быть review-независима и готова к отдельному merge.
Асинхронный workflow review: без синхронных собраний
Синхронное совещание по review — "давайте сейчас 30 минут посмотрим код" — это ошибка time-boxing. Review делается асинхронно: рецензент в своём блоке глубокой работы изучает PR, оставляет inline комментарии, открывает threads. Автор в своём блоке отвечает. Синхронный пинг в Slack — "смотришь мою PR сейчас?" — запрещён.
Запрос на review осуществляется через tag в GitHub: /cc @reviewer или автоматически через файл CODEOWNERS. Рецензент в течение 24 часов либо одобрит, либо спросит. Если вопрос, автор отвечает в течение 12 часов или добавляет коммит. Второй раунд review завершается за 12 часов. Общее время — не свыше 48 часов, это целевой цикл.
Inline comment threads получают статус resolved или переносятся в issue с тегом "later". Размытое "обсудим потом" недопустимо — либо решается сейчас, либо становится задачей в backlog, PR merge-ится. Blocker review ясен: security bug, breaking change API, регрессия производительности. Обсуждение стиля кода не является blocker — линтер уже есть, вопросы стиля закрываются "resolve without change".
Review bot: автоматизация, сфокусированность на главном
Автоматические проверки в CI pipeline снижают нагрузку на manual review: линтер (ESLint, Prettier), покрытие тестами diff (новый код ниже 80% — отклонение), анализ bundle size (+50KB — алерт), security scan (npm audit). Без зелёного статуса check'ов PR даже не может выйти из draft.
Блокирующие check'и: если в commit message есть "TODO" или "FIXME" по regex — PR отклоняется. Если изменился endpoint (@app.route decorator) — обновление API документации должно быть в той же PR, иначе bot блокирует. Эти правила перенаправляют manual review на семантическую глубину: правильна ли бизнес-логика, хватает ли обработки edge case'ов, полны ли тест-сценарии.
Категоризация комментариев: nit, question, blocker
Каждый комментарий в review классифицируется — рецензент добавляет тег. nit: предпочтение, не блокирует merge ("имя переменной могло быть яснее"). question: не понял, объясни ("какой edge case у этого regex?"). blocker: нельзя merge, требуется исправление ("этот null check отсутствует, в production упадёт").
Nit-комментарии закрываются "resolve without change" — автор говорит "окей, но в этой PR не менять, в следующий рефакторинг", рецензент одобрит. Question разбираются в thread, достаточное объяснение — resolved. Blocker требует ещё одного коммита, пока blocker не разрешён — кнопку merge нажать нельзя (GitHub branch protection rule это форсирует).
Метрика comment density разделяет категории: если blocker'ов свыше 20% — PR scope плохо спланирована, если nit'ов свыше 60% — review поверхностный, сначала отрегулируй lint конфиг. Идеальное распределение: 15% blocker, 50% question, 35% nit. На sprint retro эти доли обсуждаются: "Blocker'ов стало больше, значит, фаза планирования PR ослабла".
Место метрик review в sprint retrospective
После каждого спринта открывается review dashboard: среднее время до review, распределение по размерам PR, гистограмма плотности комментариев, файлы с максимальным числом ревизий, нагрузка на рецензентов (у кого скопилось PR). Эти метрики превращают расплывчатую "качество растёт ли" в конкретные цифры.
Если time-to-review превышает 36 часов (целевых 24) — анализ причин: перегружены ли рецензенты, PR открываются ли вне рабочего времени, переключение контекста? Если дисбаланс нагрузки (один разработчик сделал 12 review, другой 2) — ротация CODEOWNERS меняется. Если PR открываются вне часов — это сигнал, что async workflow нарушен: на фазе draft команда синхронизируется, PR ready открывается уже зрелой.
Если comment density упала — было 0,05, стало 0,02 — глубина review снизилась. Обычно это происходит в спринтах высокой velocity: все заняты фичами, review становится поверхностным. На retro вывод: "Velocity растёт, но quality review не должна падать — уменьшаем размер PR, ускоряем цикл." Без метрик этот вывод невозможен — все скажут "мы хорошо review'им", а данные покажут обратное.
Конфликтов нет, есть система
Личные конфликты в review возникают из-за отсутствия системы: что является blocker, что merge-able, кто когда review'ит — всё размыто. Если система ясна, конфликта нет: правило 24 часов нарушено — автор эскалирует (пинг team lead), 300 строк превышены — бот отклоняет, blocker не разрешён — merge невозможен по веткам. Все играют по одним правилам, личное мнение устранено.
Feedback в review адресован коду, не человеку: не "ты всегда так делаешь", а "в этом файле отсутствует null check, в других хэндлерах он есть". На retrospective имён нет: не "разработчик X не review'ит", а "time-to-review выше целевого, перераспределим нагрузку". Метрика создаёт объективность — все смотрят на цифры в dashboard, спор закончен.
Культура code review связана с брэндом команды так же, как и с инженерной дисциплиной: если команда говорит "мы review'им за 24 часа, PR не более 300 строк", эта дисциплина встраивается с первого дня. Новый разработчик видит правила в первом PR, адаптируется. Система не зависит от субъективности лидера — меняется лидер, метрики остаются.
Time-to-review 24 часа, размер PR 300 строк, плотность комментариев 0,03–0,08 — в вашей команде цифры могут быть другими. Главное — цифры должны быть, отслеживаться, обсуждаться на retro. Культура code review — это не субъективное одобрение senior разработчика, это дисциплинированный системный дизайн команды. Если вы review'ите без метрик, вы не контролируете качество, вы создаёте узкое место. Начните сейчас: измерьте time-to-review последних 10 PR и, если выше 48 часов, запустите анализ причин.