AI-разработка: от вайбкода до своих рук
Проверяем, а не верим
Тест — это записанное обещание: как предсказывать результат до запуска и заставить агента доказывать, что всё работает.
Проверяем, а не верим
Вернёмся к странице из урока «Первый проект за вечер». Допустим, вы попросили агента добавить туда форму «напишите мне»: имя, e-mail, поле для сообщения, кнопка «Отправить». Агент ответил «Готово, форма работает». Вы открыли страницу, вписали своё имя и настоящий адрес, нажали кнопку — появилось «Спасибо, сообщение отправлено». Выглядит отлично. Вы показали страницу знакомому.
Знакомый сделал то, чего вы не делали. Нажал «Отправить», ничего не заполнив, — «Спасибо, сообщение отправлено». Пустое письмо ушло. Потом ввёл адрес anna@ — обрубок без домена. Форма приняла и его.
Демо проверяет один путь. Жизнь ходит остальными
Что произошло на самом деле? Вы проверили форму ровно одним способом — тем, которым пользуется аккуратный человек с правильными данными. У такого сценария есть имя: happy path, «счастливый путь». Всё заполнено, всё корректно, никто никуда не спешит.
Но у формы путей гораздо больше. Пустые поля. Адрес с опечаткой. Текст на десять тысяч знаков, вставленный из документа. Двойной клик по кнопке от нетерпения. Каждый из этих путей кто-нибудь обязательно пройдёт — не назло, просто люди пользуются программами по-разному.
Агент, кстати, тоже проверял happy path — если вообще что-то проверял. Его «форма работает» означает «я написал код, который, по моим представлениям, должен работать». Это прогноз, а не результат проверки.
Отсюда и разница, вынесенная в заголовок урока. «Выглядит работающим» — один путь прошёл у вас на глазах. «Работает» — проверены и те пути, которыми пойдут другие люди.
Ловить такие дыры после того, как их нашёл знакомый, поздно и обидно. Нужен способ находить их раньше — и начнём с привычки, которая не требует ни строчки кода.
Скажите, что должно произойти, — до запуска
Приём простой. Перед тем как нажать кнопку, сформулируйте вслух или в заметке: «Сейчас я отправлю форму с пустым сообщением. Должна появиться надпись "Введите сообщение", и письмо уйти не должно».
Потом нажмите и сравните.
Исходов два. Совпало — хорошо, одна дорожка проверена, идём дальше. Не совпало — это сигнал. С ним надо что-то делать: либо чинить код, либо признать, что вы сами не знали, как программа должна себя вести. Второе случается чаще, чем кажется, и это тоже полезное открытие: пока ожидание не сформулировано, его не с чем сравнивать.
Формулировать надо именно до запуска, и вот почему. Если сначала посмотреть на результат, мозг услужливо подстроит ожидание под увиденное: «ну, наверное, так и задумано». Расхождение исчезнет — не потому что его нет, а потому что вы его не зафиксировали. Предсказание, произнесённое заранее, отрезает этот путь к самообману. А что делать с самим расхождением, вы уже умеете: читать сообщение об ошибке мы учились в уроке «Почему сломалось».
У привычки есть потолок. Предсказание живёт у вас в голове и к вечеру умирает. Случаев уже три, завтра будет десять, и прогонять их руками после каждой правки вы не станете — честно, не станете, никто не станет. Хочется, чтобы предсказания были записаны и проверяли себя сами.
Тест — обещание, записанное кодом
Тест — это маленькая программа, которая проверяет другую программу. То же самое предсказание — «если отправить пустую форму, покажется ошибка» — только записанное так, чтобы его мог выполнять компьютер. Столько раз, сколько нужно, и без вашего участия.
Вот такой тест целиком. Не пугайтесь, сейчас прочитаем его по-русски:
test('пустое сообщение не проходит', () => {
const result = checkForm({ email: 'anna@example.com', message: '' });
expect(result.ok).toBe(false);
expect(result.error).toBe('Введите сообщение');
});
Построчно:
test('пустое сообщение не проходит', ...)— объявляем обещание и даём ему имя. Имя — обычная фраза, она для людей.checkForm({ ... message: '' })— вызываем проверку формы с пустым сообщением. Это то же «нажать отправить, ничего не заполнив», только без браузера и без рук.expect(result.ok).toBe(false)— «ожидаю, что форма ответила отказом». Слово expect так и переводится: «ожидаю».expect(result.error).toBe('Введите сообщение')— «и ожидаю, что текст ошибки именно такой».
Если все ожидания сошлись, тест зелёный: [OK]. Если хоть одно разошлось — красный: [ERROR], с указанием, что ожидалось и что пришло на самом деле. То самое сравнение предсказания с реальностью из прошлого раздела, только выполняет его машина.
Писать такое самому не нужно — скоро увидим, кто напишет. А вот читать нужно уметь: тест читается как предложение на почти русском языке, и это его главное свойство.
Раз писать тесты будете не вы, а агент, — что тогда остаётся вам? Самая содержательная часть работы.
Ваша работа — назвать случаи и прочитать ответ
Агент хорошо пишет тесты, когда ему сказали, что именно проверять. Без этого он охотно выдаст десяток тестов на happy path — все пройдут с первого раза и ничего не поймают.
Назовите случаи сами. Для нашей формы:
- Пустое сообщение — должна быть ошибка «Введите сообщение».
- Адрес без
@или обрубок вродеanna@— ошибка «Проверьте адрес». - Текст на десять тысяч знаков — форма не должна ни зависнуть, ни молча обрезать письмо.
И попросите примерно так:
Напиши тесты на эти три случая.
Запусти их и покажи, что сейчас они падают.
Потом исправь код и покажи, что все три проходят.
Просьба «покажи, что падают» — не придирка. Тест, который ни разу не был красным, сам никем не проверен: возможно, он проходит всегда, что бы ни творилось в коде. Красный до исправления и зелёный после — доказательство, что тест смотрит в нужное место.
Когда агент принесёт тесты, прочитайте их как чеклист:
- Имена тестов совпадают с вашими случаями? Если случаев три, а тестов про них два — где третий?
- Ожидания проверяют суть? «Функция что-то вернула» — не проверка. «Вернула отказ с текстом "Проверьте адрес"» — проверка.
Если тесты пролистать и кивнуть не читая, они превращаются в декорацию: строчки есть, защиты нет. Читать их вы уже умеете — мы только что делали это построчно.
Остался психологический момент. В первый раз, когда прогон окрасится красным, будет неприятно — как будто вас поймали на ошибке.
Красный тест — друг
Поменяйте знак у этого чувства. Красный тест означает: проблема найдена сейчас, на вашей машине, за минуту до исправления. Та же проблема, найденная знакомым — а позже настоящим пользователем, — обходится дороже: пользователь не напишет вам подробное письмо, он молча решит, что «тут всё сломано», и закроет вкладку. Красный тест — самый дешёвый из всех способов узнать плохую новость.
И второе свойство, ради которого всё затевалось: тесты остаются. Завтра агент переделает форму и, сам того не заметив, заденет проверку адреса. Дифф из урока «Код, который ты не читал» покажет, что изменилось; тесты покажут, уцелели ли при этом записанные обещания. Ваше ручное демо жило один вечер — обещания проверяются при каждой правке, автоматически.
Теория закончилась. Перенесём её на ваш проект.
Практика: три обещания для вашей страницы
Возьмите страницу, которую вы собрали в уроке «Первый проект за вечер».
- Выберите на ней одну интерактивную вещь: форму, кнопку, поле ввода — что есть.
- Запишите три предсказания обычным русским языком: одно про правильный сценарий и два про кривые. Например: «если нажать кнопку дважды подряд, действие выполнится один раз, а не два».
- Отдайте их агенту тем же промптом (prompt — текстовая просьба агенту), что выше: напиши тесты — покажи красные — исправь — покажи зелёные. Claude Code, Cursor, Copilot — интерфейс не важен, просьба одна и та же.
- Прочитайте тесты вслух, как мы читали
checkForm. Если какую-то строчку пересказать по-русски не выходит — спросите агента, что она проверяет. Это рабочий вопрос, а не признак слабости.
Критерий выполнения:
- [OK] три случая назвали вы, а не выбрал агент
- [OK] вы своими глазами видели тесты красными, а потом зелёными
- [OK] каждый тест вы можете пересказать одним предложением
Что дальше
Теперь у проекта есть записанные обещания, и агент обязан их выполнять — не на словах, а прогоном тестов. Но у этой защиты есть условие, о котором пока не было речи: проверки работают, пока в проекте можно ориентироваться. Когда агент несколько вечеров подряд складывает код куда получится, наступает момент, когда тест красный, а вы не можете найти ни сам тест, ни код, который он проверяет. Файлов тридцать, названия загадочные, половина, кажется, вообще не используется.
Как не дать проекту превратиться в свалку — файлы, структура и постоянные инструкции агенту — в следующем уроке: «Порядок в проекте».