Я к вам пишу — чего же боле?
Агент все может написать.
Но за ошибки поневоле
Придется вам же отвечать.

(Письмо инженера Татьяны к вайбкодеру Евгению)

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

Обещания читателю

Ни одна строчка в тексте статьи не была написана LLM. Агентов использовал для “гугления”, проверки статьи на ошибки и генерации текстовых графиков. Рифмы искал через генераторы рифм. Каждую букву текста набрал с клавиатуры.

Пишу в первую очередь для разработчиков. Не важно, как вы относитесь к разработке с агентами, согласны или нет с подходом — в любом случае надеюсь, что получится навести вас на какие-то новые мысли.

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

Кто говорит

Дано мне легаси — что делать с ним,
Таким запутанным, теперь моим?

(Мандельштам, если бы он устроился в Яндекс.)

Написанное приобретет больший смысл, если я немного расскажу о своем опыте.

С самого начала карьеры я фокусировался на создании поддерживаемого кода, и произошло это благодаря глубокой травме. В 2017 году устроился в Яндеквс и столкнулся с легаси впервые в жизни. Испытал столько боли, что стремление писать понятный код отпечаталось в моей психике.

Поэтому на протяжении карьеры я изучал редкие языки, вроде Clojure (вообще, с десятком языков поработал), читал SICP, разбирал кодовые базы в open-source — все в стремлении понять, как писать код так, чтобы минимизировать долгосрочное страдание.

Если вы посмотрите на мои другие статьи на хабре, многое будет про качество кода и поддерживаемость систем:

‣ Заговор разработчиков против корпораций
‣ Заговор разработчиков против корпораций: архитектура
‣ Один выгоревший сеньор или два джуна с горящими глазами?
‣ Как распараллелить тесты с базой данных
‣ Зачем Clojure Flutter
‣ Как декларативно описать коллапсирующий тулбар
‣ Delegate Adapter — зачем и как

Последние полтора года активно писал код с агентами, буквально каждый день, пытаясь следовать уже сформировавшимся принципам и нащупать новый подход.

Для чего нужен подход или цели разработчика

Ускорить путь от мысли к коду —
Прекрасный подов ликовать.
Но я хочу иметь свободу
Его без мата поменять.

(Пушкин агентной эры)

Агенты позволяют писать код быстро, но поддержка остается в зоне нашей ответственности. И бремя это тем более тяжко, чем сложнее и суровее проект.

В статье Заговор разработчиков против корпораций: архитектура и принципы я писал, что архитектура нужна, в основном, ради двух вещей:

‣ Сокращать time to market (TTM);
‣ Соблюдать SLA.

Эти же критерии будут применимы и здесь, и я считаю, что оба зависят от того, насколько сложную систему приходится поддерживать. Для дальнейшего понимания проблемы придется остановиться на нескольких определениях.

Когда легкость порождает сложность

Нажал на кнопку — и готово!
Уже открыл PR агент.
Но пал соседний компонент —
И править всё придётся снова.

(Пушкин агентной эры)

Если вы смотрели доклад Рич Хикки “Simple made easy” или уже знакомы с идеями, можете пропускать параграф. Если нет, рекомендую оригинал:

Легко (easy) — понятие субъективное: то, что рядом, что легко нам. Например, русский язык легкий для нас, потому что мы носители, но трудный для иностранцев. Антоним “легко” — “трудно” (hard).

Совершенно другая категория понятий — просто и сложно (simple and complex). Этимология слов подразумевает сложение (сгиб) вещей. Простой значит односложенный. Сложный значит многосложенный, запутанный, переплетенный. У Рича Хикки в докладе сложность — это про связывание независимых аспектов системы.

Сложность — это объективно свойство в отличие от трудности. Но сложность в коде трудно определить. Взять code smells. Вроде бы, чем их больше, тем сложнее система. Но это не всегда так. Например, нарушение DRY — code smell, но иногда дублирование упрощает. Писал об этом в Злоупотребление DRY в статье про заговор.

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

Из доклада Рича Хикки “Simple Made Easy”
Из доклада Рича Хикки “Simple Made Easy”

Зачем избегать сложности?

Крошка сын к отцу пришел,
И сказал тревожно:
— Сделать просто нелегко…
— Да. Зато надежно!

