18 нояб. 2024 г.·7 мин чтения

ИИ-сгенерированный код: когда он помогает, а когда скрывает проблемы

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

ИИ-сгенерированный код: когда он помогает, а когда скрывает проблемы

Почему сначала кажется, что это очень быстро

ИИ-сгенерированный код в первые несколько дней кажется безопасным, потому что прогресс легко увидеть. Появляется экран. Форма отправляется. Отчёт загружается с реальными данными. Для небольшой команды это важно. Два человека могут за полдня сделать то, на что раньше уходила почти неделя.

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

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

Проблемы появляются на границах. Слабая архитектура редко возникает внутри одной страницы или одной функции. Она проявляется там, где одна часть продукта соприкасается с другой: auth, billing, permissions, очереди, общие данные, повторы, фоновые задания и сторонние API. В таких зонах есть правила, проблемы со временем и сценарии сбоев, которые сгенерированный фрагмент редко понимает целиком.

Небольшие команды обычно замечают это позже, когда на доработку уже не остаётся времени. Те же разработчики, которые быстро двигались вперёд, теперь вынуждены чинить странное поведение в production, искать дублирующуюся логику по файлам и распутывать код, который в одиночку выглядел нормально. Крупная компания ещё может какое-то время скрывать такие издержки. Команда из пяти человек обычно не может.

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

Где ИИ-сгенерированный код помогает небольшой команде

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

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

То же относится к заготовкам для тестов и вспомогательным скриптам для миграций. ИИ хорошо пишет первый черновик unit-тестов, seed-данных, mock-ответов и типового кода вокруг новой таблицы или поля. Он также может подготовить файлы миграции для обычных изменений схемы. Разработчику всё равно нужно проверить имена, крайние случаи и безопасность отката, но медленный первый проход уже не начинается с нуля.

Небольшие интеграции с фиксированными входными данными — ещё один хороший вариант. Например, форма, которая отправляет лид в CRM, webhook, который передаёт данные о заказе в бухгалтерский сервис, или скрипт, импортирующий строки CSV в известную схему. Когда поля стабильны, а поведение простое, архитектура обычно остаётся аккуратной, потому что сама задача узкая.

Больше всего это окупается на повторяемых шаблонах. Если у команды уже есть один хороший обработчик API, одно надёжное фоновой задание или один чистый шаблон страницы, ИИ может перенести этот шаблон на всю кодовую базу с неплохой последовательностью. Это важнее, чем просто скорость. Повторяемые шаблоны проще проверять, тестировать и потом заменять.

Простое правило помогает: пусть ИИ пишет скучный код после того, как человек определил форму. Если команда уже понимает, где живёт логика, как выглядит модель данных и как должны работать ошибки, ИИ часто экономит время и не оставляет после себя бардак.

Где он начинает скрывать слабую архитектуру

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

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

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

Вскоре код для checkout читает одну версию, админ-панель — другую, а фоновые задания — третью. Никто не планировал такого расхождения. Оно распространяется, потому что скопированная логика распространяется быстро. Один хелпер вставляют во второй сервис, потом в cron-задачу, потом в worker очереди. Небольшое несовпадение в одном месте превращается в несколько немного разных правил.

Повторы, очереди и пути сбоев быстрее всего показывают слабую структуру. Если запрос на платёж истекает по времени, приложение повторяет попытку, проверяет статус у платёжного провайдера или случайно создаёт второй платёж? Если задача падает после отправки части цепочки писем или после обновления одной таблицы, но не другой, у кода должно быть понятное правило восстановления.

Ненадёжные продукты часто показывают одни и те же признаки. Проверки авторизации появляются в контроллерах, middleware и случайных вспомогательных файлах. Правила billing протекают в UI-код вместо того, чтобы жить в одном сервисе. Worker-ы копируют бизнес-логику из веб-запросов. Обработка ошибок меняется от одного endpoint к другому.

Именно здесь помогает внешняя проверка. Сгенерированный код не всегда плохой. Проблема в том, что скорость может скрыть проблемы дизайна до тех пор, пока они не ударят по деньгам, доступу или доверию клиентов.

Как оценить функцию до генерации кода

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

