21 дек. 2025 г.·7 мин чтения

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

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

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

Почему агенты уводят код в сторону в реальном репозитории

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

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

Неясные промпты усугубляют проблему. Если вы просите "add user billing support" без указания сервиса, файла и правил, часто получаете смешанные результаты: camelCase в одном месте, snake_case в другом, валидация в контроллере, логика ценообразования в хелпере и доступ к базе там, где ему не место.

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

Короткие заметки работают, потому что большинство кодовых баз живёт локальными привычками. Возможно, все операции записи проходят через один сервис. Возможно, фоновые задания никогда не должны вызывать публичный API-клиент напрямую. Возможно, всё, что связано с оплатой, требует дополнительного ревью. Эти правила могут выглядеть незначительными, но они решают, будет ли новый код «свой» или «чужой» для команды.

Простой пример делает проблему очевидной. Допустим, в новых модулях бизнес-правила лежат в сервисах, а старый endpoint всё ещё считает скидки в контроллере. Агент видит этот endpoint первым и копирует старую структуру. Код может проходить тесты и всё равно быть неверным для команды.

Архитектурные заметки для агентов, помогающих писать код, должны останавливать такой дрейф. Это ограничители, а не полный системный спецификат. Цель проста: помочь агенту выбрать правильный паттерн до того, как он напишет 300 строк не в том месте.

Что должна охватывать короткая заметка

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

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

Оставьте только правила, которые меняют результат

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

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

Этого обычно достаточно, чтобы агент не сбился с пути. Этого также достаточно, чтобы новый коллега быстро сориентировался.

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

Простой язык тоже важен. Если новый инженер не поймёт заметку с первого дня, агент, скорее всего, тоже не последует ей. Используйте прямые предложения и конкретные примеры, например: "API request types лежат рядом с роутом" или "только billing-сервис может записывать записи invoice".

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

Правила именования, которые стоит записать

Большинство команд думают, что именование очевидно, пока агент не добавит UserManager, user-service, users.ts и customer_data в одну и ту же фичу. Каждое имя отдельно выглядит разумно. Вместе они усложняют обзор и уменьшают доверие к коду.

Начните с правил для файлов и папок. Делайте их скучными и консистентными. Если команда использует kebab-case для файлов и папок, скажите это и приведите один пример, который показывает весь шаблон, а не один файл.

Например, фича payments может выглядеть так:

payments/create-invoice-handler.ts payments/invoice-service.ts jobs/retry-failed-payment-job.ts

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

Называйте код по роли, а не по расплывчатому назначению. Хендлер должен звучать как точка входа, привязанная к запросу, событию или команде. Сервис — как бизнес-логика. Job — как запланированная или очередьвая работа. Если команда хранит поля базы в snake_case, а код приложения в camelCase, напишите это прямо. Агенты часто смешивают стили, если вы этого не укажете.

Короткий блок правил именования обычно выглядит так:

  • Handlers заканчиваются на -handler
  • Services заканчиваются на -service
  • Jobs заканчиваются на -job
  • Столбцы базы данных — в snake_case
  • Переменные в приложении и поля объектов — в camelCase

Также укажите слова, которых команда избегает. Это важнее, чем кажется. Если manager в кодовой базе означает долгоживущий координатор, не позволяйте агенту использовать это слово как синоним сервиса. Если model означает сущность БД, не используйте его для API-пейлоадов. Запретите расплывчатые имена вроде helper, common, data, process, если только команда не использует их с чётким значением.

Множественные и единственные формы путают агентов постоянно. Многие команды используют множественные имена для роутов и таблиц, например users и orders, но единственные для файлов и типов вроде user.ts и Order. Проблема начинается, когда в одной фиче используют invoice, в другой — invoices, и никто не помнит, что где хранит список, а что — одну запись.

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

Границы сервисов, которые агент должен уважать

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

Начните с владения. Запишите, какой сервис владеет каждой записью и каждым бизнес-решением. Данные профиля пользователя могут жить в accounts, статус подписки — в billing, проверки прав — в auth. Это предотвращает распространённую ошибку: сгенерированный код читает данные в одном сервисе, принимает решение в другом и сохраняет результат в третьем.

Пропишите пути вызовов тоже. Некоторый код может использовать локальный пакет. Другие действия должны идти через API, событие или очередь, даже если прямой запрос к базе выглядит быстрее. Если order-сервису нужен статус инвойса, скажите: "call billing API." Не оставляйте это правило подразумеваемым.

Общие утилиты должны иметь чёткую грань. Агенты часто переносят логику в общий пакет, потому что это выглядит аккуратно. Это размывает доменные правила по всему коду. Утилиты должны решать простые кросс-сервисные задачи вроде логирования, повторных попыток, парсинга дат или форматирования ID. Логика сервиса должна оставаться в сервисе, который владеет данными и решением.

