Урок 3

Совет — зная это, вы уже можете командовать

Четыре фразы — это всё.

Агенту: “Создай Hurl-тест” ИИ напишет контракт, проверяющий правильность работы функции. Plain text, который можно прочитать без навыков программирования.

Агенту: “Добавь эту функцию. Но существующие Hurl-тесты должны проходить” Эта одна фраза предотвращает дрифт. Если ИИ при добавлении новой функции сломает существующую — Hurl сообщит красным текстом.

Агенту: “Закоммить” Сохранение рабочего состояния. Как точка сохранения в игре. Если следующая задача провалится — возврат сюда.

Агенту: “Откати” Возврат к последней точке сохранения. Восстановление того, что ИИ сломал.

Паттерн этих четырёх фраз

Функция готова → “Создай Hurl-тест” → Проверка прохождения → “Закоммить” → Следующая функция → “Существующие Hurl должны проходить” → При проблеме “Откати”

Это храповик. Шестерёнка, идущая только вперёд. Будь функций 5 или 50 — существующие не ломаются.

Почему это работает?

В уроке 2 мы узнали: дайте ИИ мнение — получите лесть, дайте факт — получите исправление. То, что возвращает Hurl — не мнение, а факт. “test failed: status 401, expected 200” — здесь нечему льстить.

Быстрый старт

Создайте один Hurl-тест для приложения задач из практики урока 2. Это займёт 3 минуты.

Агенту: “Напиши Hurl-тест, проверяющий правильность работы текущей функции добавления задач”

ИИ создаст файл .hurl.

Агенту: “Запусти Hurl-тест”

Если прошёл — зелёный. Теперь намеренно сломаем.

Агенту: “Переименуй id в todo_id в ответе API добавления задач”

Агенту: “Запусти Hurl-тест”

Красный текст — провал. Это обнаружение дрифта.

Агенту: “Откати”

Снова зелёный. Вот суть храповика.


Почему нужно командовать именно так

В уроке 2 мы увидели проблемы: логический дрифт, потеря контекста, предвзятость лести. После 5 функций существующие ломаются, а ИИ ложно заявляет “всё работает”.

В этом уроке мы изучим три инструмента для предотвращения. Все они десятилетиями используются инженерами. Не нужно уметь читать код. ИИ пишет и запускает. Вам достаточно спросить: “Прошло?”

Роли трёх инструментов:

ИнструментАналогияЧто делает
HurlКонтрактОбъявляет “эта функция должна работать так”
GitТочка сохраненияГарантирует “можно вернуться к этому моменту”
CI/CDАвтоматическая камера наблюденияМеханизирует “проверяется каждый раз автоматически”

Hurl — объявление API-контракта в plain text

Что такое Hurl

Hurl — это файл, описывающий “как должен работать этот API”.

По аналогии с игрой: в RPG покупка зелья у NPC имеет правило “1 зелье → -50 золота, +100 здоровья”. Hurl проверяет, что это правило не изменилось после патча.

Реальный файл Hurl:

# Добавление задачи
POST http://localhost:8080/api/todos
{
  "title": "Купить молоко",
  "priority": "high"
}
HTTP 201
[Asserts]
jsonpath "$.id" exists
jsonpath "$.title" == "Купить молоко"
jsonpath "$.priority" == "high"
jsonpath "$.completed" == false

Читается даже без навыков программирования:

  • POST — запрос “добавь” серверу
  • http://localhost:8080/api/todos — адрес списка задач
  • { “title”: “Купить молоко” } — отправляем такие данные
  • HTTP 201 — при успехе должен прийти ответ 201
  • jsonpath “$.title” == “Купить молоко” — в ответе должно быть “Купить молоко”

Это контракт. “При добавлении задачи приходит 201, название и приоритет возвращаются как есть.” Если контракт нарушен — Hurl сообщает красным текстом.

Ещё один пример:

# Доступ без авторизации — отказ
GET http://localhost:8080/api/todos
HTTP 401

“При доступе к списку задач без логина должен прийти 401 (требуется аутентификация).” Это тоже контракт. Если ИИ “наведёт порядок” в коде авторизации и сломает это правило — Hurl поймает мгновенно.

Почему Hurl — отличие от юнит-тестов

“Инструментов тестирования много, почему именно Hurl?” Для вайб-кодера есть особая причина.

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

