Лучшие практики работы с AI-агентами

Как подготовить кодовую базу к агентной разработке

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

Статья синтезирует практики из материалов Logic Inc, Block Engineering, Anthropic Engineering и личного опыта работы с Claude Code в production-проектах.

100% покрытие кода тестами

Высокое покрытие тестами — это не про предотвращение багов. Это про гарантию того, что агент проверил поведение каждой строки, которую написал. Разница принципиальная: при 95% вы по-прежнему принимаете субъективные решения о том, что «достаточно важно» тестировать. При 100% происходит фазовый переход.

Фазовый переход при 100% покрытии: если строка не покрыта тестом — это значит только одно: вы только что что-то сделали. Coverage-отчёт превращается в конкретный TODO-лист. Не в абстрактный ориентир, а в точный список строк, для которых нет теста.

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

Побочные эффекты 100% покрытия

Logic Inc называют 100% покрытие «секретным оружием» агентной разработки. Их опыт: команды, начавшие с этого требования, получали предсказуемые результаты от агентов даже в сложных legacy-проектах. Команды, пропустившие этот шаг, сталкивались с тем, что агент корректно решал формулировку задачи, но ломал поведение в смежных модулях.

Как начать, если покрытие сейчас 60%: не ставьте цель «100% к концу квартала». Введите правило: CI не проходит без теста на новый код. Старый код покрывайте инкрементально, когда касаетесь его в рамках задач. Через несколько месяцев покрытие подтянется органически, а культура сформируется без форсажа.

Пространства имён и структура файлов

Файловая система — это первичный навигационный API агента. Он не читает документацию с чашкой кофе; он строит карту кодовой базы по именам файлов, директорий и модулей. Качество этой карты напрямую определяет качество его решений.

Сравните два пути:

# Плохо — агент не понимает контекст
src/
  utils/
    helpers.ts        # Что здесь? Неизвестно
    misc.ts           # Ещё хуже
  services/
    service1.ts       # Какой сервис?
    handler.ts        # Чего?

# Хорошо — агент сразу понимает домен
src/
  billing/
    invoices/
      compute.ts      # Считает сумму инвойса
      validate.ts     # Проверяет инвойс перед сохранением
    subscriptions/
      renew.ts        # Логика продления подписки
      cancel.ts       # Отмена с возвратом средств
  auth/
    tokens/
      sign.ts         # Подписывает JWT
      verify.ts       # Верифицирует подпись

Путь ./billing/invoices/compute.ts сообщает агенту: домен (billing), поддомен (invoices), действие (compute). Он с высокой вероятностью найдёт нужный файл с первой попытки, не перебирая десятки кандидатов из utils/.

Принцип: много маленьких файлов

Размер файла — это не эстетика, это прагматика контекстного окна. Агент держит файл «в уме» целиком. Файл на 50 строк — полностью в контексте, все зависимости видны, ни одна деталь не выпадает. Файл на 800 строк — агент работает с частичным знанием, и его решения отражают это.

Характеристика Маленькие файлы (< 100 строк) Большие файлы (> 300 строк)
Видимость агента Полная — весь файл в контексте Частичная — агент работает с фрагментом
Точность правок Высокая — агент видит все зависимости Снижается — возможны коллизии с невидимыми частями
Навигация Быстрая — имя файла описывает содержимое Медленная — нужен поиск внутри файла
Тестируемость Высокая — один модуль, один ответственный Низкая — много ответственностей, сложно изолировать
Практическое правило: если файл больше 200 строк — спросите себя, не выполняет ли он несколько ответственностей. Если выполняет — разбейте. Это улучшит работу агента и заодно сделает код более тестируемым.

Именование как документация

Вкладывайте смысл в имена. Агент читает имя файла до того, как открывает его. Хорошее имя — это намерение, выраженное синтаксически:

Этот же принцип применяется к namespace-модулям. Billing::Invoices::ComputeTotal точнее говорит агенту, куда идти и что менять, чем Utils::BillingHelpers.

Быстрые эфемерные окружения

Агент работает в цикле: изменение → проверка → правка → повтор. Скорость этого цикла — это скорость агента. Медленные guardrails деградируют всё.

Быстро

