Код-ревью стало ключевым этапом в разработке: генерация кода с помощью LLM упростилась, а вот проверка его качества по-прежнему требует инженерной экспертизы.

В новом переводе от команды Spring АйО эксперты сообщества подробно и на собственном опыте рассказали про нюансы код-ревью.


За последние два года код-ревью стало значительно важнее. Генерация кода с помощью LLM теперь проста, но проверка кода по-прежнему так же сложна.

Уточнение от автора статьи

Разумеется, существуют инструменты для код-ревью на базе LLM. И они довольно полезны! Но, по крайней мере на сегодняшний день, они всё ещё уступают настоящим инженерам, потому что не могут учитывать тот объём контекста, который доступен компетентному специалисту.

Многие инженеры-программисты теперь тратят столько же (или даже больше) времени на проверку кода, сгенерированного их собственными ИИ-инструментами, сколько на ревью кода своих коллег.

Мне кажется, многие инженеры неправильно проводят код-ревью. Конечно, существует множество подходов к этому процессу, так что в значительной степени это отражение моих профессиональных предпочтений.

Не ограничивайтесь только просмотром diff

Самая большая ошибка, которую я наблюдаю, — это ревью, сосредоточенное исключительно на diff.

Уточнение от автора статьи

Для читателей, не связанных с разработкой: под «diff» здесь понимается разница между существующим кодом и предлагаемыми изменениями — какие строки были удалены, добавлены или изменены.

Большинство самых ценных комментариев при код-ревью почти не связаны с самим diff, а основаны на вашем понимании остальной части системы.