Начните с одного предложения: какую задачу эта функция решает для пользователя? Держите формулировку узкой. «Показать ежемесячный отчёт по продажам для одного менеджера магазина» — ясно. «Улучшить отчётность» — нет. Такое предложение убирает шум и помогает быстрее заметить расползание объёма.

Потом обозначьте границы. Запишите, что функция может читать, что может менять и что должна оставить в покое. Страница отчёта может читать заказы и возвраты, но не изменять их. Поток оформления заказа может создавать заказы, резервировать товар и обращаться к платёжным сервисам. У этих сценариев совсем разный уровень риска, даже если в промпте оба звучат просто.

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

Нужен и дом для операционной логики. Решите, где будут логи, где будут тесты и кто отвечает за повторы при сбоях. Если подтверждение платежа не успело прийти вовремя, повторяет ли попытку фронтенд или этим занимается фоновой job? Если отчёт загружает устаревшие данные, где вы увидите это первым? Эти решения сильнее влияют на код, чем сам промпт.

Хорошо работает простое правило: не генерируйте код, пока этих заметок нет. Олег Сотников давно говорит об этом в работе с продуктом и архитектурой, в том числе в AppMaster.io. Генерация кода — это дешёвая часть. А вот разбор кода, который пересёк границы, скопировал правила данных или скрыл пути сбоя, и становится настоящим счётом.

Простой пример для продукта: страница отчёта против checkout

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

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

Такую страницу можно делать с неровностями, потому что ошибки быстро замечают. Её используют три коллеги. Они и так примерно понимают, какими должны быть цифры. Если что-то выглядит странно, они попросят исправление. Даже если код не красивый, нагрузка на поддержку остаётся низкой, и команда не теряет деньги каждую минуту, пока баг лежит в системе.

Checkout — полная противоположность. Он одновременно касается выручки, доверия и поддержки. Маленькая ошибка в checkout может дважды списать деньги с карты, применить не ту скидку, потерять заказ после оплаты или заблокировать клиента на мобильном устройстве. Команда платит за такой баг не один раз: потерянные продажи, работа с возвратами, сердитые письма и часы, потраченные на поиск причины.

Checkout также требует правил, которые ИИ-код легко размывает, если человек не задал их первым. Команде нужны чёткие шаги для налогов, проверки наличия, повторных попыток платежа, создания заказа, письма с подтверждением и обработки ошибок. Если эти правила живут только в разрозненных промптах и сгенерированных файлах, код может выглядеть готовым, а структура под ним останется шаткой.

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

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

Как обычно выглядит cleanup

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

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

То же самое происходит со структурой проекта. Похожий код оказывается в папках, которые выглядят по-разному, но делают почти одно и то же, например services/orders, modules/order и features/create-order. Название само по себе может быть нормальным. Проблема в том, что следующему разработчику приходится гадать, где находится настоящая логика заказа. ИИ часто добавляет ещё одну папку, которая в моменте кажется удобной, а через месяц — запутывает.

Исправления багов становятся дорогими очень обычным способом. Команда находит ошибку округления в итогах счёта и патчит первую же функцию, которую видит. Ошибка возвращается, потому что тот же расчёт был скопирован в admin endpoint, background worker и задачу экспорта CSV. Теперь команда чинит не один дефект, а ищет копии.

Прослеживание одного запроса тоже становится медленным. Простое действие вроде «создать аккаунт» должно легко читаться. Вместо этого запрос проходит через controller, helper, сгенерированный сервис, второй слой проверки, задачу в очереди и fallback-обработчик почти с тем же кодом. Каждый файл выглядит маленьким. Вместе они делают путь слишком сложным, чтобы ему доверять.

Поэтому cleanup обычно начинается со скучных решений. Выберите одно место для проверок. Выберите один шаблон папок и постепенно двигайтесь к нему. Удаляйте копии после каждого исправления, а не оставляйте их «на всякий случай». Если один запрос трудно проследить за 20 минут, это уже тревожный сигнал.

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

Ошибки, которые часто делают небольшие команды с ИИ-кодом

Ускорьтесь без хаоса
Используйте ИИ для скучных задач, а Олег поможет сначала выстроить архитектуру.

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

