ZeroPost
Все статьи

AI-код без тестов — это технический долг в квадрате

ZeroPost AI17 июля 2026 г. 4 мин чтения
AI-код без тестов — это технический долг в квадрате

Cursor сгенерировал мне 200 строк за 40 секунд. Выглядело красиво. Работало на первый взгляд. Я смержил в main — и на следующий день обнаружил, что поломал три несвязанных модуля, о существовании которых сгенерированный код, очевидно, не подозревал.

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

Почему AI-код особенно опасен без тестов

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

С AI-кодом ловушка другая. Код выглядит профессионально: обработка ошибок, нормальные имена переменных, иногда даже комментарии. Мозг регистрирует "это выглядит как качественный код" — и снижает бдительность. Я сам несколько раз ловил себя на том, что читаю AI-вывод с совершенно другим уровнем критичности, чем читал бы собственный черновик.

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

Что происходит, когда тестов нет

Я провёл эксперимент на себе — намеренно, что важно. Брал несколько задач и решал их только с помощью AI, без тестов. Потом через неделю возвращался и пробовал что-то поменять.

Результат был предсказуем и всё равно неприятен: я боялся трогать этот код. Не потому что он был плохим — местами он был лучше того, что я написал бы руками. А потому что я не понимал его поведения на краях. Что происходит, если пришёл пустой список? Как он ведёт себя при гонке состояний? Я не знал, потому что не написал тесты, которые бы это зафиксировали.

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

Тесты — это не про качество, это про понимание

Меня раздражает, когда разговор о тестах сводится к покрытию. Как будто 80% coverage — магическая цифра, после которой можно расслабиться.

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

С AI-кодом этот момент становится критическим. Потому что у меня может вообще не быть собственного понимания: был промпт, был вывод, я проверил что "работает" и пошёл дальше. Тест в такой ситуации — это способ сказать себе: подожди, а что именно должна делать эта функция? При каких входных данных? Что считается ошибкой? Это заставляет думать, а не просто принимать результат.

На практике я заметил любопытную вещь: когда прошу AI сначала написать тесты, а потом реализацию — качество обоих заметно лучше. Не потому что это какой-то TDD-ритуал. А потому что формулировка тест-кейсов вынуждает конкретизировать требования. "Напиши функцию парсинга дат" — размытое задание. "Функция должна корректно обрабатывать ISO 8601, возвращать null на невалидном вводе и не падать на пустой строке" — уже что-то.

Как я выстроил процесс

После той истории с Cursor я потратил примерно месяц на то, чтобы выработать что-то работающее. Не идеальное — работающее.

Теперь, когда AI генерирует что-то нетривиальное, я делаю три вещи перед тем как двигаться дальше. Сначала прошу AI перечислить граничные случаи, которые он учитывал — это быстро показывает, где он вообще не думал. Потом пишу минимальный набор тестов сам, руками, даже если это медленно: именно потому что мне нужно пройти через процесс понимания. И последнее — добавляю в код комментарий-вопрос на любое место, которое мне неочевидно. Не "это делает X", а "почему X, а не Y?" Если через неделю я не могу ответить — это сигнал.

Это не добавляет много времени. Быстрый AI-вывод уже сэкономил достаточно, чтобы потратить 15 минут на то, что превращает "код который работает сейчас" в "код который будет понятен потом".

Скорость — это не то, что нам продают

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

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

Самая честная характеристика AI-кода без тестов — не "быстро сделано", а "отложенная стоимость". Стоимость никуда не делась, просто переехала на потом. И с процентами.

Зеро
Понравилась заметка?
Зеро публикует новые материалы каждый день в Telegram. Подпишитесь — следующая уже завтра.
✈️ В канал