Двухэтапное ревью кода для более быстрых и безопасных отзывов команды
Двухэтапное ревью кода сначала проверяет логику и соответствие задаче, а затем — безопасность, обработку ошибок и уборку, чтобы ускорить ревью и уменьшить баги и шум.

Почему один проход ревью даёт сбои
Один длинный ревью просит от человека ответить на два разных вопроса одновременно. Работает ли код так, как нужно? И достаточно ли он безопасен и чист, чтобы его оставить?
Эти вопросы требуют разного внимания. Проверка логики нуждается в общей картине фичи, потоке данных и граничных сценариях. Проверка «уборки» более локальна: имена, мёртвый код, отсутствующие тесты, слабые сообщения об ошибках, пробелы в логах и мелкие проблемы с безопасностью. Когда ревьюверы пытаются делать и то, и другое одновременно, один тип комментариев прерывает другой.
Именно поэтому один длинный ревью часто превращается в кашу. Ревьювер начинает с проверки корректности суммы заказа, затем замечает слабое имя переменной, потом отсутствие проверки на null, и пытается вернуться к бизнес-правилу. После нескольких переключений исходная логика уже расплывчата. Ошибки проскальзывают, потому что ревьювер постоянно восстанавливает контекст вместо того, чтобы оставаться на одном вопросе.
Мелкие комментарии также заглушают важные. Серьёзная баг-задача может оказаться похоронена между заметками о форматировании или названиях тестов. Автор правит поверхностные вещи первым делом, в то время как глубокая проблема остаётся открытой дольше, чем нужно.
Сгенерированный код усугубляет это. ИИ может быстро производить много кода, и многое из этого выглядит правдоподобно на первый взгляд. Это создаёт ловушку: ревьюверы тратят энергию на просмотр объёма вместо проверки намерения. Они комментируют стиль, потому что стиль легко заметить, и при этом пропускают реальную проблему — например, проверку прав в неправильном месте или цикл повторной попытки, который может списать деньги дважды.
Двухэтапное ревью работает лучше, потому что отделяет «решает ли код задачу» от «насколько он безопасен и аккуратен для слияния». Команды обычно проверяют сгенерированный код быстрее, когда перестают смешивать эти задачи.
Это видно на примере небольших команд, активно использующих ИИ. Разработчик просит модель сгенерировать новый эндпоинт, получает 300 строк и открывает один большой ревью. Ревьювер находит три проблемы с именами, один дублирующий хелпер и отсутствующий комментарий. Позже кто-то обнаруживает, что эндпоинт принимает запросы без проверки владения аккаунтом. Баг был там всё это время. Процесс ревью позволил его пропустить.
Первый проход: проверка, решает ли код нужную задачу
Первый проход должен ответить на один вопрос: решает ли код нужную задачу?
Команды пропускают это чаще, чем думают. Они видят работающие тесты, аккуратное форматирование и понятные имена функций, затем упускают более важное. Код реализует неправильное правило или покрывает только happy path. В двухэтапном ревью первый проход защищает продуктовую логику.
Начните с основного потока. Читайте код от входа до результата так, как будто вы пользователь или владелец продукта. Что приходит на вход? Какие решения принимает код? Что выходит в конце? Если вы не можете объяснить этот поток несколькими простыми предложениями, код требует дополнительного просмотра.
Это особенно важно с кодом от ИИ. Сгенерированный код часто выглядит завершённым, но маленькие логические ошибки прячутся внутри аккуратной структуры. Начинать с комментариев по стилю — пустая трата времени, если сама фича неверна.
Практический первый проход обычно сводится к четырём проверкам:
- Изменение соответствует задаче, тикету или бизнес-правилу.
- Основной поток работает от начала до конца без странных объездов.
- Граничные случаи изменяют поведение так, как ожидается.
- Вопросы уборки остаются за пределами обзора, если они не мешают пониманию.
Граничные случаи особенно важны, когда они влияют на деньги, доступ, статус или время. Если скидка применяется только при сумме выше определённого порога, проверьте суммы чуть ниже и чуть выше этого порога. Если пользователь может отменить бронь только до дедлайна, проверьте, что происходит за минуту до и за минуту после. Эти случаи скажут больше, чем беглый просмотр.
Игнорируйте имена, форматирование и мелкие рефакторинги на этом этапе, если они не мешают пониманию. Переменная с именем tmpData может подождать. Правило возврата денег, которое взимает неверную комиссию, — нет.
Хорошие комментарии первого прохода прямые: «Это отвергает повторных клиентов, но правило говорит, что требуется одобрение только для новых пользователей.» Это даёт автору реальное направление для фикса. Шлифовку оставьте на потом, после того как логика будет верна.
Второй проход: проверка безопасности, отказов и уборки
Второй проход начинается только после того, как логика выглядит правильной. Фича работает, happy path имеет смысл, и теперь задача меняется. Перестаньте спрашивать «Делает ли это правильную вещь?» и спросите «Что ломается, когда реальныe пользователи, грязные данные или странное время столкнутся с этим кодом?»
Это сдвиг важен. Когда команды смешивают обе задачи в одном просмотре, они пропускают мелкие проблемы безопасности или тратят слишком много времени на спор о названиях, прежде чем заметят плохой дефолт.
Начните с риска. Сгенерированный код часто принимает слишком много, доверяет вводу слишком рано или оставляет настройки слишком открытыми. Ищите широкие права доступа, отсутствующие проверки ввода, раскрытые секреты, включённый режим отладки и бесконечные циклы повторных попыток. Код может работать в первый день и создать проблему безопасности на десятый.
Затем целенаправленно прочтите пути отказа. Проверьте, что видит пользователь, когда API тайм-аутит, запись отсутствует или загрузка файла терпит неудачу. Хороший код корректно обрабатывает пустые состояния, частичные данные и медленные ответы, не вводя пользователя в заблуждение. Если приложение работает только когда все зависимости ведут себя идеально, ревью не завершено.
Тесты здесь тоже важны, но количество тестов — не главное. Проверьте, покрывают ли тесты неправильный ввод, ошибки прав доступа и рисковые граничные случаи. Если код трогает продовые системы, спросите, помогут ли логи быстро найти причину проблемы. Задайте тот же вопрос про мониторинг. Если это сломается в 2 часа ночи, узнает ли команда об этом раньше, чем начнут жаловаться пользователи?
Короткий чеклист второго прохода помогает:
- Попробуйте найти хотя бы одну проблему с безопасностью, даже в небольшом изменении.
- Прочтите один путь отказа от начала до конца.
- Проверьте, доказывают ли тесты, что код падает безопасно.
- Проверьте, укажут ли логи и оповещения на причину.
Оставьте имена, повторяющиеся блоки и мёртвый код на конец. Они важны, но не должны отвлекать внимание от безопасности и поддержки. Когда рискованные части будут чисты, уберите мусор: подчистите имена, удалите остатки и сократите дублирование. Такой порядок делает ревью быстрее и ловит баги, которые действительно вредят.
Как запускать процесс
Команды работают быстрее, когда рассматривают ревью как две короткие задачи, а не один длинный спор. Это особенно важно при ревью сгенерированного кода, потому что отполированный вывод может скрывать слабую логику.
Начните до открытия дифа. Автор должен добавить короткое резюме в начало pull request: что изменилось, зачем и где рискованные части. Достаточно трёх–пяти строк. Если ревьюверу нужно гадать про цель, ревью сразу замедляется.
Потом сделайте текущую стадию очевидной. Добавьте простую пометку в заголовке pull request или в статусе, например «первый проход» или «второй проход». Эта маленькая метка держит всех в одном режиме и препятствует смешению глубоких логических замечаний и мелких стилевых нот.
Простой поток выглядит так:
- Автор открывает pull request с кратким резюме и пометкой «первый проход».
- Ревьювер проверяет поведение, предположения, граничные случаи и соответствует ли код задаче.
- Автор исправляет сначала логические ошибки.
- После этого pull request переключается на «второй проход».
- Ревьюверы проверяют безопасность, тесты, логи, комментарии, нейминг и мелкие правки.
Порядок важен. Если ревьювер начинает с нейминга или форматирования при ещё неустоявшейся логике, автор часто переписывает ту же область дважды. Это создаёт шум и тратит время.
Полезно также не раздувать поток обсуждений во втором проходе. Группируйте мелкие фиксы в одно короткое замечание или в один дополнительный коммит, вместо того чтобы открывать десять отдельных нит-потоков по импортам, формулировке логов и мелким переименованиям. Ревью ощущается спокойнее, когда «ниты» идут вместе.
Одно простое правило работает хорошо: если комментарий всё ещё важен после переписывания, оставляйте его в первом проходе. Если он исчезнет после переписывания, отложите на второй.
Простой пример из команды под дедлайном
Небольшой SaaS-стартап нужно было выпустить форму регистрации до демо продукта. Большая часть кода пришла от ИИ-инструментов, поэтому pull request сначала казался готовым: страница, обработчик API, шаг с email и тесты, которые на беглый взгляд выглядели нормальными.
У команды была знакомая проблема. Когда они ревьюили сгенерированный код одним проходом, комментарии смешивались. Один ревьювер говорил о правилах паролей, другой — о редактировании логов, третий заметил пропущенные тесты. Тред быстро превращался в шум, и простые правки стояли рядом с большими рисками.
Они разделили ревью.
В первом проходе ревьювер смотрел только на поведение. Проверяли, отвергались ли плохие email'ы, блокировались ли слабые пароли по правильной причине, видел ли существующий пользователь понятное сообщение и переводил ли успешный регистрационный сценарий пользователя на следующий шаг. Ещё проверяли скучное, но важное: соответствует ли код продуктовым правилам или модель придумала свою версию.
Первый проход нашёл три проблемы. Форма принимала пробелы в конце email, API возвращал одинаковое сообщение для двух разных ошибок, и успешный поток пропускал подтверждение email в одном граничном случае. Разработчик исправил эти замечания за один цикл, потому что каждое замечание было про логику и ожидаемые результаты.
Второй проход начался после того, как поток заработал. Другой ревьювер проверил то, что обычно торопят перед слиянием. Попросили rate limit на эндпоинт регистрации, убрали лог, который печатал сырые email-адреса, и добавили тесты для повторных попыток при таймауте почтового сервиса.
Они также заметили типичную проблему уборки из AI-кода: неиспользуемый хелпер и флаг в конфиге, который никому не нужен.
Команда смёржила изменение в тот же день. Не потому, что код был идеален, а потому что у каждого прохода была одна задача. Комментарии оставались сфокусированными, никто не спорил по разным темам одновременно, и разработчик мог исправлять по очереди.
Ошибки, которые делают команды
Самая частая ошибка — шлифовать код, прежде чем кто-то согласится, что логика верна. Ревьювер замечает неудобные имена, отступы или повторяющийся хелпер и начинает исправлять мелочи сразу. Через десять комментариев никто ещё не ответил на главный вопрос: решает ли этот код нужную задачу с правильными правилами?
Такой порядок тратит время. Если команда потом изменит логику, многие комментарии по уборке станут мёртвой работой. Лучший привычка простая: первый проход решает, нужно ли этому коду вообще существовать в текущем виде. Второй делает его безопасным, чистым и удобным для поддержки.
Команды также замедляют себя, смешивая стилевые комментарии в каждом треде. Один комментарий спрашивает про граничный случай, следующий спорит про имена переменных, затем кто-то указывает на порядок импортов. Ревью превращается в шум, и серьёзные проблемы теряются.
Это усугубляется при сгенерированном коде. ИИ часто выдаёт аккуратный на вид код, так что ревьюверов тянет к косметике. Оптимальная форма может скрывать слабую обработку ошибок, пропущенные проверки прав или код, работающий только для happy path.
Ещё одна ошибка — пропускать второй проход, потому что первый прошёл гладко. Логика может быть корректна и при этом оставить после себя мусор. Код может пройти беглый просмотр и при этом раскрывать секреты в логах, не иметь тестов, дублировать старые функции или оставлять неиспользуемые ветки, которые запутают следующего разработчика.
Ещё одна проблема в небольших командах — один и тот же человек делает оба прохода всегда. Этот человек устаёт, начинает пробегать глазами и превращается в бутылочное горлышко. Слепые пятна растут, когда одни и те же глаза всегда проверяют логику и уборку в одном порядке.
Несколько простых правил избегают большинства проблем:
- Откладывайте замечания по стилю и неймингу до утверждения логики.
- Требуйте реального второго прохода, даже для коротких изменений.
- Меняйте ревьюверов или дайте второму человеку делать второй проход.
- Используйте инструменты форматирования, чтобы люди тратили время на суждение, а не на формат.
Такой раздел особенно полезен, когда команда начинает активнее использовать ИИ в разработке. Быстрый вывод помогает только тогда, когда люди проверяют правильные вещи в правильном порядке.
Кто должен делать каждый проход
Назначать одного и того же человека на оба прохода кажется эффективным, но обычно создаёт слепые пятна. Один ревьювер начинает с продуктового поведения, затем увлекается неймингом, логами, секретами и деталями деплоя. Ревью затягивается, и полезные комментарии смешиваются.
Для сгенерированного кода разделяйте работу по менталитету. Первый ревьювер проверяет, делает ли изменение правильную вещь для пользователя и бизнеса. Второй — безопасно ли это запускать, удобно ли поддерживать и не приведёт ли это к проблемам позже.
Простое разделение работает так:
- Первый проход: инженер с продуктовым мышлением, тимлид или владелец фичи проверяет логику, граничные случаи и ожидаемое поведение.
- Второй проход: кто-то ближе к безопасности, инфраструктуре, платформе или старший бэкенд-ревьювер проверяет безопасность, производительность, логи, конфиги и уборку.
- Если доступен только один ревьювер, делайте проходы в разное время, а не в одном заходе.
Ограничения по времени помогают. Первый проход должен быть коротким, часто 10–15 минут для обычного pull request. Второй проход может быть ещё короче, около 5–10 минут, потому что ревьювер не восстанавливает бизнес-контекст с нуля.
Отдельные правила по одобрению помогают больше, чем многие команды ожидают. Если одно одобрение покрывает всё, люди пропускают второй проход, когда очередь растёт. Даже если ваш инструмент показывает только одну зелёную галочку, команда может считать утверждение логики и утверждение безопасности двумя отдельными шагами.
Команды, которые работают с частичным CTO или небольшой платформенной группой, часто успешно применяют такое разделение. Один человек отвечает за правильность продукта, другой — за операционные риски в стеке. Это особенно подходит для ревью кода от ИИ, потому что сгенерированный код часто выглядит нормально, но скрывает слабую обработку ошибок, шумные запросы или рискованные дефолты.
Быстрая проверка перед слиянием
Слияние должно вызывать ощущение «скучно». Если в ветке всё ещё остаются базовые вопросы, ревью не закончено.
Прямо перед слиянием перестаньте искать шлифовку и спросите, можно ли оставить код на следующую неделю. Здесь двухэтапное ревью помогает сильнее всего. Первый проход проверяет, работает ли изменение. Второй — убедится, что оно не принесёт лишних проблем.
Используйте короткую финальную проверку:
- Ветка соответствует задаче. Если задача была «добавить экспорт CSV», код должен добавлять экспорт CSV, а не тайком включать дополнительные рефакторы.
- Кто-то проверил пути отказа. Посмотрите, что происходит, когда API тайм-аутит, файл отсутствует, у пользователя нет доступа или ввод пустой.
- Кто-то проверил секреты, аутентификацию и обработку ввода. Нет захардкоженных токенов, нет свободных прав и нет сырого пользовательского ввода, попадающего в запросы, пути к файлам или shell-команды.
- Автор убрал шум. Удалите debug-print'ы, закомментированные блоки, неиспользуемые хелперы и сгенерированный код, который никто не вызывает.
- Тесты покрывают рискованные места. Не нужно покрывать каждую строку, но нужны тесты там, где ошибки будут вредить пользователям, деньгам или данным.
Первый пункт важнее, чем команды признаются. Сгенерированный код часто выглядит насыщенно и завершённо, но всё ещё может не выполнять реальную задачу. Ревьювер должен сравнить ветку с тикетом простыми словами и ответить на один вопрос: «Я бы назвал это выполненным, будь я запросившим?»
Уборка важна, потому что мусор накапливается быстро. Один забытый секрет, один пропущенный чек доступа или один мёртвый хелпер могут превратить маленькое слияние в долгую уборку на следующей неделе. Пять дополнительных минут сейчас могут сэкономить час позже.
Если хоть один пункт не отмечен, не мёржьте. Попросите недостающий тест, уберите шум или исправьте небезопасный путь.
Начните с малого и измеряйте
Начните с одной команды, одного репозитория и одного шаблона pull request. Малый эксперимент даёт быстрый фидбек и мешает людям спорить о процессе, в котором они не участвовали.
В первую–две недели используйте одно и то же разделение во всех ревью. Первый проход проверяет, делает ли код нужную работу. Второй — безопасность, уборку и всё, что затруднит будущие изменения.
Вам не нужна новая связка инструментов или длинная политика. Большинство команд может начать с четырёх простых шагов:
- Добавьте две короткие секции в шаблон pull request: «Первый проход» и «Второй проход».
- Попросите ревьюверов оставлять комментарии в соответствующей секции.
- Отслеживайте, сколько времени занимает ревью от открытия до одобрения.
- Считайте баги, найденные после слияния, в течение нескольких недель.
Эти данные важнее мнений. Если время ревью падает и баги после слияния не растут, процесс работает. Если баги падают, а время ревью остаётся на месте — это тоже хорошая сделка.
Не фиксируйте процесс слишком рано. Фронтенд-база может требовать больше внимания к граничным случаям и состояниям в первом проходе. Бэкенд или инфраструктурный сервис может требовать более строгого второго прохода для прав, секретов, повторных попыток, логов и обработки отказов.
Держите чеклист для ревью коротким. Если он растёт каждую неделю, люди перестанут им пользоваться. Отсеките всё, что не ловит реальные проблемы.
Реалистичный следующий шаг — прогнать эксперимент на пяти–десяти pull request'ах, а затем обсудить результаты на одной короткой встрече команды. Посмотрите на время ревью, количество повторно открытых комментариев, баги после слияния и чувство перегрузки у ревьюверов. Последнее важно: хорошие практики должны делать работу спокойнее, а не тяжелее.
Если команда хочет внешней помощи в настройке практических AI-воркфлоу для ревью, Oleg Sotnikov at oleg.is делает такую работу как Fractional CTO и советник стартапов. Его опыт охватывает разработку ПО, работу CTO, инфраструктуру и AI-инициативы, что делает дизайн таких процессов практичным, а не теоретическим.
Если эксперимент сработает, оставьте шаблон, запишите несколько проверок, которые действительно ловят проблемы, и примените модель в следующей команде.