Времена меняются, и известное изречение Линуса Торвальдса «Talk is cheap. Show me the code» сегодня можно переформулировать: «Code is cheap. Show me the spec». Меня зовут Алекс Гусев, и я хочу объяснить, почему теперь именно спецификация, а не код, становится главным артефактом разработки.
Agent Driven Software Management и Spec-Driven Development
Я разрабатываю подход под названием ADSM (Agent Driven Software Management), который формализует мой личный опыт в методологию Spec-Driven Development (SDD). В рамках этой публикации я покажу, как SDD в виде ADSM применяется к созданию простого приложения — помощника по формированию плейлистов в Spotify.
Также я продемонстрирую, что происходит, когда один и тот же агент (Codex, GPT-5.4) генерирует код на основе одной и той же спецификации, но с разным уровнем reasoning: high, medium и low.
Предыстория: от идеи к автоматизации
Для семейного мероприятия понадобился плейлист на 4–5 часов. ChatGPT успешно составил список из 100 треков — с названиями и исполнителями. Оставалось только перенести их в Spotify. Раньше это делалось вручную, но теперь такие задачи легко автоматизировать с помощью ИИ-агентов.
Я не пишу «вайбкод», но зато практикую SDD. На создание первой версии приложения ушло чуть больше двух часов чистого времени.
До начала проекта я не знал о возможностях API Spotify. ChatGPT подсказал ссылку developer.spotify.com и объяснил, как зарегистрировать приложение.
Оказалось, что аутентификация реализуется через OAuth. Для этого нужен домен и TLS-сертификат. Домен был, сертификат — через Let’s Encrypt. Я пишу только на JavaScript, поэтому выбор языка и платформы был очевиден: TeqFW.
Разработка с агентом
Я создал приватный репозиторий на GitHub, склонировал его локально и добавил в контекст (./ctx/spec/) типовые шаблоны для node.js-приложений на основе библиотеки @teqfw/di.
Час я провёл в диалоге с Codex-агентом в VSCode: обсуждали запуск, конфигурацию, зависимости. Агент фиксировал всё в контексте проекта (./ctx/docs/).
Затем я попросил агента создать:
package.json;- bootstrap-файл
./bin/cli.mjs; - головной скрипт
./src/Main.mjs.
После этого — две итерации:
- Интеграционные тесты и код для получения и сохранения токена аутентификации через веб-сервер.
- Загрузка и парсинг текстового файла с треками, поиск в Spotify и создание плейлиста (всё с интеграционными тестами).
Соответствие формату ES6-модулей я проверял с помощью скилла teq-esm-validator.
Приложение проверялось по частям: запуск, аутентификация, разбор файла, поиск треков, создание плейлиста. Через два часа в Spotify был создан плейлист из 80+ композиций. Остальные треки не нашлись.
Детерминированность: не кода, а функционала
В комментариях на Хабре часто звучит мнение, что LLM-агенты неприменимы, потому что не дают детерминированного результата. Но программирование всегда было отчасти искусством.
«Детерминированность результата» ≠ «Детерминированность кода»
Если Леонардо да Винчи рисовал бы «Джоконду» десять раз, у него получилось бы десять разных картин одной и той же женщины. Так и с кодом: десять реализаций одного функционала — это десять разных приложений.
Эксперимент: три версии, один контекст
Я опубликовал код, созданный агентом (GPT-5.4, high reasoning) — версия 1.0.0. Контекст я намеренно удалил.
Затем попросил того же агента (но с уровнем reasoning medium) удалить папки ./src/ и ./test/ и, на основе неизменного контекста из ./ctx/, сгенерировать код с нуля — версия 2.0.0.
То же самое — с low reasoning: версия 3.0.0.
Агенту давался чёткий промпт: не восстанавливать прошлую реализацию из git, проектировать с нуля. В этом и был смысл итерации.
Результат: код во всех трёх версиях разный. Но приложение работает одинаково.
Ошибки и их детерминированность
Все три версии «затупили» при добавлении треков в плейлист. Dry-запуск проходил успешно, треки находились, но при добавлении агент использовал устаревший API Spotify. Пришлось вручную указывать на ошибку — трижды.
Если бы я не стремился к чистоте эксперимента, я бы добавил в контекст требование использовать новый API. Но я сознательно оставил контекст неизменным. Это показало: ошибки в прочтении контекста тоже детерминированы.
Третья версия (low reasoning) не смогла корректно запустить веб-сервер: он стартовал, но приложение сразу его останавливало, не дожидаясь получения токена. На уровнях high и medium такой проблемы не было.
Объём контекста vs объём кода
Я потратил месяцы на создание спецификаций для своего стиля разработки (./ctx/spec/code/platform/teqfw/). Эта документация переиспользуется во всех моих проектах.
На описание конкретного продукта ушло пара часов. А на генерацию кода каждой версии — около 10 минут. При этом на каждую версию уходило примерно 4% недельной квоты plus-подписки ChatGPT.
Соотношение объёма контекста и кода впечатляет:
- Файлы в
ctx: 53 - Каталоги в
ctx: 15 - Строк в
ctx: ~10 000 - Файлы в
src(v1–v3): 18–23 - Строк в
src: ~1 500
Да, это моя осознанная позиция: документы контекста должны быть в разы больше результирующего кода.
Скиллы как корректоры поведения агента
Моя платформа TeqFW использует позднее связывание: все зависимости внедряются через конструктор. В ./src/ нет ни одного статического импорта — это нетрадиционный подход, и агенты с ним справляются плохо.
Когда агенты упорно генерировали код со статическими импортами, я создал скилл teq-esm-validator — тоже с помощью Codex по методологии ADSM. Теперь достаточно указать в промпте: «используй скилл» — и проблема почти исчезает.
Заключение: код как производный артефакт
Я сравниваю поведение LLM-агентов с дождевой водой: она течёт по рельефу, собирается в ручьи и стремится к океану. Агент идёт по пути наименьшего сопротивления.
В этой аналогии:
- Контекст — плотины и каналы;
- Скиллы и тесты — насосы и шлюзы, поднимающие воду на новый уровень.
Основные затраты — на построение инфраструктуры. Но зато потом вода (код) почти всегда попадает туда, куда нужно.
Код — не конечный продукт. Это производный артефакт взаимодействия когнитивного контекста и агента.
Именно поэтому контекст проекта (53 файла в ./ctx/) важнее кода (18–23 файла в ./src/). Когда есть контекст, агент сгенерирует нужный код за минуты — даже для экзотической платформы вроде TeqFW.
Код всех трёх версий — дешёв. Изучайте его. А если хотите увидеть контекст — пишите в личку. Дам бесплатно, в обмен на обратную связь о применимости подхода в ваших проектах.
И немного прекрасного
ИИ-агенты легко генерируют «бойлерплейт» и делают ненужными тонны зависимостей в node_modules.
Они спокойно хардкодят Web API и перехардкодят при изменениях. В моём приложении всего:
- 2 зависимости для runtime (мои библиотеки);
- 2 зависимости для dev-режима (типы Node.js).