(Маяковский эры вайбкодинга)

Предупреждение, чтобы параграфы ниже имели смысл, нужно разобраться с терминами: легко и трудно, просто и сложно.

Вайбкодинг — это легко. Агенты радикально удешевляют генерацию кода, но системы, созданные таким образом, могут получиться сложными. Чтобы избежать случайной сложности (accidental complexity), придется вникнуть в задачу, спроектировать архитектуру, подходящую под развитие проекта. А это уже трудно.

Возникает конфликт: решение с агентом дается легко, но получается сложным. А сделать просто — трудно. Может быть, сложность — это не страшно, а легкость разработки с агентами ее компенсирует?

Есть две причины считать, что агентная разработка не компенсирует сложность.

Во-первых, мы несем ответственность за код, который пишет LLM. Чем этот код сложнее, тем труднее его понять. А чем хуже мы понимаем систему, тем меньше оснований считать ее надежной. Другими словами, мы не сможем гарантировать TTM и SLA (см. “Для чего нужен подход” выше), если не понимаем код.

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

Понимает ли LLM сложность?

Нам не дано предугадать,
Как слово наше отзовется:
Попросишь код не усложнять —
Ещё оберточка найдётся.

(Некрасов агентной эры)

Скажу по секрету: статью я начал писать еще летом, и тогда ответ был “определенно нет”. Все настолько быстро меняется, что постоянно приходится переписывать статью. Сейчас frontier модели вроде Gpt6 Astra и Opus 5.5 заметно сильнее, поэтому наверняка ответить не могу. Склоняюсь к тому, что LLM все же не понимает и не избегает сложности.

Мнение основано в большей степени на моем ревью кода агентов и на разборе имеющихся исследований. Последнее — в меньшей степени, потому что исследования “старые” и замеряют соседние со сложностью вещи: трудность, code smells, соблюдение архитектурных границ, количество строк кода, high cohesion/low coupling, технический долг. Это важно, но не отвечает на вопрос про сложность, как мы ее определили выше.

LLM лучше говорит о сложности, чем избегает ее. LLM может рассуждать о high cohesion/low coupling и separation of concerns, но на деле создавать скрытые зависимости, использовать state там, где он не нужен, выдумывать абстракции, где можно было обойтись без них.

Несколько исследований для подтверждения выводов

‣ ττ -Bench: An Environment for End-To-End, Realistic Agent Construction: про то, что агенты (например, Claude + Opus 5) автоматизируют написание кода, но не инженерное мышление. Агенту плевать на то, что будет в проде под нагрузкой, какие реальные требования нужно учесть, какие решения можно переиспользовать. Не проходит тест — агент поправит… тест. Главное — решить задачу.

‣ SlopCodeBench: Benchmarking How Coding Agents Degrade Over Long-Horizon Iterative Tasks: у LLM получается в 2.3 раза больше строчек кода по сравнению с проектами людей, ~6x деградация по метрикам скорости роста verbosity и structural erosion (как сложность накапливается в уже сложных функциях). Лучшая модель в эксперименте — GPT-5.5.

‣ Estimating problem difficulty without ground truth using large language model comparisons: оценки LLM и людей по трудности задач (не сложности) совпадают. Корреляция Пирсона 0.8.

‣ Can LLMs Estimate Student Struggles? Human-AI Difficulty Alignment with Proficiency Simulation for Item Difficulty Prediction: LLM не может подстроиться под опыт конкретного человека и предсказать, что будет трудно ему.

‣ Rethinking Code Complexity Through the Lens of Large Language Models: фактически тут про трудность для моделей при работе со ~сложным кодом, где сложность определяется через глубину вложенности и ветвления.

‣ Beyond Strict Rules: Assessing the Effectiveness of Large Language Models for Code Smell Detection: простые code smell LLM (DeepSeek-R1, GPT-5 mini, Llama-3.3, and Qwen2.5-Code) находят, более сложные, но видимые людям, — нет. Тут конечно вопрос: как поведут себя frontier модели?

‣ The Modular Imperative: Rethinking LLMs for Maintainable Software: исследование про архитектурную мимикрию. LLM (Claude Sonnet 4) могут разбивать код по файлам и писать про separation of concerns, но в то же время неявно связывать сущность и запутывать (т.е. усложнять) систему.