Тест-сьют, линтер, type-checker должны укладываться в секунды для затронутых файлов и в 1–2 минуты для полного прогона. Если CI занимает 15 минут — агент либо ждёт, либо делает несколько изменений без проверки и накапливает ошибки. Оба варианта плохие.

Что ускоряет прогон:

Эфемерно

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

# Типичный сценарий с git worktree
git worktree add .worktrees/fix-invoice-rounding -b fix/invoice-rounding
cd .worktrees/fix-invoice-rounding

# Копируем конфиг, поднимаем изолированную БД
cp .env.example .env.local
DATABASE_URL=postgres://localhost/myapp_agent_001 bundle exec rails db:setup

# Запускаем агента в изолированном контексте
claude --worktree

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

Конкурентно

Несколько агентов должны работать одновременно без конфликтов. Это требует, чтобы окружения не делили состояние: отдельные порты, отдельные БД, отдельные кэши. Docker Compose с параметризованными именами сервисов решает это нативно:

# docker-compose.yml с параметризованным проектом
# Запуск: COMPOSE_PROJECT_NAME=agent_001 docker compose up -d
services:
  db:
    image: postgres:14
    ports:
      - "${DB_PORT:-5432}:5432"  # Каждый агент получает свой порт
  web:
    build: .
    environment:
      DATABASE_URL: postgres://db/${COMPOSE_PROJECT_NAME}_db
Практический результат: команды, внедрившие эфемерные окружения, сообщают о сокращении времени на «разборку с окружением» с часов до минут. Агент не тратит токены на диагностику конфигурационных проблем — он сразу работает над задачей.

Сквозная типизация

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

Без типов агент работает с семантически пустыми переменными: id, value, data. С типами — с конкретными доменными концептами:

# Без типов — агент не знает, что можно перепутать
def charge(user_id, amount, currency)
  ...
end

# С типами — агент видит контракт
# @param user_id [UserId]
# @param amount [Money]
# @param currency [CurrencyCode]
# @return [ChargeResult]
def charge(user_id, amount, currency)
  ...
end

Семантические имена типов

Примитивы — String, Integer — не несут доменного смысла. Создайте типы-обёртки с говорящими именами:

Примитив Семантический тип Что даёт агенту
String UserId Нельзя передать WorkspaceId туда, где ожидается UserId
String WorkspaceSlug Агент знает, что это URL-безопасная строка с конкретным форматом
String SignedWebhookPayload Тип гарантирует, что payload прошёл верификацию подписи
Integer CentsAmount Нельзя перепутать с Float-долларами — классическая ошибка биллинга
Hash ValidatedApiParams Агент знает, что эти параметры прошли валидацию схемы

Типизация на всех уровнях

Сквозная типизация означает последовательность от края до края системы:

# Пример: DB constraint как тип-гарантия
CREATE TABLE subscriptions (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id     uuid NOT NULL REFERENCES users(id),
  status      text NOT NULL CHECK (status IN ('active', 'paused', 'cancelled')),
  amount_cents integer NOT NULL CHECK (amount_cents > 0),
  currency    char(3) NOT NULL,
  created_at  timestamptz NOT NULL DEFAULT now()
);

-- Триггер как инвариант домена
CREATE FUNCTION check_subscription_invariants() RETURNS trigger AS $$
BEGIN
  IF NEW.status = 'active' AND NEW.cancelled_at IS NOT NULL THEN
    RAISE EXCEPTION 'Active subscription cannot have cancellation date';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Эффект для агентной разработки: когда агент вносит изменение, несовместимое с инвариантом, БД или статический анализатор немедленно это сигнализирует. Агент получает точную ошибку с местом, а не загадочное поведение в рантайме. Это сокращает debugging-циклы с десятков до единиц.

Автоматизация code review

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

Автоматические commit-сообщения из diff

LLM анализирует diff и генерирует описание по единым правилам (Conventional Commits или внутренний стандарт). Побочный эффект: если в описании появляется «add debug logging» или «remove TODO» — это сигнал, что что-то забыли убрать. Описание становится зеркалом, в котором виден реальный размах изменения.

LLM-ревью с кодифицированными правилами

Агент-ревьюер анализирует PR по чеклисту. Чеклист хранится в репозитории, версионируется и эволюционирует вместе с кодом:

# .claude/agents/code-reviewer.md
---
name: code-reviewer
description: Automated PR reviewer
tools: Read, Grep, Glob, Bash
---
Проверь PR по следующим критериям:

Архитектура:
- Функции не длиннее 50 строк
- Один файл — одна ответственность
- Нет циклических зависимостей между модулями

Безопасность:
- Нет захардкоженных секретов или ключей
- User input проходит валидацию перед использованием
- SQL-запросы используют параметризацию

Качество:
- Нет console.log / puts / pp в production-коде
- Все TODO привязаны к тикетам (формат: TODO(TICKET-123))
- Миграции обратимы (reversible)
- Новый код покрыт тестами

Самообучающийся процесс

После апрува PR отдельный промпт извлекает «уроки» из комментариев ревьюеров и дописывает их в правила ревью. Со временем типовые замечания — «здесь нужно добавить индекс», «не забыл про rollback?» — перестают повторяться: агент учится их предотвращать.

Распределение ответственности: автоматизированный ревьюер проверяет соответствие стандартам — это 70% типичного ревью. Человек фокусируется на архитектурных решениях, trade-offs и бизнес-логике. Senior-инженеры ценят своё время — не тратьте его на обнаружение console.log.

Практический минимум чеклиста

Категория Правило Почему важно
Размер Функции не длиннее 50 строк Большие функции сложнее тестировать и труднее держать в контексте
Конфигурация Нет захардкоженных значений Конфиги должны быть в ENV или конфигурационных файлах
Отладка Нет console.log / puts в коммите Отладочный вывод не должен попадать в production
Задачи Все TODO привязаны к тикетам TODO без тикета — это TODO навсегда
БД Миграции обратимы Необратимая миграция блокирует rollback в аварийной ситуации
Тесты Новый код покрыт тестами CI не проходит без теста на новое поведение

Закон Амдала и организация

В 1967 году Gene Amdahl сформулировал принцип, который точно описывает ловушку большинства AI-внедрений: ускорение части системы ограничено долей, которую эта часть занимает.

Формула Амдала:
Speedup = 1 / ((1 − P) + P / S)

где:
  P = доля задачи, которую можно ускорить (0 до 1)
  S = коэффициент ускорения этой части

Пример:
  Написание кода — 20% рабочего времени (P = 0.2)
  Агент ускоряет написание кода в 10 раз (S = 10)

  Speedup = 1 / ((1 − 0.2) + 0.2 / 10)
          = 1 / (0.8 + 0.02)
          = 1 / 0.82
          ≈ 1.22x

Ускорение написания кода в 10 раз даёт итоговое ускорение всего на 22%, а не на порядок. Потому что написание кода — это меньшая часть разработки.

В крупных компаниях разработчики пишут код около часа в день. Остальное время — планирование, ревью, тестирование, дебаг, документация, коммуникация. Это 80% времени, которое AI не трогает, если вы ускоряете только кодинг.

Где ещё применять агентов

Этап Доля времени Что делает агент
Планирование и спецификации 15–20% Исследует кодовую базу, задаёт контекстные вопросы, генерирует PRD и технические спеки за часы вместо недель
Code review 15–25% Автоматизирует проверку стандартов; человек смотрит только на решения и trade-offs
Тестирование 15–20% Генерирует тесты, находит пробелы в покрытии, пишет regression-тесты на баги
Дебаг 10–15% Получает симптомы, выдвигает гипотезы о root cause, пишет фикс с регрессионным тестом
Документация 5–10% PR-описания и диаграммы генерируются автоматически из diff и кода
Написание кода 15–25% Реализация по спецификации, scaffold типовых структур, рефакторинг

AI-агенты и малые команды

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

Малая команда с хорошими практиками может получить от агентов непропорционально высокий прирост. Именно поэтому WhatsApp обслуживал 600 миллионов пользователей с ~50 инженерами, а Instagram в момент продажи за $1 млрд имел команду в 13 человек: высокая доля прямой работы, минимум координационных потерь.

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

Резюме

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

Ключевая мысль: AI-агент возвращает цену инженерной дисциплины. Практики, которые раньше были «nice to have» — хорошие имена, маленькие функции, 100% тесты, типы — теперь напрямую влияют на то, насколько эффективно агент решает задачи. Это не про AI. Это про качество системы, которая теперь проверяется с беспрецедентной скоростью.