Первая ошибка — размытая ответственность. Один человек пишет промпт, другой вставляет результат, третий одобряет pull request, и никто не чувствует себя ответственным за поведение после релиза. Когда баг появляется в billing, auth или отчётности, команда теряет время, пытаясь понять, кто вообще достаточно хорошо знает код, чтобы его исправить.

Ещё одна частая ошибка — слишком рано принимать абстракции. ИИ любит генерировать слои: service classes, helpers, factories, wrappers и adapters. Часть из этого действительно нужна. Но многое — просто церемония вокруг простого кода. Если у функции один сценарий использования, обычная функция часто лучше, чем три файла и паттерн с красивым названием.

Команды также пропускают логи, потому что демо работает. Это плохой обмен. Чистое демо почти ничего не говорит о том, что происходит при реальном трафике, странных входных данных или частичных сбоях. Если checkout ломается у 3 процентов пользователей, а полезных логов нет, время, сэкономленное на генерации, исчезает за один день.

Тревожные признаки обычно легко заметить. Нет явного владельца у каждого сгенерированного модуля. Абстракции добавлены до того, как повторное использование доказало их необходимость. Слабые логи вокруг ошибок, повторов и внешних вызовов. Успех измеряется закрытыми задачами, а не стабильным поведением.

Последний пункт важнее, чем многие команды готовы признать. Закрытые задачи создают ощущение скорости, но пользователям всё равно, сколько карточек переехало по доске. Им важно, работает ли функция, может ли поддержка объяснить проблему и сможет ли команда изменить её на следующей неделе без страха.

Здесь тоже помогает внешняя проверка. Когда продукт продолжает двигаться вперёд, а структура становится всё мягче, человек с опытом в архитектуре обычно быстро замечает закономерность.

Короткая проверка перед объединением

Сначала план, потом промпт
Определите владение данными, пути ошибок и границы сервисов, прежде чем ИИ напишет ещё один файл.

ИИ-сгенерированный код может выглядеть готовым задолго до того, как его безопасно выпускать. Короткое ревью перед объединением экономит много cleanup позже, особенно маленькой команде, которая не может позволить себе неделями незаметно терять качество в production.

Начните с владения бизнес-правилами. Если окно возврата — 14 дней, это правило должно жить в одном понятном месте, а не одновременно в API, админ-панели и background job. Когда ИИ пишет код из нескольких промптов, он часто повторяет одно и то же правило в немного разных формах. Так и появляются баги.

Потом прочитайте названия. Хорошие названия звучат как сам продукт, а не как генератор. Если команда говорит «trial», «paid plan» и «expired account», код должен использовать те же слова. Когда названия расходятся, люди неправильно понимают поток и позже чинят не ту часть.

Полезная проверка перед объединением проста. Убедитесь, что каждое бизнес-правило имеет одного владельца в коде. Прочитайте тесты и посмотрите, есть ли там сценарии сбоя, а не только удачные случаи. Запустите одну или две ошибки и проверьте, что логи показывают, что именно сломалось и где. Потом попросите другого разработчика за несколько минут проследить запрос от входа до результата.

Этот последний шаг полезнее, чем кажется. Если другой человек не может быстро понять поток, проблема редко в его навыке. Скорее всего, код разрезан на слишком большое число хелперов, обёрток и сгенерированных файлов.

Простой пример это хорошо показывает. Допустим, экспорт отчёта ломается, когда файл слишком большой. В объединении должен быть тест на это ограничение, понятное сообщение об ошибке и логи, которые укажут на worker или endpoint, отказавший в обработке. Если единственное доказательство — «у меня на машине работало», ещё не объединяйте.

Такой ревью-процесс небольшой, но он ловит много слабой архитектуры ИИ-кода до того, как она начнёт распространяться.

Что делать дальше, если кодовая база уже кажется шаткой

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

Запишите этот поток простыми словами. Достаточно одной страницы: точка входа, слой сервисов, модель данных, внешние вызовы, тесты и точки сбоя. Команды обычно быстро находят проблему. Редко виноват сам ИИ-сгенерированный код. Проблема чаще в слабой границе, которая позволяет грязным решениям расползаться.

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

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

Если команда снова и снова упирается в одну и ту же стену, внешняя архитектурная проверка может сэкономить время. Полезная проверка описывает продукт, изучает workflow с ИИ и смотрит, не вынуждают ли решения по инфраструктуре писать неудобные пути в коде.

