TDD-цикл с Vibe Codex: красный, зелёный, рефакторинг
Лучший AI-ассистент для TDD — тот, который сначала признаётся, что тест падает, и только потом предлагает решение.
TDD страдает от той же болезни, что и большая часть инженерных практик: «теоретически — да, на проекте — некогда». Vibe Codex меняет расклад: цикл «красный → зелёный → рефакторинг» проходится за три-пять минут вместо двадцати, и поэтому фактически делается.
Красный: формализуем поведение
TDD начинается не с теста, а с описания: «что должно произойти?». Пока есть устная формулировка, теста ещё нет.
$ vibe-codex tdd "функция normalizePhoneRu принимает строку, \
возвращает E.164 для российских номеров; \
если не получается — null"
Ассистент уточняет:
[opus] Уточнения:
- +7XXXXXXXXXX и 8XXXXXXXXXX — оба валидные?
- пробелы, скобки, дефисы — игнорировать?
- короткие номера (112, 911) — null или ошибка?
- КZ-номера (+77XXXXXXXX) — null (не российские)?
[me] да / да / null / null
[opus] ок, генерирую тесты.
// pkg/phone/phone_test.go
func TestNormalizePhoneRu(t *testing.T) {
cases := []struct {
in, want string
}{
{"+79161234567", "+79161234567"},
{"89161234567", "+79161234567"},
{"+7 (916) 123-45-67", "+79161234567"},
{"8 916 123 45 67", "+79161234567"},
{"112", ""}, // null
{"abc", ""}, // null
{"+77011234567", ""}, // KZ, null
}
for _, tc := range cases {
if got := NormalizePhoneRu(tc.in); got != tc.want {
t.Errorf("for %q got %q, want %q", tc.in, got, tc.want)
}
}
}
$ go test ./pkg/phone
FAIL ./pkg/phone [build failed]
Идеально. Тест падает — потому что функции ещё нет.
Зелёный: минимальная реализация
Хороший ассистент знает, что «минимальная» — это буквально минимальная. Не «правильная архитектурно», а «делает тесты зелёными».
$ vibe-codex tdd green
[opus] Генерирую минимальную реализацию:
- удаляем не-цифры
- проверяем длину 11 и первую цифру
- заменяем 8 на 7
[written] pkg/phone/phone.go
package phone
import "strings"
func NormalizePhoneRu(in string) string {
digits := strings.Map(func(r rune) rune {
if r >= '0' && r <= '9' {
return r
}
return -1
}, in)
if len(digits) != 11 {
return ""
}
if digits[0] == '8' {
digits = "7" + digits[1:]
}
if digits[0] != '7' {
return ""
}
return "+" + digits
}
$ go test ./pkg/phone
PASS
ok ./pkg/phone 0.012s
Рефакторинг: имя, структура, инварианты
Здесь ассистент делает то, что обычно скучно: вынести магические числа, добавить комментарии где это правда нужно, проверить читаемость.
$ vibe-codex tdd refactor
[opus] Предложения:
- вынести len(digits) != 11 в константу phoneLen
- выделить isDigit в отдельную функцию или использовать
unicode.IsDigit
- добавить doc-comment на функцию
[diff] +12 -8
Заметьте — рефактор маленький. Это правильно: большой рефакторинг ломает фокус.
Где TDD-цикл ломается без аккуратности
«Самая лёгкая ошибка — попросить ассистент сделать „красный→зелёный“ одной командой. На выходе вы получите тест, написанный под уже существующую реализацию».
- Никогда не давайте генерировать тесты и реализацию в одном промпте. Это перестаёт быть TDD.
- Сначала тест, проверяете глазами, что он осмысленный, потом запускаете
tdd green. - На рефакторинге запускайте тесты после каждой правки. Vibe Codex может это делать сам в режиме
--watch. - Для багов цикл такой же: воспроизвели тестом, попросили зелёный, рефакторнули.
Багфикс по TDD
Это любимый кейс. Пришёл баг — пишем тест, который его воспроизводит:
$ vibe-codex tdd bug "после ребута сервиса баланс пользователя \
показывается на 100 рублей меньше"
[opus] Гипотезы:
1) кеш не сбрасывается;
2) транзакция баланса не зафиксирована до рестарта;
3) round() в одном месте — round(), в другом — floor().
[opus] Какую проверить первой?
Это не «AI сам нашёл баг». Это «AI помог сформулировать гипотезы, чтобы вы их проверили».
Когда TDD не работает
В UI с тонкой моторикой пикселей, в перформанс-критичном коде, в исследовательских скриптах. Vibe Codex знает эти зоны и сам предлагает другой подход — характеристические тесты, бенчмарки, проверка глазами.
Скучный итог
TDD — это дисциплина, которую обычно бросают, потому что «долго». Vibe Codex делает её быстрой ровно настолько, чтобы перестать бросать. Это не магия — это снятый барьер. Дальше всё зависит от вас.
Готов попробовать?
brew tap xrouter-chat/tap && brew install vibe-codex — и за 30 секунд ты в деле.
Поставить Vibe Codex →