AI ошибается. Люди тоже ошибаются.
Проблема в том, что AI производит код полный недочетов и скрытых ошибок быстрее, чем чинит и в большем объеме, чем человек способен прочитать.
Каждая сгенерированная строка имеет стоимость владения - ее нужно поддерживать на регулярной основе. Это не актив, а нагрузка для проекта. Код нужно проверить, понять, учитывать при следующих изменениях, он попадает в контекст занимает там место. Чем больше кода генерируется, тем дороже становится дальнейшая разработка.
Нужно уменьшать стоимость проверки результата и стоимость владения.
Промпт не является контрактом. Это пожелание на естественном языке, допускающее десятки интерпретаций. Можно написать модели "не ломай совместимость", "учти все крайние случаи" и "пиши надежно", но эти фразы невозможно автоматически проверить. Контракт должен быть формальным и желательно исполняемым.
Типы фиксируют форму данных, сигнатуры и архитектурные границы. Это дешевый, широкий, но неглубокий контроль. Типы не подтверждают бизнес-логику, порядок операций, права доступа, транзакционность, идемпотентность, отсутствие гонок и корректность побочных эффектов. А в TypeScript типы вообще не являются точным описанием того, что будет реально исполняться в виртуальной машине. Типы стирается до runtime и виртуальная машина сама выводит свои типы, которые отличаются от того, что вы себе написали в TS.
Типы описывают представление компилятора о программе, а виртуальная машина работает с реальными значениями у которых есть вычислимая "форма" и с кодом, кторый оптимизируется во время исполнения под эту форму. Данные всегда приходят из сети, БД, JSON, JavaScript-модуля, пользовательского ввода и не соответствуют тому, что было в TS. Типы в рантайме более строгие, чем в TS, например, он учитывает порядок полей в объекте, знает, как резолвится асинхронная функция, через ивентлуп или очередь микротасков, отличает значения внутри Number: HeapNumber, Smi, Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64, Float16, Float32, Float64, Word8, Word16, Word32, Word64...
Более того, TypeScript сознательно не является полностью sound-системой типов. Он допускает операции, безопасность которых невозможно гарантировать статически. Поэтому типы полезны как дешевый статический фильтр, документация и компактное описание архитектурной границы. Но они не подтверждают, что программа действительно выполняет контракт. Для этого нужна runtime-валидация, ограничения данных и тесты наблюдаемого поведения.
Тесты фиксируют поведение гораздо точнее. Мутационное тестирование намеренно портит реализацию чтобы проверить общую стабильность на сломанном пути. Контрактные тесты подтверждают совместимость модулей и сервисов Интеграционные тесты проверяют взаимодействие с базой, сетью и инфраструктурой. E2E фиксируют наблюдаемое пользователем поведение. Нужно зафиксировать даже неизвестное legacy-поведение, а как это сделать типами?
Полная типизация внутренней реализации постепенно теряет смысл, AI способен читать реализацию целиком и отслеживать реальные рантайм-типы гораздо более точно. Во многих проектах достаточно JavaScript для реализации каждого модуля + d.ts для контрактов. Typings становятся суммаризацией кода и документации. Они описывают обещание модуля внешнему миру, не заставляя потребителя изучать реализацию. Внутри можно свободно менять алгоритмы, структуры данных и декомпозицию, пока сохраняются внешние типы, тесты и инварианты.
Полностью типизированный код может быть неправильным. Он может идеально собираться и одновременно нарушать бизнес-правила, терять данные, создавать гонки, неправильно повторять платежи или выдавать пользователю чужие права. Типизация реализации создает полезные ограничения, но иногда еще и ложное ощущение надежности. А лишние типы забирают внимание человека, увеличивают кодовую базу и жрут контекст AI.
Заходим к Илье, учимся тестировать с AI: https://ai.javascript.ninja/gld-ai-r
Post #2136
2.5K
- ❤ 16
- 🤯 4
- 💯 2