Разработка с LLM без технического долга
Языковая модель пишет первую версию за часы. Проблема не в этом, а в том, что происходит через три месяца: приходит письмо «у меня не работает», вы открываете код и видите в нём чужой проект. Правило, которое закрывает эту ситуацию, одно: код, который вы не сможете починить ночью по логам, в прод не идёт.
Это не про недоверие к модели. Это про то, что в micro SaaS дежурный по проду — вы, и другого не будет.
Где модель экономит дни
Выигрыш реальный и он не в «написать за меня продукт», а в конкретных блоках:
| Задача | Что даёт модель | Риск |
|---|---|---|
| Чужой API по документации | вытаскивает ограничения и форматы за минуты | документация врёт, проверять запросом |
| Вёрстка лендинга | четыре блока и адаптив за час | лишние зависимости и мёртвый CSS |
| Конфиг деплоя, nginx, systemd | рабочий шаблон вместо чтения мануалов | права и секреты по умолчанию небезопасные |
| Разбор чужих выгрузок | парсер под кривой CSV за полчаса | молча съедает битые строки |
| Миграции и SQL | синтаксис без опечаток | удаляющий запрос без бэкапа |
| Текст, письма, тексты ошибок | черновик, который остаётся отредактировать | вода и обещания, которых продукт не даёт |
Свой пример: когда я разбирал двенадцать площадок для автопостинга, половина работы была не в коде, а в их особенностях. У LinkedIn токен требует ручной переавторизации раз в шестьдесят дней, у Bluesky ссылки в тексте размечаются по байтовым офсетам UTF-8 — с кириллицей это отдельное развлечение. Модель достаёт такие детали из документации за минуты. Дальше их всё равно надо проверить настоящим запросом: часть API ведёт себя не так, как написано.
Где модель создаёт долг
Долг появляется не от плохого кода, а от кода, за который никто не отвечает. Четыре типовых источника.
Слишком большой дифф. Вы просили поправить одну функцию, в ответ пришли семь файлов, новый слой абстракции и переименованные переменные. Такой дифф невозможно прочитать целиком, поэтому его принимают не читая — и именно он через месяц ломается.
Незаказанные зависимости. Модель охотно тянет библиотеку на задачу в десять строк. Каждая зависимость — это обновления, уязвимости и чужие поломки в вашем расписании.
Абстракции «на вырост». Интерфейс с одной реализацией, фабрика на один объект, конфиг для значения, которое никогда не менялось. Это выглядит как хорошая архитектура и работает как лишний слой, через который вы ночью продираетесь к настоящей ошибке.
Тихое проглатывание ошибок. try/except вокруг всего с пустым телом или
логом в никуда. Продукт не падает, а просто перестаёт делать то, за что
заплатили, и вы узнаёте об этом от клиента.
Правило приёмки
Практика, которая держит долг на нуле без замедления работы:
- Одна задача — один дифф. Не «сделай оплату», а «добавь обработчик вебхука, проверь подпись, верни 200». Задача формулируется так, что её результат можно прочитать за пять минут.
- Прочитать вслух. Если вы не можете объяснить дифф своими словами — он не принят. Не «переспросить у модели», а именно объяснить: понимание проверяется на выходе, а не на входе.
- Проверить не глазами, а запуском. Любая ветка, цикл и парсер получают один запуск на настоящих данных. Данные клиента всегда грязнее демо: пустые поля, лишние колонки, даты в трёх форматах.
- Диффы только в git. Каждый шаг — отдельный коммит с человеческим сообщением. Возможность откатиться на один шаг назад дороже любого рефакторинга.
- Зависимости — по списку. Новая библиотека добавляется, только если вы сами решили её добавить.
Это добавляет минут, а не часов. Модель по-прежнему пишет быстрее, чем вы, просто вы остаётесь тем, кто понимает результат.
Что не отдаётся модели без проверки
Список короткий и не режется никогда — он же перечислен в минимальном наборе первой версии:
- Деньги. Проверка подписи вебхука, идемпотентность, порядок «списали — выдали доступ». Сценарий «деньги ушли, доступ не появился» — худший из всех, и он пишется руками и тестом.
- Доступ и разграничение клиентов. Один клиент не должен видеть данные другого. Это проверяется отдельным тестом, а не чтением кода.
- Границы доверия. Всё, что приходит извне: формы, загруженные файлы, ответы чужих API. Валидация здесь не «на будущее», а обязательна.
- Секреты. Ключи в переменных окружения, не в репозитории и не в диалоге.
- Удаляющие миграции. Перед
DROPиDELETE— дамп, всегда. - Бэкапы и логи. Логи такие, чтобы по ним было видно, что делал конкретный клиент. Это ваш единственный инструмент в три часа ночи.
Как понять, что долг уже накопился
Признаки, каждый из которых виден без аудита:
- на баг из одной строки уходит вечер, потому что сначала надо вспомнить, как устроен модуль;
- вы боитесь трогать файл и обходите его новым кодом рядом;
- в проекте есть места, про которые вы говорите «оно как-то работает»;
- при ошибке в проде вы идёте читать код, а не логи;
- обновление одной библиотеки ломает две несвязанные функции.
Лечение одинаковое: изолировать или переписать. Изолировать — вынести в модуль с узким входом и выходом, чтобы непонятный код перестал быть в середине основного сценария. Переписать — своими руками, мелкими коммитами, с одним тестом на каждую ветку. Второй путь дороже на часы и дешевле на месяцы.
Чек-лист перед деплоем
- Каждый дифф прочитан и объясняется своими словами.
- Все внешние данные валидируются на входе.
- Сценарий оплаты покрыт тестом, включая ошибку провайдера.
- Секретов в репозитории нет.
- Логов достаточно, чтобы восстановить путь конкретного клиента.
- База копируется по расписанию, восстановление проверено хотя бы раз.
- Новых зависимостей нет — или каждая добавлена осознанно.
- Есть способ откатить деплой одной командой.
Семь из восьми — это не «почти готово», а «есть один способ потерять деньги или данные». Дешевле закрыть его сейчас.
Что модель не меняет
Спрос. Модель уверенно напишет лендинг сервису, который никому не нужен, и не остановит вас: проверка спроса по-прежнему делается разговорами и платёжной формой до кода. И ответственность: сгенерированный код ломается в проде так же, как любой другой, а платят человеку, который отвечает на письма и чинит баги за день.
Что из этого получается у меня и за какие сроки — в заметках и на странице проектов. Если у вас есть код, с которым вы уже боитесь остаться один на один, — напишите в телеграм, разберём, что там изолируется, а что переписывается.
Частые вопросы
Можно ли сделать micro SaaS, если сам почти не пишешь код?
Собрать первую версию — можно. Дожить с ней до сотого клиента — нет. Минимальный порог такой: вы читаете код и понимаете, что он делает, умеете смотреть логи и откатывать деплой. Писать с нуля необязательно, разбираться в написанном обязательно.
Как понять, что модель написала плохой код, если я не эксперт?
По трём признакам, которые видны без экспертизы: вы не можете объяснить своими словами, что делает функция; в диффе меняется больше файлов, чем вы просили; появились библиотеки, которых вы не заказывали. Любой из трёх — повод не принимать дифф, а разбить задачу мельче.
Стоит ли давать модели доступ к продовой базе или ключам?
Нет. Секреты живут в переменных окружения и в менеджере секретов, а не в контексте диалога и не в репозитории. Схему базы и обезличенные примеры данных показывать можно, боевые ключи и персональные данные клиентов — нельзя.
Нужны ли тесты, если продукт живёт пятьдесят часов?
Нужны в трёх местах: деньги, доступ и обработка внешних данных. Это несколько десятков строк, они окупаются на первом же изменении. Покрывать тестами вёрстку лендинга в первой версии смысла нет.
Что делать с кодом, который работает, но я его не понимаю?
Либо разобрать и переписать своими руками, либо изолировать: вынести в отдельный модуль с узким входом и выходом и обложить проверками. Худший вариант — оставить его в середине основного сценария и надеяться, что не сломается.