Сложность или трудность: автономия или контроль

И сложно, и трудно, и некому промпт передать
В минуту душевной невзгоды.

(Лермонтов агентной эры).

Хочется избежать и сложности, и трудности, но возможно ли это? Как связаны сложность и трудность в контексте разработки с агентами и что они из себя представляют?

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

Оба варианта представлены на графике ниже, где зависимость между сложностью и трудностью — обратная:

Сложность
   ↑
   │ ● Полная автономия
   │   \
   │    \
   │     \
   │      ●  ← хороший баланс
   │        `---__
   │              `-----● Полный контроль
   │
   └────────────────────────→ Трудность
       легко          трудно

Полная автономия будет наверху слева, где наши усилия минимальны, но агент создает сложные системы. Полный контроль будет справа снизу, где мы делаем практически все сами и контролируем сложность.

У меня есть предположение, что существует точка баланса, после которой дальнейшее вложение усилий дает все меньше отдачи — прямо как закон убывающей отдачи. Пример: вы отрефакторили один тест по новым правилам, осталось 50 похожих тестов. Можно писать шаблон, и это большие усилия — но ценности в них минимум, потому что агент по аналогии переделает все сам.

Если график переделать под зависимость между отдачей от ИИ и вложением собственных усилий, он выглядел бы как кривая Парето:

Отдача
   ↑
   │                         __________________
   │                  ______/
   │              ___/
   │         .___/  
   │      __/  ← хороший баланс
   │    _/
   │   /
   │  /
   │ /
   │●
   └────────────────────────────────────→ Усилия

И нам бы хотелось найти те 20% усилий, котоыре дадут 80% результата.

Как найти баланс между автономией и контролем?

На график глядя, я впервые
Нашёл желанный идеал.
Пришли задачи боевые —
И я опять его искал.

(Пушкин агентной эры)

Формально — никак.

Во-первых, нельзя оценить трудность для разработчиков: она субъективна и она меняется.

Во-вторых, практически невозможно сравнить сложность двух систем, даже несмотря на то, что сам термин “сложность” предполагает объективность. Нет универсальной шкалы сравнения. Можно смотреть на цикломатическую сложность, глубину вложенности, размеры функций, количество code smells, плотность графа зависимостей и тому подобное. Но как мы это сравним — будем придумывать веса для разных показателей?

В-третьих, кривая может сдвигаться левее с улучшением языковых моделей. Пример с GPT 5.3 vs 6.0 Asktra:

Сложность
   ↑
   │ ●
   │  \                       ● — GPT-5.3
   │   \                      ○ — GPT-6.0 Astra
   │    \
   │ ○   \
   │  \   \
   │   \   \
   │    ○←──●   ← выбранный уровень сложности
   │     \   `---__
   │      `----__  `---__
   │             `-------`---◆ Полный контроль
   │
   └──────────────────────────────→ Трудность

На GPT-6.0 сложность системы будет ниже при тех же усилиях.

Как видите, трудность субъективна и меняется, сложность тяжело оценивать, а LLM постоянно улучшаются. Поэтому невозможно предложить универсальный способ работы с LLM, который был бы лучше остальных и оставался таким спустя время.


Как писать код с агентами — подход сверху

Наши пальчики устали —
И агентов мы позвали.
Пальцам стало хорошо.
Но сеньорам подожгло.

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

Сегодня мы всё меньше делаем сами и всё больше делегируем агентам — делегируем написание кода и документации, code review, ведение jira, разбор проблем и тестирование.

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

Waterfall vs Agile или почему SDD должен умереть

История научила нас, что waterfall — каскадная модель жизненного цикла ПО — неэффективна. Если мы заранее пытаемся всё продумать и спланировать, мы очень поздно получаем обратную связь. Можно разрабатывать сервис полгода и понять, что он вообще был не нужен. Это дорого и непрактично.

И именно так оно в Spec Driven Development. В большинстве определений, что я нашел, SDD — это проработка и требований к реализации, и деталей реализации заранее. Такое определение и у GitHub Spec Kit, и у Kiro, и у CodeSpeak (было в начале 2026 года).

Так вот, невыгодно прорабатывать огромную спеку со всеми деталями до разработки. Лучше указать в спеке намерения и ограничения, а затем, по мере разработки фичи, добавить описание подводных камней. Чтобы в документации был ответ, почему и зачем код написан тем или иным образом, но не что написано.

В подтверждение тезисов оставлю 3 ссылки:

  • CodeSpeak переоделись и вместо позиционирования «Спека вместо кода» пришли к восстановлению намерений из спек.

  • Роберт Мартин прямо критикует SDD и предлагает поскорее получать рабочую реализацию (youtube) и приводит Agile в пример.

  • Мой TG пост про сравнение SDD с safe-scumming в Total War.

Если вы и так согласны, что в SDD нужно только документировать намерения и ограничния, то вопрос — зачем называть это SDD? Подобные правила документации существовали до SDD (Requirements Engineering, BDD, ADR, Model-Driven Development), зачем нам вообще этот термин?

В основе лежат ценности

Как только мы отходим от ценностей Agile в конкретные реализации вроде SCRUM, на практике получается или cargo cult, или water-scrum-fall, или что-то еще хуже. Мою критику SCRUM можно почитать в статье про заговор разработчиков.

Но сами ценности Agile прекрасны:

  • Работающее ПО важнее исчерпывающей документации.

  • Сотрудничество с заказчиком важнее, чем согласование условий договора.

  • Готовность к изменениям важнее, чем следование первоначальному плану.

Чувствуете, как далеко Agile от проработки спеки заранее и как близко к изменениям по ходу работы?

К разработке ПО с агентами я бы применил все ценности agile и добавил еще одну:

Ответственность за качество ПО лежит на разработчике, не на LLM.

Принципы опираются на ценности

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

Признание того, что работоспособность ПО — лучший измеритель прогресса.

Можно за день приготовить детальную спеку, а можно получить уже работающий софт. Последнее ценнее. Работающий код легко переписать на другую реализацию тем же агентом, писал об этом в ТГ-посте про code review.

Признание важности простоты, как искусства не делать лишней работы.

Можно неделю готовить план, договариваясь со всеми подряд, а можно за час собрать прототип, обнаружить, что опыт не тот — и сразу отказаться от задачи.

Стремление к техническому совершенству и к хорошему проектированию с целью увеличения гибкости.

Этот принцип показывает, что бездумно вайбкодить на скорость — тоже не вариант. Гибкость нужна для соблюдения TTM и SLA, как писал выше. А “техническое совершенство” — это отсутствие излишней сложности в нашем определении выше (оно же accidental complexity).

К имеющимся принципам я бы добавил еще один, учитывая, что у нас уже есть ценность про ответственность разработчика:

Работать блоками, которые вы способны осознать.

Это единственный способ нести ответственность за систему. Грубо говоря: джун пусть работает со строчками и функциями, мидл с классами и интерфейсами, сеньор — с интерфейсами и модулями. Если с модулями будет работать джун, сможет ли он поддерживать “техническое совершенство” системы?


Как писать код с агентами — подход снизу

Ты назвал модель сеньором.
Я назвал диван мотором.
Он не едет, хоть убей.
Дай ему еще ролей.

(Агнию Барто агентной эры)

Выше в статье я настаивал, что невозможно сформировать универсальный метод работы с LLM, который учтет все аспекты проекта, текущий уровень LLM, компетентность разработчиков и прочие факторы.

Иными словами, волшебной таблетки нет и не будет, какой бы привлекательной эта идея ни казалась. Но можно выделить “аксиомы” и сформировать ряд правил на основе этих аксиом. Я бы предложил следующий список:

  1. Результат работы LLM прямо зависит от релевантности и контекста.

  2. Промпты вроде “ты сеньор” не влияют на качество кода.

  3. Модель совершенно не понимает реальный мир.

  4. Там, где нет правильных ответов, LLM не может сделать правильный выбор.

  5. Естественный язык — не язык программирования: он неоднозначный и двусмысленный.

  6. LLM легко делает задачи по аналогии.

1, 4 и 5 самоочевидны. 2 исследовано со всех сторон (раз, два, три работы за 2024, 25 и 26 годы). 6 тоже подтверждается и исследованиями (раз, два), и моим опытом. 3 попробую доказать скриншотом, простите мне один раз:

Общение с ChatGPT PRO в августе 2026
Общение с ChatGPT PRO в августе 2026

Правила разработки с агентами на основе аксиом

Ниже приведу неисчерпывающий список правил, которые были актуальны и год назад, и вчера, и, скорее всего, останутся таковыми в будущем. Кроме того, давайте стараться учитывать наши ценности и принципы, определенные выше.

‣ Следи за качеством кодовой базы

Если LLM легко пишут код по аналогии (аксиома 6), им проще будет поддерживать архитектурные паттерны на основе того, что уже написано. Это же подтверждает исследование Rethinking Code Complexity Through the Lens of Large Language Models, приводил его выше. Кроме того, accidental complexity — это лишние зависимости и лишний код в целом, что ухудшает качество контекста, поступающего в LLM (аксиома 1).

Большой вопрос — как следить. Многое зависит от стека и проекта. На мой взгляд, чтобы избежать катастрофы, минимально нужно:

  • иметь опытных людей в команде, заинтересованных в проекте долгосрочно;

  • покрывать код метриками качества на: code smells, code style, соблюдения границ модулей, цикломатическую сложность;

  • проводить code review не только агентами.

Code review — это скучно и муторно, но есть способ сделать его и интереснее, и иногда полезнее. Вместо ревью можно делать реализацию на основе написанного кода. Если последний уже проверен на работоспособность, а тесты — интеграционные, легко заменить реализацию и попробовать сделать лучше. Подход может показаться радикальным, и он таким бы и был, если б не возможности переписать ПР за 20 минут агентом. Подробнее о подходе писал в TG-посте про code review.

Кстати, насчет интеграционных тестов: разбирал их в статье про заговор — запрещаем рефакторинг обилием Unit-тестов.

‣ Документируй намерения и ограничения, но не реализацию

Сколько бы текста вы ни написали на естественном языке, вы не сможете гарантировать детерминированный код (аксиома 5) и пример в ТГ. LLM — это не компилятор из естественного языка в программный. SDD-фреймворки меняют парадигму от “спека вместо кода” на “спека для документации намерений”. Подробнее писал выше в параграфе Waterfall vs Agile или почему SDD должен умереть.

Ну и в AGENTS.md можно не добавлять “спам” вроде “ты senior developer”. Это ведь ни на что не влияет (аксиома 2). Но можно добавить примеры хороших абстракцию в уже написанном коде (аксиомы 5 и 6).

‣ Разбивай документацию на файлы, не держи все в одном месте

Если проект большой, а в LLM попадает файл с документацией всего, LLM забьет контекст лишним (аксиома 1). Да, LLM стали умнее и контекстное окно увеличилось, но всегда найдется проект еще больше. В качестве примера могу показать документацию на своем open source проекте:

  1. Изначально агенту попадает AGENTS.md

  2. Оттуда он может найти ссылку на AGENTS.md конкретного модуля (backend/AGENTS.md).

  3. Дальше агент может найти документацию с подводными камнями по конкретным фичам (пример).

‣ Архитектурные решения принимает разработчик, а не LLM

Учитывая, что LLM не понимает реальный мир (аксиома 3), а правильный ответ зачастую зависит от понимания реального мира (аксиома 4), принимать решения придется нам самим. Какой стек выбрать, использовать ли gRPC, нужен ли RMQ для очереди задач или лучше подойдет Postgres, микросервисы или монолит, разбивать ли таблицу на шарды, хранить ли текст в базе данных или в S3 — все эти и подобные решения LLM не примет за вас.

Напустсвенные слова

Код ты можешь не писать,
Но обязан отвечать.

В статье я сфокусировался на определениях, постановке проблемы, ценностях и принципах. Конкретных рекомендаций было немного. Уверен, что читатель сможет сам придумать больше правил и успешно интегрировать их в свою работу, если поставит правильные цели, поймет проблемы и примет ценности и принципы, о которых я писал выше. Тем, кто ищет волебную таблетку или SDD-фреймворк для решения всех проблем, могу пожелать лишь удачи.

Комментарии (0)