Например, один из самых очевидно полезных комментариев — «этот метод не нужно добавлять здесь, он уже есть в другом месте». Сам diff не даст вам такой комментарий. Вы должны заранее знать другие части кодовой базы, о которых автор diff`а может не знать.

Аналогично, замечания вроде «этот код лучше перенести в другой файл» очень важны для поддержания качества кодовой базы в долгосрочной перспективе. Главный принцип при работе с крупными кодовыми базами — это консистентность (подробнее об этом я пишу в тексте «Ошибки, которые инженеры совершают в больших устоявшихся кодовых базах»). Очевидно, по одному только diff судить о консистентности всего предполагаемого изменения просто невозможно.

Рассматривать только diff гораздо проще, чем анализировать, как изменения вписываются в кодовую базу в целом. Вы можете быстро пробежать diff и оставить построчные комментарии (например: «переименуй эту переменную» или «эта функция должна быть устроена иначе»). Такие комментарии могут быть даже полезны! Но, ограничиваясь только таким подходом, вы упускаете значительную часть пользы от код-ревью.

Не оставляйте слишком много комментариев

Возможно, моя самая спорная точка зрения по поводу код-ревью заключается в том, что хорошее ревью не должно содержать больше пяти-шести комментариев. Большинство инженеров оставляют слишком много замечаний. Когда вы получаете ревью с сотней комментариев, с ним практически невозможно взаимодействовать иначе, кроме как на самом поверхностном уровне. Любые действительно важные замечания теряются в этом шуме.

Уточнение от автора статьи

Это частный случай общего правила коммуникации: если вы скажете человеку одну вещь, он, скорее всего, её запомнит; если вы скажете двадцать — он, вероятно, не запомнит ни одной.

Что делать, если вы видите двадцать мест в diff, которые нужно исправить — например, двадцать случаев использования переменных в camelCase вместо snake_case? Вместо того чтобы оставлять двадцать отдельных комментариев, я бы порекомендовал написать один обобщённый комментарий, в котором вы объясняете, какой стилистический подход следует применить, и просите инженера самостоятельно внести нужные правки построчно.

Из этого правила есть как минимум одно исключение. Когда вы нанимаете нового инженера в команду, может быть полезно оставить множество стилистических комментариев, чтобы помочь ему разобраться в специфике «код стайла», принятого в конкретной кодовой базе. Но даже в этом случае стоит помнить, что любые важные замечания, скорее всего, затеряются среди этих мелочей. Возможно, даже лучше будет оставить общий комментарий вроде «здесь мы не используем ранние выходы (early return) из функций», чем делать отдельное замечание к каждому случаю early return в diff.

Не проводите ревью через призму «как бы я это написал»

Одна из причин, по которой инженеры оставляют слишком много комментариев, заключается в следующем подходе к ревью:

  1. Посмотреть на фрагмент diff

  2. Спросить себя: «А как бы я написал этот код?»

  3. Оставить комментарий по каждому расхождению между своим вариантом и фактическим кодом

Такой подход легко приводит к сотне замечаний в pull request: бесконечный поток комментариев вроде «я бы выполнил эти две операции в другом порядке» или «я бы немного иначе структурировал эту функцию» и так далее.

Я не говорю, что такие мелкие замечания всегда плохи. Иногда порядок операций действительно имеет значение, или функции действительно плохо структурированы. Но одна из моих ключевых позиций в инженерии программного обеспечения — это то, что практически любую задачу можно решить несколькими допустимыми способами, и выбор подхода часто зависит от личных предпочтений.

Как рецензент, вы должны уметь одобрять решения, отличные от ваших собственных, без комментариев — при условии, что оба варианта допустимы. В противном случае вы ставите своих коллег в неудобное положение. Они либо согласятся со всеми вашими замечаниями, чтобы избежать конфликта (что приведёт к напрасной потере времени и фактически говорит о вас, как об обладателе "синдрома вахтера"), либо будут спорить по каждому пустяку, что займёт ещё больше времени. Код-ревью — это не момент, когда вы должны навязывать коллегам свои личные предпочтения.

Комментарий от Евгения Сулейманова

Можно предложить проверку по критериям - выполняет требования, поддерживаемость, контракты не ломаются, бюджеты latency/ресурсов соблюдены, безопасно. Если да - личные предпочтения не повод блокировать.

Если вы не хотите, чтобы изменение было замержено, оставьте блокирующее ревью

До этого момента я говорил только о комментариях в ходе ревью. Но «высший приоритет» в код-ревью — это не содержание комментариев, а его статус: одобрение, просто комментарии или блокирующее ревью. Именно статус ревью придаёт тон всем комментариям. Комментарии при одобрении читаются как «всё отлично, вот пара пожеланий, если захочешь». Комментарии в блокирующем ревью звучат как «вот почему я не хочу, чтобы это было замержено».

Если вы хотите заблокировать изменение — оставьте блокирующее ревью. Многие инженеры считают невежливым оставлять блокирующий отзыв, даже если видят серьёзные проблемы, и вместо этого просто пишут комментарии, описывая эти проблемы. Не делайте так. Это формирует культуру, в которой никто не понимает, можно мержить изменения или нет. Одобрение должно означать: «Я не против, если ты замержишь, даже проигнорировав мои комментарии». Просто комментарии без статуса — «Я не против, если ты замержишь после одобрения другого участника, даже если проигнорируешь мои замечания». Если вас расстроит, что изменение замержили — вы должны оставить блокирующее ревью. Тогда автор изменений будет точно знать, можно мержить или нет, и ему не придётся бегать по всем комментаторам, чтобы получить их неформальное одобрение.

Комментарий от Евгения Сулейманова

Имеет смысл установить SLA и эскалацию - когда ставим Request changes (контракты/безопасность/риск прод), срок ответа автора/рецензента (например, 1 рабочий день), что делать при блоке > N дней (синк/mini-RFC).

Очень помогает привести соответствие статусов инструментам (GitHub/GitLab) и вставить шаблон блокирующего комментария (причина -> шаги "как снять блок" -> обещание ре-апрува).

Комментарий от Михаила Поливахи

В ряде крупных западных бигтхеов комментарии на code review стараются разделять на блокирующие, и на nitpick-и, где nitpick это просто "вкусовое" замечание,  которое больше относится к стилистике кода и т.п., нежели чем к семантике программы. 

Несмотря на то, что nitpicking на code-review многие считают очень спорной практикой, в реальности это происходит сплошь и рядом. Обсудим на подкасте.

Большинство ревью должно завершаться одобрением

Начну с оговорки: многое зависит от типа кодовой базы, о которой идёт речь. Например, я считаю вполне допустимым, если pull request’ы в такие проекты, как SQLite, чаще всего получают блокирующее ревью. Но в стандартной SaaS-кодовой базе, где команды активно разрабатывают новые функции, подавляющее большинство ревью должно завершаться одобрением. Я подробно разбираю различие между этими двумя типами кодовых баз в тексте Pure and Impure Engineering.

Если множество PR’ов блокируются, это обычно свидетельствует о чрезмерном контроле. Один из типичных сценариев, с которым я часто сталкивался, выглядит так: одна команда владеет «узким горлышком», через которое проходят функции других команд — например, конфигурацией edge-сети, где определяются новые публичные маршруты, или структурой базы данных, которую необходимо изменить для внедрения новых функций. Такая команда обычно ориентирована на стабильность, а не на скорость — в отличие от команд, занимающихся разработкой новых фич.

Комментарий от Евгения Сулейманова

Предложите формальный контракт между командами - SLA на ревью, перечень блокирующих критериев, окна изменений, совместные RFC-сессии; это снижает число эскалаций.

У инженеров в этой “платформенной” команде может быть даже другое название должности, например SRE, или они вообще могут принадлежать к другой организационной структуре. Их мотивация, таким образом, не совпадает с мотивацией продуктовых команд, которым они номинально «помогают».

Предположим, что продуктовая команда хочет обновить публичные маршруты ingress, чтобы запустить важный проект. Но команде edge-сети этот проект не интересен — он не влияет ни на их задачи, ни на показатели их руководителя. Единственное, что может повлиять на их оценку, — это проблемы в продакшене, вызванные изменениями. А значит, их мотивация — блокировать любые потенциально рискованные изменения как можно дольше. Для команды, которая готова принять определённый риск ради выпуска фичи, это может быть чрезвычайно раздражающим.

Уточнение от автора статьи

В итоге такие тупики обычно решаются через жалобы: продуктовая команда обращается к своему директору или вице-президенту, который жалуется директору или вице-президенту команды edge-сети, и тот в ответ велит просто разблокировать это изменение. Но такой способ устранения конфликта интересов довольно грубый и срабатывает только для достаточно «громких» фич, которые могут получить поддержку со стороны топ-менеджмента.

Конечно, существуют и другие причины, по которым PR’ы могут часто блокироваться. Возможно, компания только что наняла множество неопытных инженеров, которым действительно не стоит позволять вносить изменения в код. Или недавно произошёл крупный инцидент, и теперь любые рискованные изменения блокируются на пару недель, пока пользователи об этом забудут. Но в нормальных условиях высокая доля блокирующих ревью говорит о наличии структурной проблемы.

Многим инженерам — и я не исключение — нравится оставлять блокирующие ревью, по тем же причинам, по которым людям вообще нравится быть «стражами порядка». Кажется, что ты в одиночку оберегаешь качество кодовой базы или предотвращаешь будущий инцидент в продакшене. Это также возможность потешить одно из распространённых инженерных тщеславий — продемонстрировать своё техническое превосходство над менее опытным коллегой. Ах, ты не знал, что твой код вызовет N+1-запрос? А я знал. Как хорошо, что я внимательно всё прочитал, не так ли?

Комментарий от Михаила Поливахи

Несколько лет назад на hackernews попала статья, которая как раз говорила про разные аспекты программной разработки. в том числе и про ЭГО, как один из главных лимитирующих факторов в рамках разных процессов. Крайне рекомендую почитать.

Этот принцип — склонность одобрять изменения, а не блокировать их — настолько важен, что в руководстве Google по код-ревью он стоит первым и называется «главным принципом среди всех правил код-ревью».

Уточнение от автора статьи

Принцип Google формулируется ещё жёстче: изменение следует одобрить, даже если это всего лишь незначительное улучшение, а не идеальный код. Я же воспринимаю посыл так: «Я понимаю, что тебе хочется, но не будь занудным хранителем порога — одобри, наконец, этот PR!»

Заключительные мысли

Я вполне уверен, что многие инженеры не согласятся с большинством (а может, и со всеми) пунктами в этом посте. И это нормально! У меня также есть много убеждений насчёт код-ревью, которые, на мой взгляд, очевидно верны, но я бы не стал включать их сюда.

Из моего опыта, стоит придерживаться следующих подходов (ниже, в конце статьи, приведен пример чеклиста Code Review по мнению эксперта сообщества Spring АйО Евгения Сулейманова):

  • Обращать внимание на то, какой код не был написан в PR, а не только на diff

  • Оставлять небольшое количество продуманных комментариев, а не наспех писать построчные замечания, которых в итоге накапливается сотня

  • Смотреть на код через призму «будет ли это работать», а не «точно ли это так, как сделал бы я»

  • Если вы не хотите, чтобы изменение было замержено — оставьте блокирующее ревью

  • Если нет очень серьёзных проблем — аппрувьте изменения.

Всё это в целом применимо и к ревью кода, сгенерированного агентными LLM-системами. Они особенно склонны упускать важный код, который стоило бы написать; им также сложно справляться со ста комментариями сразу; у них есть свой собственный стиль. Единственное исключение — принцип «старайтесь аппрувить изменения». К LLM это не относится. Генерируемые ИИ PR’ы мо��но и нужно блокировать столько, сколько потребуется.

В завершение хочу сказать, что существует множество подходов к код-ревью. Вот неполный список целей, которых может стремиться достичь процесс ревью:
— убедиться, что несколько человек в команде знакомы с каждым участком кодовой базы;
— обсудить архитектурные решения в изменениях;
— найти тонкие баги, которые один человек может не заметить;
— горизонтально передавать знания внутри команды;
— повысить ощущение сопричастности к изменениям;
— обеспечить соблюдение стиля и формата кода;
— соответствовать требованиям SOC2 вроде «один человек не может изменить систему в одиночку».

Я перечислил эти цели в порядке их важности лично для меня, но у других инженеров порядок может быть совсем другим — и подход к код-ревью у них тоже будет отличаться.

P.S.: Этот пост получил в основном положительные отзывы на lobste.rs и Hacker News. Нескольким людям не понравился пример с camelCase против snake_case — они считают, что такие вещи должна отслеживать автоматизация. Возможно, так, но принцип сохраняется и для менее очевидных случаев, которые нельзя так просто автоматизировать — например, «всегда логировать с определёнными тегами перед операциями записи». В этой ветке комментариев ведётся интересное обсуждение норм вокруг блокирующих ревью. Наконец, самый популярный комментарий на lobste.rs гласит, что я неправильно интерпретирую гайд Google, перефразируя его как «склоняйтесь к одобрению». На мой взгляд, принцип действительно направлен на то, чтобы убедить умных, придирчивых инженеров чаще одобрять изменения — но, да, это уже моя интерпретация.

Комментарий от Евгения Сулейманова

Одобряйте достаточно хорошие изменения, если они улучшают систему и не нарушают инварианты

Комментарий от Евгения Сулейманова. Пример чек листа, который потенциально можно применить на своем проекте.

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

Проверка

Вопрос рецензента

Что считать доказательством

Статус

1

Контекст

Зачем изменение? Какие альтернативы рассматривали?

Описание PR с проблемой/целями/компромиссами

OK / FIX

2

Совместимость

Не ломает ли публичные API/схемы/контракты?

Дифф OpenAPI/IDL/DDL, миграционный план, версия контракта

OK / FIX

3

Риск & Blast radius

Какой "радиус поражения"? Есть фичефлаг/канареечный запуск/роллбэк?

Флаг, план rollout/rollback, лимит аудитории

OK / FIX

4

Надежность

Есть timeouts/retries/backoff? Идемпотентность/дедупликация?

Код клиента/ретраев, тесты отказоустойчивости

OK / FIX

5

Производительность

Критические пути/сложность/IO учтены?

Базовые метрики, оценка сложности, профилировка (если релевантно)

OK / FIX

6

Тест-план

Что покрыто тестами, что нет? Есть позитив/негатив/границы?

Unit/integ тесты, шаги ручной проверки, скриншоты/лог

OK / FIX

7

Обсервабилити

Есть метрики/логи/трейсы по write-пути и ошибкам?

Метрики (counter,histogram), логи ключевых событий, trace-спаны

OK / FIX

8

Безопасность

Нет утечек секретов/PII? Авторизация/валидация входа ок?

Secrets из vault, валидация инпутов, проверки ролей/скоупов

OK / FIX

9

Консистентность

Соответствует принятому стилю/паттернам/слою?

Ссылки на гайд, отсутствие "второго велосипеда", ADR при отклонении

OK / FIX

10

Документация

Обновлены README/ADR/миграционные заметки?

Коммит с докой, ADR-ссылка

OK / FIX

11

Размер PR

Не слишком ли большой? Можно дробить?

Кол-во измененных строк/файлов, логичная разбивка

OK / FIX

12

Внешние зависимости

Новые библиотеки безопасны/по лицензии/версии?

dep-scan, лицензии, список обновлений

OK / FIX

13

LLM-контент

Если код от ИИ - прошел авто-проверки? Нет "галлюцинаций"?

Логи генерации/ссылки, тест-план, отсутствие несуществующих API

OK / FIX

14

Итоговое решение

Изменение "достаточно хорошее" и улучшает систему?

Суммарный комментарий рецензента (BLK/MAJ/NIT)

Approve / Request changes

Комментарий от Евгения Сулейманова. Шаблон блокирующего комментария

Request changes (BLK)

Причина блокировки:

  1. Нарушение контракта Foo v2 (несовместимая схема поля bar).

  2. Отсутствуют таймауты/ретраи в BarClient -> риск зависаний.

  3. Нет метрик/логов на критичном write-пути -> нечем мониторить.

Как снять блок:

  • Вернуть совместимость или поднять версию контракта с миграцией.

  • Добавить timeouts/retries/backoff, тесты на отказоустойчивость.

  • Прописать метрики (counter ошибок, histogram латентности) и логи ключевых событий.

Комментарий от Евгения Сулейманова. Что это все дает разработчикам на практике
  • Быстрее мержим PR. Понятная семантика статусов (Approve/Comments/Request changes) и правило "BLK только по контрактам/безопасности" сокращают итерации и холостые ожидания.

  • Меньше бессмысленных правок. Линтер/форматтер/прехуки выносят стиль из ревью -> фокус на сути, а не на пробелах и кейсах.

  • Меньше холивара. Критерии приемлемости и таксономия BLK/MAJ/NIT глушат "я бы сделал иначе" и переводят обсуждение в плоскость требований и рисков.

  • Предсказуемый процесс. PR-шаблон и чеклист (контракты, миграции, таймауты/ретраи, метрики/логи/трейсы, тест-план) делают ревью воспроизводимым и прозрачным.

  • Меньше регрессий в проде. Обязательные таймауты/ретраи/идемпотентность + наблюдаемость на write-пути ускоряют отладку и снижают частоту инцидентов.

  • Проще работать между командами. SLA на ревью, "окна изменений", список блокирующих критериев снимают узкие места и эскалации.

  • Быстрее онбординг. "Менторский режим" на старте + те же чеклисты = меньше микрокомментов, больше полезного контекста.

  • Нормальная работа с ИИ-PR. Авто-проверки и политика для LLM-кода экономят время на механике и страхуют от "галлюцинаций"/лицензий.

  • Меньше контекст-свитчинга. Мелкие инкрементальные PR под фичефлагами легче читать, тестировать и катить.

  • Рост автономности. Можно делать качественный self-review по чеклисту и приносить на ревью сразу "готовый к аппруву" PR.

Итог: меньше шума, меньше кругов по ревью, больше фокуса на рисках и архитектуре - скорость доставки растет, качество продакшена стабилизируется.


Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.

Комментарии (3)


  1. just-a-dev
    29.10.2025 15:15

    Ох уж этот Евгений Сулейманов! Можно саму статью было под экспандер засунуть, оставить только его комментарии


  1. Astrowalk
    29.10.2025 15:15

    Так может, не с того конца начали? Пусть код пишут инженеры, а ревью делает LLM?


    1. anaxita
      29.10.2025 15:15

      это сильно хуже