Копирование и вставка между сервисами вызывает другую проблему. Модель видит похожие хендлеры и клонирует их, включая неправильные правила валидации, имена таблиц или формы событий. Частые точки отказа: проверки auth, скопированные в код продукта; правила биллинга, попавшие в onboarding; шаблоны уведомлений, скопированные с сервис-специфичными плейсхолдерами; структуры запросов/ответов, скопированные и затем изменённые только в одном сервисе.

Небольшой пример закрепляет правило. В SaaS-приложении агент может добавить "suspend account for non-payment" внутри user-сервиса, потому что там расположен экран аккаунта. Заметка о границах должна сказать: billing решает вопрос о должниках, auth обеспечивает доступ, а user-сервис только отображает статус.

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

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

Review Your Repo Rules
Ask Oleg to review naming, boundaries, and stop points before agents copy the wrong pattern.

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

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

Код, требующий повышенной осторожности

Короткая заметка может указать рискованные места, например:

  • файлы, которые рассчитывают цены, налоги, кредиты, возвраты или инвойсы
  • код логина, сессий, токенов и проверки ролей
  • проверки прав, спрятанные в middleware, хелперах или декораторах
  • скрипты миграций, seed-данные и всё, что меняет схему
  • воркеры, очереди, планировщики, retries и задания с отправкой email или webhook

Устаревший код тоже требует предупреждения. Папка может выглядеть просто, но зависеть от старых имён, старых полей базы или поведения, которого никто не догадается, прочитав одну функцию. Если в модуле есть скрытые допущения, скажите об этом в одном коротком предложении. Например: "Do not rename fields in this package. Old mobile clients still send them."

Когда агент должен остановиться

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

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

Будьте конкретны в точках остановки. "If you touch anything under billing/, auth/, migrations/, or jobs/, make the smallest safe change and ask for review before expanding scope" — этого достаточно. Такая фраза предотвращает множество дорогих ошибок.

Как писать заметку шаг за шагом

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

Затем напишите правила в самой короткой форме, которая всё ещё понятна. Хорошие заметки больше похожи на техпаспорт цеха, чем на дизайн-документ. Часто достаточно одной страницы.

Перечислите повторяющиеся ошибки простым языком. Добавьте правила именования с простыми примерами, например: "use customer_id, not customerId in SQL." Добавьте правила границ, которые говорят, какой сервис может читать данные биллинга и какой должен вызывать API. Затем добавьте один маленький пример изменений, который показывает правильный паттерн в контексте.

Держите правила именования и границ конкретными. "Keep modules clean" слишком расплывчато. "HTTP handlers validate input, services hold business rules, repositories touch the database" — намного лучше. Агенты следуют локальным паттернам, когда вы их явно прописываете.

Один небольшой пример помогает больше, чем длинное объяснение:

Change request: add invoice status to the customer screen.
Expected pattern: handler reads request, customer service asks billing service for status, billing tables stay inside billing service, UI uses existing status enum names.

Этот один блок может предотвратить много плохого кода. Он показывает именование, владение и где данные могут пересекать границу.

После первой реальной задачи сразу пересмотрите заметку. Посмотрите, что агент всё ещё делал неправильно и чем никто не пользовался. Уберите мёртвые правила. Добавьте недостающее правило, которое предотвратило бы проблему.

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

Простой командный пример

Set AI Coding Guardrails
Build simple repo instructions for handlers, services, jobs, and areas that need review.

Представьте небольшой SaaS с четырьмя частями. Веб-приложение показывает дашборды и экспорт. API обрабатывает логины, отчёты и запросы биллинга. Воркер строит тяжёлые отчёты в фоне. База хранит пользователей, инвойсы, задания отчётов и события аудита.

Короткая заметка в репозитории может сказать:

  • Изменения отчётов идут в api/reports, worker/report_jobs и страницы отчётов в вебе.
  • Код биллинга остаётся в api/billing и web/billing. Не импортируйте типы биллинга в отчётный код.
  • Сохранённые записи отчётов используют существующую модель Report. Не создавайте SavedReport, ReportModel или ReportEntity.
  • Никогда не правьте старые миграции в db/migrations/legacy. Добавьте новую миграцию.

Теперь дайте агенту задачу: добавить "team activity report" с экспортом в CSV. С этой заметкой агент получает узкий путь. Он добавляет экран отчёта в веб, новый endpoint API в reports и воркер, который строит CSV из событий аудита. Также создаёт одну новую таблицу для фильтров отчётов.

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

Правило именования даёт больше, чем аккуратные файлы. Без него агент может создать SavedReport в API, ReportEntity в воркере и ReportDto в вебе для одной и той же сущности. Ревьюверу придётся распутывать три почти одинаковые копии. Если заметка говорит "persisted report data is always Report", агент повторно использует модель и добавляет только нужные поля.