Это также тот момент, когда CTO на частичной занятости может помочь, не тормозя команду. Олег Сотников через oleg.is работает со стартапами и небольшими компаниями над архитектурой продукта, рабочими процессами разработки с ИИ и выбором инфраструктуры до того, как cleanup превращается в переписывание. Цель не в идеальном коде. Цель — в кодовой базе, где следующая функция занимает два дня вместо двух недель, и где одно исправление не ломает пять других путей.

Начните с одного потока, исправьте одну границу и сделайте следующий merge гораздо труднее испортить.

Часто задаваемые вопросы

Действительно ли ИИ-сгенерированный код полезен для небольшой стартап-команды?

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

Он перестаёт быть выгодным, когда feature затрагивает auth, billing, очереди или общие данные. Сначала пусть человек задаст форму, а потом ИИ заполнит скучные части.

Какие функции безопаснее всего делать с помощью ИИ-сгенерированного кода?

Лучше всего подходят внутренние страницы отчётов, админ-инструменты, CRUD-экраны, заготовки для тестов и простые задания на импорт или вебхуки. Такие функции следуют знакомым шаблонам и несут меньше риска, если что-то пойдёт не так.

Еженедельный отчёт по продажам — лучший кандидат для ИИ, чем checkout. Если баг просто мешает нескольким коллегам, его можно исправить без пожара в поддержке.

Каким функциям нужно больше человеческого проектирования, прежде чем использовать ИИ?

Checkout, billing, auth, permissions, retries, background jobs и всё, что связано с деньгами, требуют более медленной работы. Для таких потоков нужен один ответственный за каждое правило, один источник истины для данных и тесты на сценарии сбоя.

Если функция может списать деньги дважды, потерять заказ или дать не тот доступ, не позволяйте промптам придумывать структуру.

Почему ИИ-сгенерированный код в первую неделю кажется таким быстрым?

Потому что первая версия обычно покрывает только один успешный сценарий. Демонстрация работает, экран загружается, и к сложным случаям ещё никто не прикасался.

Настоящие проблемы всплывают позже: просроченные токены, дублирующиеся вебхуки, частичные сбои и скопированные правила в разных файлах. Ранняя скорость может скрыть слабую архитектуру.

Как оценить функцию, прежде чем просить ИИ написать код?

Сначала запишите одну фразу о том, какую задачу функция решает для пользователя. Потом отметьте, что она может читать, что может менять и что должна оставить в покое.

После этого укажите источник истины для каждого поля и решите, где будут retries, логи и тесты. Если вы не можете описать это простыми словами, код пока не генерируйте.

Какие проблемы с cleanup обычно всплывают позже в ИИ-сгенерированном коде?

Команды обычно находят одно и то же правило в нескольких местах. Проверки начинают расходиться, имена папок тоже, и один запрос начинает прыгать через слишком большое число хелперов и обёрток.

Исправления становятся медленнее, потому что скопированная логика прячется в endpoints, workers и exports. Вы перестаёте чинить одну функцию и начинаете искать клоны.

Что нужно проверить перед объединением ИИ-сгенерированного кода?

Проверьте, что каждое бизнес-правило живёт в одном месте. Затем прочитайте тесты и убедитесь, что там есть сценарии сбоя, а не только успешные случаи.

Запустите один или два ошибочных сценария и посмотрите, что именно упомянуто в логах. Если другой разработчик не может проследить запрос от входа до результата за несколько минут, остановитесь и упростите код до объединения.

Что делать, если кодовая база уже кажется хрупкой?

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

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

Когда небольшой команде стоит привлечь внешнюю архитектурную проверку?

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

Полезная проверка описывает один реальный поток, находит дублирующуюся логику и показывает, где сломались границы. Обычно это экономит больше времени, чем ещё один раунд латания.

Должен ли ИИ проектировать архитектуру или только писать код?

Используйте ИИ для реализации, а не для продуктовых и системных решений. Человек должен решить, где живёт логика, как движутся данные и что происходит при сбое.

Такой раздел даёт скорость без потери контроля. Олег Сотников часто работает с командами именно на этом этапе: сначала задаёт границы, а потом помогает использовать ИИ, чтобы двигаться быстрее внутри них.