Hurl — иначе. Он проверяет на входе. Отправляет запрос, проверяет ответ. Не знает внутреннюю структуру кода. Как бы ИИ ни менял код — если наблюдаемое поведение такое же, тест проходит, если другое — провал.

Юнит-тестыHurl
АналогияРазборка деталей двигателяДорожные испытания
Если ИИ меняет кодТест тоже может изменитьсяТест остаётся, проверяется только результат
Сложность чтенияНужно знать кодЧитается как обычный текст
Обнаружение дрифтаЕсли ИИ изменит и тест — пропуститНезависим от кода, обнаруживает естественно

Hurl проверяет не код, а поведение. Код ИИ может менять свободно. Поведение меняться не должно. Это различие — ключ к обнаружению дрифта.

Почему это эффективно — доказано исследованиями

В уроке 2 мы узнали о предвзятости лести. Совет “пиши тесты” тоже зависит от формулировки.

Исследование TDAD (Test-Driven AI Development, 2026) точно это проверило. ИИ исправлял баги при разных условиях тестирования:

УсловиеРегрессия (% поломки существующих функций)
Базовое (без указаний по тестам)6,08%
Процедурное указание “делай TDD”9,94% (ухудшение!)
Предоставление файла затронутого теста в контексте1,82% (снижение на 70%)

Удивительный результат. “Делай TDD” — ухудшает. ИИ путается, пытаясь следовать процедурному указанию. Но “этот тестовый файл должен проходить” — конкретный контекст — снижает регрессию на 70%.

Разница ясна:

  • “Разрабатывай с тестами” → процедурное указание → ИИ путается
  • “Этот Hurl-файл должен проходить” → конкретный контракт → регрессия -70%

Не указание метода, а контракт — что должно проходить. Именно об этом “фраза 3” выше.

Git — точка сохранения с возможностью отката

Что такое Git

В играх делают сохранения. Перед боссом — сохранение, проиграли — загрузка.

Git — это функция сохранения для кода. “Сейчас всё работает” → сохранение (коммит). Следующая задача провалилась → возврат к предыдущему сохранению.

Вайб-кодинг без Git:

Функция 1 → работает
Функция 2 → работает
Функция 3 → функция 1 сломалась!
→ Хочу откатить... а какое было состояние функции 2?
→ ИИ: "вернуть к тому, что было" → ИИ не знает, что было "то"
→ Начинаем сначала

С Git:

Функция 1 → работает → коммит (сохранение 1)
Функция 2 → работает → коммит (сохранение 2)
Функция 3 → функция 1 сломалась!
→ "Вернись к сохранению 2" → функции 1 и 2 работают
→ Пробуем функцию 3 другим способом

Git: достаточно двух слов

Не нужно учить десятки команд Git. Вайб-кодеру нужны две вещи.

“Закоммить” — сохранить текущее состояние

"Закоммить текущее состояние. Сообщение — 'Функция добавления задач готова'"

“Откати” — вернуться к предыдущему состоянию

"Откати к последнему коммиту"

Когда коммитить

Правило простое:

  1. Функция готова и работает → коммит
  2. Все Hurl-тесты проходят → коммит
  3. Перед началом следующей функции → обязательно коммит

Без коммита — при проблеме некуда вернуться. Как 3 часа игры без сохранения.

Аналогия Git: базовые лагеря при восхождении

На Эверест не лезут за один раз. Базовый лагерь → Лагерь 1 → Лагерь 2 → … → вершина. В каждом лагере ставят палатку и накапливают запасы. При плохой погоде спускаются в предыдущий лагерь. Без лагерей в шторм — гибель.

Git-коммиты — это лагеря. При каждой готовой функции — лагерь. Если ИИ сломает следующую функцию — можно вернуться в предыдущий.

CI/CD — машина охраняет автоматически

Что такое CI/CD

CI (Continuous Integration) — автоматический запуск тестов при каждом обновлении кода. CD (Continuous Deployment) — автоматический деплой при прохождении тестов.

Сейчас достаточно знать CI. CD — потом.

Без CI:

Вы:      "Добавь функцию"
ИИ:      "Готово!"
Вы:      (на экране проверяете только новую функцию) "Работает!"
→ Не замечаете, что существующая функция сломана

С CI:

Вы:      "Добавь функцию"
ИИ:      (пишет код)
Машина:  (автоматически запускает все Hurl-тесты)
Машина:  "Тест логина провален!"
Вы:      "Логин сломан. Почини."
ИИ:      (исправляет)
Машина:  "Все тесты пройдены"
Вы:      "Закоммить"

