Процессы code review обычно начинаются как «контроль качества», а заканчиваются как «война эго». По мере роста команды проявляются две ловушки: PR'ы висят неделями без внимания, или каждый комментарий воспринимается как личная критика. Обе проблемы имеют одну корень — отсутствие измеряемых правил. За 8 лет работы в Roibase с командой из 15+ человек разных специальностей мы научились простому: пока вы не положите культуру review на числовые метрики, субъективное суждение неизбежно. Когда time-to-review, плотность комментариев и размер PR становятся системой, качество растёт, а конфликты падают.
Скорость Review: SLA Time-to-Review
Каждый PR имеет жизненный цикл. Время от открытия до первого комментария — time-to-first-review — первый индикатор дисциплины команды. В Roibase мы установили максимум 4 часа (в рабочее время). Почему 4 часа? Это сладкое пятно между сохранением блоков deep work и ускорением цикла обратной связи в асинхронной модели.
Правило: первый reviewer должен посмотреть PR в течение 4 часов после открытия. Механизм enforcement — не Slack-уведомление, а GitHub Actions workflow. При открытии PR автоматически ставится тег, через 4 часа назначенному reviewer'у приходит Slack-упоминание. Это мягкое напоминание, которое исключает забытые review'ы.
Метрика time-to-merge ещё критичнее. Время от открытия PR до merge в main ветку — например, для backend-изменений: максимум 24 часа. Для frontend: 48 часов. Почему разница? Backend-merge'ы обычно требуют меньше визуальной проверки, могут быть задеплоены за feature flag. Frontend требует design QA и кросс-браузерных тестов.
Метрика-дашборд: Linear Integration
Мы интегрируем Linear с GitHub — каждый PR автоматически связывается с Linear-тикетом. Статус тикета обновляется в соответствии с PR lifecycle. В конце спринта смотрим метрику: средний time-to-merge. Если команда превышает 36 часов, на ретроспективе это проблема для обсуждения — обычно это PR size или нагрузка на reviewer'ов.
Размер PR: Правило 400 строк
Большие PR'ы нельзя review'ить. Это наиболее частый консенсус в индустрии, но редко превращается в измеряемое правило. Стандарт Roibase: максимум 400 строк изменений (сумма additions + deletions). Откуда это число? Это объем кода, который reviewer может логично держать в голове при 30-минутном focused review.
Чтобы enforce'ить правило, используем GitHub branch protection: PR с более чем 400 строк получает автоматический label «needs-split» и не может быть смёрджен. Есть исключения — обновления зависимостей, migration-скрипты. Но даже они требуют manual override с обоснованием в комментарии GitHub.
Как делать большие рефакторинги? Stacked PR'ы. Первый PR: изменение интерфейса, второй: реализация, третий: удаление старого кода. Каждый под 400 строк, каждый можно review'ить отдельно. Это медленнее? Да. Риск merge conflict'ов выше? Немного. Но quality review'я улучшается кратно — reviewer может действительно понять каждое изменение.
# GitHub Actions — PR size check
name: PR Size Check
on: pull_request
jobs:
size_check:
runs-on: ubuntu-latest
steps:
- name: Check PR size
run: |
ADDITIONS=$(jq '.pull_request.additions' "$GITHUB_EVENT_PATH")
DELETIONS=$(jq '.pull_request.deletions' "$GITHUB_EVENT_PATH")
TOTAL=$((ADDITIONS + DELETIONS))
if [ $TOTAL -gt 400 ]; then
echo "PR too large: $TOTAL lines"
gh pr edit --add-label needs-split
exit 1
fi
Плотность комментариев: Граница нитпикинга
Не все комментарии равны. «Это можно рефакторить» и «Здесь может быть null pointer exception» — разные по критичности. В шаблоне review'а Roibase категории комментариев обязательны:
| Категория | Tag | Пример |
|---|---|---|
| Blocker | 🔴 BLOCKER | Уязвимость, crash при runtime |
| Major | 🟠 MAJOR | Регрессия производительности, ошибка логики |
| Minor | 🟡 MINOR | Соглашение о именовании, покрытие тестами |
| Nitpick | 🔵 NITPICK | Вопрос вкуса, субъективно |
Правило: нитпик не более 30%. Если в PR 10 комментариев, не больше 3 нитпик'ов, остальное — blocker/major/minor. Почему? Потому что review с преобладанием нитпик'ов снижает мотивацию автора, reviewer'а воспринимают как излишне придирчивого.
Метрика плотности комментариев: среднее число комментариев на PR. В Roibase это 3-5. Свыше 10 — обычно сигнал, что PR нужно разбить. Ноль комментариев — сигнал rubber stamp review.
Использование шаблона
Каждый reviewer начинает с шаблона GitHub PR:
## Чек-лист Review
- [ ] Логика кода верна?
- [ ] Покрытие тестами выше 80%?
- [ ] Есть breaking change? (CHANGELOG обновлён?)
- [ ] Измерено влияние на производительность? (benchmarks/)
## Комментарии
**🔴 BLOCKER:**
-
**🟠 MAJOR:**
-
**🟡 MINOR:**
-
**🔵 NITPICK:**
-
Этот шаблон делает две вещи: заставляет reviewer'а категоризировать, позволяет author'у быстро увидеть, какие комментарии критичны.
Асинхронный Review: Ловушка синхронных встреч
Code review не должен происходить на синхронных встречах. В Roibase нет концепции «review call» — все review'ы асинхронные, через GitHub. Почему? Команда работает в 3 разных timezone'ах, сохранение блоков deep work критично.
Дисциплина асинхронного review: reviewer смотрит PR в своё время глубокой концентрации (обычно 09:00-12:00). Пишет комментарии, approve или request changes. Author получает уведомление (в своём календаре), вносит изменения, re-request'ит review. Цикл обычно повторяется 2-3 раза.
Исключение: review deadlock — author и reviewer не договорились за 3 итерации, тогда открывается 15-минутный sync call. Но это происходит 5-6 раз в год, это исключение. Фирменный стиль Roibase, созданный в процессе брендирования, отражает эту культуру async-first — documentation-first, meeting-last.
Ownership vs. Gatekeeping
Целью code review является quality assurance, но побочный эффект не должен быть gatekeeping. В Roibase каждый PR требует минимум 1, максимум 2 reviewer'ов. Почему максимум 2? Потому что ожидание 3+ approval'ов имеет временную стоимость больше, чем выигрыш в quality.
Выбор reviewer'а не автоматический — выбирает author. Правило: минимум один из code owners (из CODEOWNERS файла), второй — кто угодно. Этот подход держит ownership в author'е. Вопрос «кто должен approve?» — ответственность author'а, не лидера.
Файл CODEOWNERS выглядит так:
# Backend
/backend/ @backend-team
/api/ @backend-team
# Frontend
/web/ @frontend-team
/mobile/ @mobile-team
# Infrastructure
/terraform/ @devops-team
/.github/ @devops-team
Каждое изменение файла должно быть review'но кем-то из соответствующей team'ы — но author выбирает конкретного человека.
Ретроспектива: Метрики Review
В конце каждого спринта (каждые 2 недели) смотрим на метрики review. Linear дашборд показывает:
- Средний time-to-merge (цель: 36 часов)
- Распределение размера PR (цель: 90% под 400 строк)
- Плотность комментариев (цель: 3-5 на PR)
- Доля нитпик'ов (цель: <30%)
- Review bottleneck (кто чаще всего ждёт review?)
Эти числа обсуждаются на ретроспективе, но без личных обвинений. Вместо «Алёша медленно review'ит» звучит: «Backend PR'ы ждут в среднем 48 часов, нужно ли расширить пул reviewer'ов?»
Превратить культуру code review из личных суждений в системную дисциплину несложно — нужны только измеряемые правила. SLA time-to-review, правило 400 строк, категории комментариев, async-first подход — это конкретные инструменты, которые 8 лет помогали Roibase сохранять качество при росте команды. Если ваши review'ы всё ещё работают «интуитивно» и «в зависимости от ситуации» — положите цифры, систематизируйте. Качество вырастет, конфликты упадут.