Vibe coding обычно описывают как разработку, в которой человек формулирует намерение, а модель превращает его в работающий код. Это удобно для прототипа и опасно как процесс поставки. Чем быстрее появляется результат, тем легче пропустить момент, когда задача незаметно изменилась: модель добавила зависимость, перенесла ответственность между слоями, ослабила проверку или создала второй источник истины.
Проблема не в том, что AI «пишет плохой код». Люди делают то же самое. Проблема в асимметрии скорости: модель производит больше изменений, чем человек способен внимательно проверить за то же время. Поэтому качество определяется не силой модели, а пропускной способностью контура контроля вокруг неё.
Сначала контракт задачи
Перед обращением к агенту зафиксируйте четыре вещи: наблюдаемое поведение, границы изменений, запрещённые действия и команду проверки. «Добавь поиск» — слабая постановка. «Фильтруй шесть локальных статей по заголовку, не добавляй сервер и новую зависимость, неизвестный запрос показывает пустое состояние; проверка — такие-то тесты» — рабочий контракт.
- Поведение: что пользователь сможет сделать после изменения.
- Поверхность: какие файлы, сервисы и данные разрешено менять.
- Инварианты: что обязано остаться совместимым и безопасным.
- Доказательство: тест, сборка, анализ diff или воспроизводимый сценарий.
MCP — не магия, а граница полномочий
Model Context Protocol связывает AI-приложение с инструментами и данными через host, clients и servers. Полезная часть архитектуры — не универсальный разъём сам по себе, а возможность выдавать узкие способности: прочитать конкретную документацию, проверить задачу, получить схему или выполнить ограниченную операцию. Сервер не должен автоматически видеть весь разговор и все соседние источники.
Практически это означает принцип наименьших привилегий. Инструмент чтения репозитория не обязан уметь пушить. Проверка календаря не должна создавать встречу. Доступ к production-логам не требует возможности менять переменные окружения. Чем конкретнее интерфейс инструмента, тем меньше агенту приходится угадывать и тем легче человеку оценить последствия вызова.
Тест задаёт намерение, diff показывает цену
Для новой функции сначала нужен тест, который падает по ожидаемой причине. После минимальной реализации он должен пройти, а весь набор проверок — остаться зелёным. Эта последовательность важна: тест, написанный после кода, легко подгоняется под уже выбранное решение и может никогда не доказать, что ловит ошибку.
После тестов нужен просмотр diff. Ищите не стиль, а изменение ответственности: откуда теперь берутся данные, кто валидирует ввод, где обрабатывается ошибка, какие права появились, не возник ли новый сетевой запрос или зависимость. Хороший diff мал, объясним и содержит только то, что требуется контрактом задачи.
- Красный тест падает из-за отсутствующего поведения, а не из-за опечатки.
- Минимальный код делает тест зелёным без скрытого расширения scope.
- Сборка, типы и линтер проверяются отдельными командами.
- Новая зависимость объясняется реальной необходимостью и фиксируется в lock-файле.
- Критические права и внешние действия требуют подтверждения человека.
Где человек остаётся владельцем решения
Модель может предложить архитектуру, но не знает реальную стоимость миграции и допустимый риск бизнеса. Она может сгенерировать SQL, но не должна самостоятельно решать, какие данные можно удалять. Она может подготовить письмо, но отправка внешнему адресату — отдельное действие. Полезное разделение простое: AI исследует и исполняет, человек утверждает необратимые последствия и критерии готовности.
Для кода такими воротами становятся изменения схемы, прав доступа, биллинга, аутентификации, внешних сообщений и production-развёртывания. Для каждого воротного действия заранее определите владельца, проверку и способ отката. Это не бюрократия, а ограничитель скорости именно там, где ошибка дорога.
Практический процесс на одну задачу
- Сформулируйте контракт и прочитайте существующий код до генерации.
- Дайте агенту только необходимый контекст и узкие инструменты.
- Попросите сначала добавить падающий тест и покажите ожидаемую причину падения.
- Разрешите минимальную реализацию, затем запустите полный набор проверок.
- Просмотрите diff по границам данных, правам, ошибкам и зависимостям.
- Сделайте небольшой коммит и только после него переходите к следующему поведению.
Vibe coding становится инженерным инструментом, когда «ощущение готовности» заменяется наблюдаемым доказательством. Скорость модели тогда не конфликтует с качеством: она расходуется на маленькие итерации, а не на производство большого объёма непроверенного кода.
Как внедрить процесс в команде
Начните не с общего разрешения «пользоваться AI», а с одного класса низкорисковых задач: тесты для существующего поведения, документация, небольшие интерфейсные изменения или локальный рефакторинг без смены контракта. На десяти задачах замерьте время до готового результата, размер diff, число возвратов с ревью и дефекты после слияния. Сравнивать нужно завершённую работу, а не минуты до первого сгенерированного файла.
Для повторяемости сохраните короткий шаблон задания: цель, разрешённые файлы, инварианты, команды проверки и условие остановки. Рядом нужен журнал решений: какую зависимость добавили, почему отвергли альтернативу, где человек принял риск. Такой след помогает следующему ревьюеру восстановить намерение и не превращает чат с моделью в единственное место, где существует контекст.
- До начала: владелец формулирует поведение и уровень риска.
- Во время работы: агент останавливается при выходе за разрешённую поверхность.
- Перед слиянием: другой человек проверяет diff и доказательства, а не пересказ модели.
- После выпуска: дефект связывают с пропущенным контролем и улучшают процесс, а не только промпт.
Отдельно учитывайте ложную экономию. Если разработчик получил код за десять минут, но два часа разбирал скрытую связь, ускорения не произошло. Хорошая метрика — доля задач, которые прошли с первого ревью и не потребовали отката. Она дисциплинирует и автора запроса, и пользователя инструмента: маленькая область, ясный тест и видимая цена изменения дают больше скорости, чем попытка получить целую функцию одним сообщением.