Вам не нужно запускать Hurl-тесты вручную каждый раз. Машина делает это автоматически.

CI как пожарная сигнализация

В здании есть пожарная сигнализация. При пожаре — автоматически срабатывает. Охранник не нужен для круглосуточного обхода.

CI — пожарная сигнализация кода. Если Hurl-тесты ломаются — автоматическое уведомление. Вам не нужно проверять вручную каждый раз.

Три инструмента вместе: храповиковая фиксация

Hurl + Git + CI дают храповик (ratchet). Храповик — шестерёнка, вращающаяся только в одну сторону. Повернул — вперёд, отпустил — стоит, но назад не идёт.

Функция 1 готова → Hurl-тест → всё проходит → коммит → фиксация
Функция 2 готова → Hurl-тест добавлен → старые + новые проходят → коммит → фиксация
Функция 3 в работе → старый Hurl-тест провален → коммит отклонён → исправление → всё проходит → коммит → фиксация

Правила просты:

  1. Прошедший Hurl-тест — фиксируется
  2. Зафиксированные тесты нельзя удалять/менять
  3. При новой функции — новый Hurl-тест тоже
  4. Все старые + все новые тесты должны пройти для коммита

Если сказать ИИ “отрефактори код”, ИИ свободно меняет код. Но если Hurl-тест провалится — коммит отклоняется. ИИ обязан сохранять всё существующее поведение.

Это точно совпадает с результатом исследования TDAD. Не процедурное указание “пиши тесты”, а конкретный контракт “этот Hurl-файл должен проходить”. Агент может выбирать метод, но не может нарушить контракт.

Как решаются проблемы урока 2

Проблема урока 2Решение урока 3
Логический дрифтHurl защищает существующее поведение. Поведение изменилось — провал
Потеря контекстаHurl-файлы сохраняют решения навсегда. Сессия сменилась — контракт остался
Предвзятость лести (“всё готово”)CI судит механически. Не самоотчёт ИИ, а pass/fail
Смешение решений и реализацииHurl объявляет решения (поведение) в отдельном файле от кода
Умножение деградацииХраповиковая фиксация на каждом шаге сбрасывает деградацию

Итоги

Что мы изучили:

  1. Hurl — объявляет контракт “должно работать так” в plain text. Проверяет не код, а поведение
  2. Git — создаёт точку сохранения “можно вернуться”
  3. CI/CD — устанавливает механическую проверку “автоматически каждый раз”
  4. Храповик — три вместе дают “прошёл — зафиксирован, назад не идёт”

Ключевой принцип:

Не указывайте ИИ метод. Дайте контракт — что должно проходить.

“Делай TDD” → регрессия ухудшается. “Этот Hurl должен проходить” → регрессия -70%. Разница между указанием и контрактом.

Не меняйте модель, добавьте контракт.


Анонс следующего урока

В уроке 3 мы научились защищать каждый API через Hurl. Но при росте проекта защищать нужно не только API. Структура БД, политики безопасности, UI-компоненты — всё должно быть согласовано.

В уроке 4 изучим yongol. Управление API, БД, безопасностью, UI через единую декларативную спецификацию. Перенос объекта работы ИИ с кода на спецификацию. Метод преодоления барьера 200 эндпоинтов.


Связанные статьи


Полный курс Reins Engineering

УрокНазвание
Урок 0Установка Claude Code
Урок 1Как командовать ИИ
Урок 2Как не доверять ИИ
Урок 3Нерушимое приложение
Урок 4Решения — за пределы кода
Урок 5ИИ на поводьях
Урок 6Прошёл — зафиксировал
Урок 7Как обратить лесть
Урок 8Фабрика агентов
Урок 9Автоматизация за пределами кода
Урок 10Закон данных
Урок 11Как спасти провалившийся vibe coding

Источники

  • TDAD (Test-Driven AI Development) 2026 — процедурное указание “делай TDD” ухудшает регрессию до 9,94%, предоставление тестового файла в контексте снижает регрессию до 1,82% (-70%)
  • Эксперимент Ratchet Pattern — автономный агент 40/527 (7,6%) vs храповик CLI 527/527 (100%), та же модель, разница в том, кто определяет завершение

История изменений

  • 2026-05-24: Первая версия