Предупреждение про миграции так же практично. Во многих командах есть старый путь, который всё ещё пересобирает тестовую или стейджовую базу. Одно быстрое предупреждение вроде "do not change anything before 2023_11_billing_split; that chain is fragile" остановит агента от редактирования истории, когда нужен лишь новый миграционный файл для фильтров отчётов.

Поэтому такие заметки работают лучше, когда они короткие и отвесные. Они не объясняют всё. Они блокируют частые неправильные повороты.

Ошибки, ведущие к плохому сгенерированному коду

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

Одна частая ошибка — писать мини-руководство вместо короткого гида. Команды пытаются покрыть каждое прошлое решение, каждый edge-case и каждое исключение. Это звучит аккуратно, но прячет те правила, которые агенту действительно нужны для повседневной работы.

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

Абстрактные советы создают столько же проблем. "Keep services separate" или "follow the standard module layout" почти ничего не говорят агенту. Полезная заметка называет реальные места: какие папки держат хендлеры, где живёт доменная логика, какой модуль владеет биллингом и где должен остановиться доступ к базе.

Конкретные пути важны, потому что агенты копируют формы. Если заметка говорит, что orders находятся в internal/orders, а HTTP-обработчики — в api/http, агент обычно следует этому паттерну. Если заметка остаётся на высоком уровне, агент может изобрести новую папку, добавить логику в неверный слой или напрямую связать два сервиса.

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

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

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

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

Быстрая проверка перед использованием заметки

Prepare Your Repo for AI
Set naming, ownership, and review rules that fit your current team and codebase.

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

Та же проверка подходит и для заметок для агентов. Агенты не заполняют пробелы так, как люди. Они делают догадки, и именно догадки приводят код в сторону.

Пройдите простую проверку перед тем, как полагаться на заметку:

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

Рискованные области важнее, чем многие команды ожидают. "Payments" или "auth" — этого недостаточно. Напишите правило простыми словами: не переименовывать эти события, не менять эту логику retries, не редактировать этот паттерн миграций без ревью. Это даёт агенту жёсткую границу вместо мягкого предупреждения.

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

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

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

Что делать дальше

Начните с малого. Выберите одну повторяющуюся задачу, которая уже съедает время: добавить новый API-эндпоинт, построить админ-страницу или связать фоновую задачу. Напишите заметку для этой области сначала, не пытайтесь документировать всю кодовую базу одновременно.

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

Затем протестируйте заметку на небольшом изменении. Попросите агента сделать безопасное обновление, проверьте результат и отметьте слабые места. Если код всё ещё попадает в неверную папку или вызывает неверный сервис, заметка слишком расплывчата. Исправьте заметку, выполните задачу ещё раз и сравните выводы.

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

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

Если хотите второе мнение по руководствам по использованию ИИ или правилам репозитория, Oleg Sotnikov at oleg.is помогает стартапам и небольшим командам в роли Fractional CTO и советника. Его работа фокусируется на практичных AI workflow, продуктовом архитектурном дизайне и бережных инженерных системах — именно там эти заметки начинают окупаться.

Часто задаваемые вопросы

What is an architecture note for a coding agent?

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

How long should the note be?

Одна–две страницы для одной области репозитория. Если заметка читается дольше минуты, люди пропускают её, и агент начинает гадать.

What should I put in the note first?

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

Do naming rules really matter that much?

Да. Агенты быстро смешивают имена, если оставить пространство для догадок. Пара простых правил — например -handler, -service, -job, плюс snake_case в SQL и camelCase в приложении — сильно сокращают шум.

How should I describe service boundaries?

Назовите владельца данных и владельца решения простыми словами. Напишите, например, orders asks billing for invoice status или only billing writes invoice records, чтобы агент не пересекал границы только потому, что две папки выглядят схоже.

Which parts of the codebase should I flag as risky?

Отметьте любые области, где мелкая ошибка может привести к ошибкам в деньгах, проблемам с доступом или потере данных. Как правило, это биллинг, аутентификация, миграции, повторные попытки (retries), фоновые задания и старые модули с скрытыми допущениями.

When should the agent ask for human review?

Пусть агент остановится, если непонятна ответственность или изменение затрагивает биллинг, аутентификацию, схему данных, логику повторных попыток или продовые данные. Простое правило вроде make the smallest safe change and ask for review работает лучше, чем расплывчатая рекомендация.

What do I do with legacy code and old exceptions?

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

Should I include an example change in the note?

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

Where should I keep the note, and when should I update it?

Храните заметку там, где её видят разработчики и агенты в рабочем процессе — рядом с репозиторием или в общих правилах кодирования. Обновляйте её сразу после рефакторов или когда сгенерированный код показал пробел в правилах.