Руководство разработчика по ревью кода, написанного ИИ
ИИ пишет всё большую часть каждого пул-реквеста. Вот как эффективно проверять код, сгенерированный ИИ — на что обращать внимание, чему доверять и когда переписывать.
Код-ревью всегда было способом ловить ошибки до того, как они попадут в продакшн. Но когда код написан ИИ-ассистентом, а не коллегой-человеком, динамика ревью меняется коренным образом. Ошибки, которые совершает ИИ, отличаются от ошибок человека, и вещи, которые нужно проверять, — это не то же самое, что вы проверяли бы при ревью кода коллеги.
Это руководство обобщает опыт зрелых команд по ревью кода, сгенерированного ИИ. Оно организовано по категориям проблем, которые ИИ-модели стабильно воспроизводят, чтобы вы могли проходить по систематическому чек-листу, а не полагаться на интуицию, выработанную для кода, написанного человеком.
Почему код, сгенерированный ИИ, требует иных критериев ревью
Разработчики-люди совершают ошибки, связанные с усталостью, отвлечением и пробелами в знаниях: уставший разработчик упускает граничный случай, отвлечённый забывает обработать ошибку, джуниор использует антипаттерн, потому что не знает лучшего. ИИ-модели совершают ошибки совершенно иного рода: галлюцинации, слепота к контексту и стилистическая непоследовательность.
Человек, написавший функцию, которая не обрабатывает null, вероятно, знает, как надо, просто забыл. ИИ, написавший такую же функцию, действительно не знает, возможен ли null в вашей кодовой базе, если вы ему об этом явно не сказали. Это различие важно, потому что и способ исправления разный: человеку нужно напоминание, а ИИ — ограничение, закодированное в промпте или выявленное на ревью.
Понимание этой разницы — основа эффективного ревью кода ИИ. Вы не проверяете, был ли разработчик внимателен. Вы проверяете, было ли у ИИ достаточно контекста для генерации корректного кода и соответствует ли его вывод негласным соглашениям вашей кодовой базы, которые он не мог видеть.
Пункт чек-листа 1: Галлюцинированные API и импорты
Самая распространённая проблема в коде, сгенерированном ИИ, — использование библиотек, функций или API, которые не существуют. ИИ-модели обучены выдавать правдоподобный код, и они с уверенностью генерируют импорты для пакетов, которые никогда не публиковались, и вызывают методы, которые никогда не существовали. Это не злонамеренно — модель интерполирует между реальными пакетами, виденными при обучении, и изобретает мостик, который выглядит разумно.
// AI-generated code that looks plausible but imports a non-existent function
import { renderAsync } from 'react-dom'; // renderAsync does not exist
import { optimize } from 'lodash/fp/string'; // This path does not exist in lodash
// What you actually need
import { renderToString } from 'react-dom/server';Исправление простое, но важное: проверяйте каждый импорт и каждый API-вызов по актуальной документации. Не предполагайте, что раз код компилируется, API корректны — некоторые галлюцинированные функции имеют правдоподобные сигнатуры, проходящие проверку TypeScript, но падающие в рантайме. Ревью должно включать быструю проверку любых импортов, которые вы не узнаёте.
Пункт чек-листа 2: Отсутствующая обработка ошибок
ИИ-модели склонны генерировать счастливый путь. Они отлично пишут основную логику функции — цикл, трансформацию, возвращаемое значение — и совершенно не справляются с обработкой того, что идёт не так. Сетевые запросы без catch-блоков. Файловые операции без обработки ошибок. Асинхронные функции без обработчиков reject.
Это не потому, что ИИ не умеет писать обработку ошибок. Если явно попросить, ИИ выдаст тщательную try-catch логику. Проблема в том, что поведение модели по умолчанию — написать простейшую работающую версию, а обработка ошибок в неё не входит. Каждое ревью кода, сгенерированного ИИ, должно включать проход, смотрящий только на пути обработки ошибок.
- У каждой асинхронной функции должен быть catch или обработчик reject.
- Каждый внешний API-вызов должен обрабатывать сетевые ошибки, таймауты и неожиданные форматы ответа.
- Каждое преобразование данных должно обрабатывать null, undefined и неожиданные типы.
- Каждая операция с файлами или базой данных должна обрабатывать ошибки доступа и отсутствующие ресурсы.
Полезный приём — простой тест: уберите try-catch блоки из сгенерированного ИИ кода и посмотрите, имеет ли оставшаяся логика смысл. Если да — ИИ, скорее всего, не задумывался об обработке ошибок. Если логика зависит от обработки ошибок для работы — ИИ встроил её правильно.
Пункт чек-листа 3: Несоответствия стиля и соглашений
У каждой кодовой базы есть неписаные стилевые соглашения. Команда использует ранние возвраты, а не вложенные if. Сообщения об ошибках следуют определённому формату. Имена переменных используют конкретный паттерн. ИИ-модели, обученные на миллионах публичных репозиториев, генерируют код, отражающий статистическое среднее по всем этим репозиториям, а не конкретные соглашения вашей кодовой базы.
В результате получается код, который работает, но ощущается чужеродным. Он использует иные соглашения по именованию, иную структуру модулей или иной паттерн обработки ошибок, чем окружающий код. Такая несогласованность быстро накапливается — пять сгенерированных ИИ функций, написанных в пяти разных неявных стилях, создают кодовую базу, которая кажется бессвязной и сложнее поддерживается.
Лучшая защита — включать примеры стиля в ваши промпты. Вставьте репрезентативную функцию из того же модуля и скажите «используй этот стиль». Это даёт ИИ конкретный референс, переопределяющий его обучение по умолчанию. При ревью проверяйте, что сгенерированный код мог быть написан тем же человеком, что и окружающий модуль.
Пункт чек-листа 4: Избыточная инженерия и ненужные абстракции
ИИ-модели имеют сильный перекос в сторону абстракций. Для простой задачи они часто генерируют иерархию классов, интерфейс, фабрику и три утилиты — там, где хватило бы одной функции. Эта склонность исходит из обучающих данных, где перепредставлены хорошо структурированные open-source библиотеки и недопредставлены простые скрипты и одноразовые функции.
ИИ-модели по умолчанию склонны к избыточной инженерии. Ваше ревью по умолчанию должно склоняться к простоте. Каждая абстракция, введённая ИИ, должна оправдывать своё существование перед более простой альтернативой.
При ревью спросите себя: нужен ли этому коду класс или хватило бы функции? Используется ли этот интерфейс более чем одной реализацией? Сэкономит ли вынесение этой утилиты достаточно повторений, чтобы оправдать косвенность? Если ответ на любой из этих вопросов «нет», ИИ, скорее всего, переусложнил, и простая версия лучше.
Пункт чек-листа 5: Уязвимости безопасности
ИИ-модели обучаются на коде, содержащем уязвимости безопасности. Они перенимают паттерны из этого кода, включая уязвимые. Хотя современные модели лучше избегают очевидных проблем вроде SQL-инъекций, они всё равно выдают код с тонкими проблемами безопасности, которые ревьюеру нужно ловить.
- Проверьте наличие захардкоженных секретов, API-ключей или учётных данных в сгенерированном коде.
- Убедитесь, что пользовательский ввод проверяется и санируется перед использованием.
- Проверьте, что проверки аутентификации и авторизации присутствуют в защищённых операциях.
- Убедитесь, что сгенерированные SQL-запросы используют параметризованные выражения, а не конкатенацию строк.
- Проверьте, что пути к файлам не конструируются из недоверенного ввода без санирования.
Проход ревью с фокусом на безопасность обязателен для кода, сгенерированного ИИ, который работает с чувствительными данными или пользовательским вводом. ИИ не знает, какие части вашей системы критичны с точки зрения безопасности, пока вы ему не скажете. В случае сомнений запустите статический анализатор поверх сгенерированного кода перед влитием.
Пункт чек-листа 6: Согласованность с существующей архитектурой
ИИ-модели видят каждый запрос изолированно. Они не знают, что ваша команда в прошлом квартале договорилась использовать React Query для всех запросов данных, что API всегда возвращает ключи в camelCase или что проект использует определённый паттерн управления состоянием. Сгенерированный код будет внутренне согласован, но может нарушать архитектурные решения, невидимые в текущем файле.
Именно здесь человек-ревьюер добавляет наибольшую ценность. Вы знаете решения, зафиксированные в ваших ADR, паттерны, возникшие из командных обсуждений, и дизайн-ограничения, не отражённые ни в одном файле. Проверяйте код, сгенерированный ИИ, на соответствие этим невидимым ограничениям, а не только на корректность и стиль.
Построение устойчивого процесса ревью
По мере того как ИИ генерирует всё большую часть вашей кодовой базы, процесс ревью должен масштабироваться. Команда из четырёх человек, вручную проверяющая каждую строку, написанную ИИ, выгорит. Устойчивый подход сочетает автоматические проверки с фокусированным человеческим ревью.
Автоматические проверки должны отлавливать галлюцинированные импорты, стилевые нарушения, отсутствующую обработку ошибок и типичные проблемы безопасности до того, как код вообще увидит человек. Это сводит ИИ-специфичное ревью к меньшему набору вопросов: архитектурная согласованность, дизайн-решения и тонкие проблемы, которые линтеры не могут обнаружить.
Цель — не исключить человеческое ревью кода, сгенерированного ИИ. Она в том, чтобы сделать это ревью максимально эффективным, отфильтровывая проблемы, которые инструменты могут ловить автоматически, и оставляя человеческое внимание для суждений, которые может вынести только человек. С правильным процессом ревью кода, сгенерированного ИИ, становится быстрее и надёжнее ревью кода, написанного человеком, — потому что ошибки ИИ более предсказуемы.
