Достаточно подробная спецификация — это код

Достаточно подробная спецификация — это код

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

Почему теперь нужно объяснять подробнее

Сегодня сторонники агентного программирования утверждают, что нашли способ обойтись без кода, генерируя его напрямую из технических спецификаций. Более того, они настолько активно продвигают эту идею, что теперь даже простой комикс требует пояснений.

Их аргументы, как правило, строятся на двух распространённых заблуждениях:

  • Заблуждение 1: техническая документация проще кода, который по ней создаётся.
  • Заблуждение 2: написание документации по своей сути более вдумчиво, чем написание кода.

Ниже я покажу на примерах, почему эти утверждения не выдерживают критики.

Завуалированный код

Возьмём проект Symphony от OpenAI — оркестратор агентов, который, по заявлению разработчиков, был сгенерирован на основе технической спецификации (файл SPEC.md).

Однако сама «спецификация» выглядит не как описание требований, а как псевдокод, записанный в Markdown. Например, в ней содержится текстовое описание схемы базы данных:

4.1.6 Live-сессия (метаданные сеанса работы с агентом)
Состояние, отслеживаемое, когда запущен подпроцесс ИИ-агента.
Поля:
session_id (строка, <thread_id>-<turn_id>)
thread_id (строка)
turn_id (строка)
codex_app_server_pid (строка или null)
...

Или описание логики многопоточности:

8.3 Управление многопоточностью
Глобальный лимит: available_slots = max(max_concurrent_agents - running_count, 0)
Лимит на состояние: max_concurrent_agents_by_state[state] если есть (ключ состояния нормализован)
в остальных случаях использовать глобальный лимит
Среда выполнения подсчитывает задачи по их текущему отслеживаемому состоянию в словаре running.

Есть даже разделы, явно добавленные для управления генерацией кода:

6.4 Список полей конфигурации (памятка)
Этот раздел намеренно расширен, чтобы агент мог быстро реализовать слой конфигурации.
tracker.kind: строка, обязательная, сейчас linear.
tracker.endpoint: строка, по умолчанию https://api.linear.app/graphql, когда tracker.kind=linear…

А в некоторых местах приведён код, почти дословно:

16. Образцы алгоритмов (безразличные к языку)
16.1 Запуск сервиса

Такой документ — не альтернатива коду. Это уже код, только замаскированный под спецификацию.

Конечно, включение псевдокода в технические описания — нормальная практика. Но нельзя утверждать, что спецификация заменяет код, если она сама по себе читается как код.

Технические документы проще кода, который по ним создаётся

Если вы хотите, чтобы спецификация была достаточно точной для автоматической генерации рабочего кода, вы неизбежно придёте к формализму, близкому к коду. Это подтверждает и Дейкстра:

Перевод коммуникации между машиной и человеком на родной язык последнего мало того что приведёт к значительному увеличению нагрузки на первую, но и вовсе не гарантирует, что жизнь человека станет проще. Греческая математика зашла в тупик, потому что оставалась в рамках устного и начертательного подхода. Мусульманская «алгебра» загнулась, вернувшись к риторическому стилю. А современный мир смог развиться только когда Западная Европа освободилась от оков средневековой схоластики — тщетной попытки достичь точности с помощью слов.

Инженерная точность требует символьных систем — кода. Можно лишь переупаковать эту работу, но не избежать её.

Нестабильность генерации

Даже если спецификация подробна, это не гарантирует корректной генерации кода. Я попробовала воспользоваться подходом из README Symphony:

Реализуй Symphony в соответствии со следующим техническим документом: https://github.com/openai/symphony/blob/main/SPEC.md

Попросила Claude Code создать реализацию на Haskell. Результат оказался неработоспособным: код содержал ошибки, а сам агент зависал на простых задачах, например:

Создай новый пустой репозиторий. Не нужно создавать проект GitHub. Просто создай пустой репозиторий git.

Это показывает: даже при подробной спецификации генерация кода нестабильна. «Тщетная попытка обеспечить словесную точность» (по Дейкстре) не заменяет код.

Проблема не в Symphony. Даже у стандарта YAML, с его детальной спецификацией и тестами, большинство реализаций не полностью соответствуют описанию.

Если продолжать расширять спецификацию, чтобы закрыть все пробелы, она станет гигантской — как в притче Борхеса о карте, совпадающей с империей по размеру. В итоге документ будет бесполезен.

Создание спецификации должно быть более вдумчивым, чем написание кода

Это утверждение тоже спорно. На практике составление спецификаций часто превращается в формальность. Цель — быстрее запустить продукт, а не вдумчиво проанализировать архитектуру.

Вот фрагмент из раздела 10.5 спецификации Symphony:

Контракт расширения linear_graphql:
Назначение: выполнить сырой GraphQL-запрос к Linear или мутацию, используя настроенную в Symphony авторизацию трекера для текущей сессии.
Доступность: имеет смысл, только когда tracker.kind == "linear", и настроена валидная аутентификация Linear.
Предпочтительная форма ввода: {"query": "single GraphQL query or mutation document", "variables": {"optional": "graphql variables object"}}
...

Этот текст — сборная солянка без логической связности. Он читается как продукт ИИ: формально соблюдены требования, но нет целостности, понимания контекста, цели.

Такой «слоп» возникает, когда приоритет — скорость, а не качество. Даже если писал человек, результат будет поверхностным.

Заключение

Спецификации не были призваны экономить время. Если вы оптимизируете под скорость — пишите код сразу.

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

Читать оригинал