AI-агенты усиливают архитектуру — и хорошую, и плохую. Небрежность, которую опытный разработчик мог интуитивно компенсировать, агент масштабирует как системный дефект. Нечёткие имена файлов, отсутствие типов, тесты с покрытием «достаточно» — всё это превращается из технического долга в активный тормоз. Чтобы получить реальную отдачу от агентной разработки, нужно подготовить среду заранее.
100% покрытие кода тестами
Высокое покрытие тестами — это не про предотвращение багов. Это про гарантию того, что агент проверил поведение каждой строки, которую написал. Разница принципиальная: при 95% вы по-прежнему принимаете субъективные решения о том, что «достаточно важно» тестировать. При 100% происходит фазовый переход.
Это меняет процесс работы с агентом. Вместо того чтобы доверять агенту на слово или читать весь его код, вы запускаете тесты и получаете бинарный ответ: поведение подтверждено или нет. Агент итерирует в простом цикле — изменение, тест, правка, повтор — и каждый шаг верифицирован.
Побочные эффекты 100% покрытия
- Мёртвый код исчезает сам. Если строку невозможно покрыть — она недостижима. Агент либо удаляет её, либо создаёт тест, который доказывает, зачем она нужна.
- Edge cases становятся явными. Чтобы покрыть граничные условия, их нужно сначала формализовать. Тест — это документация намерения.
- Code review упрощается. Ревьюер видит тест и сразу понимает, что именно делает новый код — без необходимости реверс-инжинировать намерение из реализации.
- Рефакторинг безопаснее. Агент может агрессивно переписывать структуру, зная, что тесты поймают регрессию.
Logic Inc называют 100% покрытие «секретным оружием» агентной разработки. Их опыт: команды, начавшие с этого требования, получали предсказуемые результаты от агентов даже в сложных legacy-проектах. Команды, пропустившие этот шаг, сталкивались с тем, что агент корректно решал формулировку задачи, но ломал поведение в смежных модулях.
Пространства имён и структура файлов
Файловая система — это первичный навигационный 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 строк) |
|---|---|---|
| Видимость агента | Полная — весь файл в контексте | Частичная — агент работает с фрагментом |
| Точность правок | Высокая — агент видит все зависимости | Снижается — возможны коллизии с невидимыми частями |
| Навигация | Быстрая — имя файла описывает содержимое | Медленная — нужен поиск внутри файла |
| Тестируемость | Высокая — один модуль, один ответственный | Низкая — много ответственностей, сложно изолировать |
Именование как документация
Вкладывайте смысл в имена. Агент читает имя файла до того, как открывает его. Хорошее имя — это намерение, выраженное синтаксически:
parse_webhook_payload.rb— неwebhook_helper.rbcharge_subscription_monthly.rb— неbilling_service.rbvalidate_user_email_uniqueness.rb— неuser_validator.rb
Этот же принцип применяется к namespace-модулям. Billing::Invoices::ComputeTotal точнее говорит агенту, куда идти и что менять, чем Utils::BillingHelpers.
Быстрые эфемерные окружения
Агент работает в цикле: изменение → проверка → правка → повтор. Скорость этого цикла — это скорость агента. Медленные guardrails деградируют всё.
Быстро
Тест-сьют, линтер, type-checker должны укладываться в секунды для затронутых файлов и в 1–2 минуты для полного прогона. Если CI занимает 15 минут — агент либо ждёт, либо делает несколько изменений без проверки и накапливает ошибки. Оба варианта плохие.
Что ускоряет прогон:
- Параллельный запуск тестов (RSpec
--format progress+parallel_tests) - Запуск только тестов для изменённых файлов (guard, watchman)
- Кэширование зависимостей и слоёв Docker
- Изолированная тестовая база данных — без пересечений между прогонами
Эфемерно
Каждую задачу агент должен начинать в чистом окружении. Одна команда — и новая среда готова. Это устраняет класс проблем «работает у меня, не работает у агента» и позволяет безопасно экспериментировать: эфемерное окружение можно выбросить без последствий.
# Типичный сценарий с 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 |
Агент знает, что эти параметры прошли валидацию схемы |
Типизация на всех уровнях
Сквозная типизация означает последовательность от края до края системы:
- API-контракты: OpenAPI-схема описывает входы и выходы каждого endpoint. Агент генерирует клиентский код из схемы, а не угадывает структуру из примеров.
- Доменный слой: Sorbet (Ruby), TypeScript, Kotlin — типы на уровне методов и классов. Статический анализ находит ошибки до запуска.
- База данных: NOT NULL constraints, CHECK constraints, foreign keys, triggers для инвариантов. БД — последний рубеж обороны от невалидных данных.
# Пример: 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;
Автоматизация 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?» — перестают повторяться: агент учится их предотвращать.
Практический минимум чеклиста
| Категория | Правило | Почему важно |
|---|---|---|
| Размер | Функции не длиннее 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. Агент просто делает их ценность очевидной и немедленной.
- 100% покрытие тестами — фазовый переход: coverage-отчёт становится точным TODO-листом. Агент проверяет каждую строку.
- Структура файлов как навигационный API — путь к файлу должен сообщать домен, поддомен и действие. Много маленьких файлов с говорящими именами.
- Быстрые эфемерные окружения — одна команда для создания чистой среды. Агент итерирует быстро, без конфигурационных накладных расходов.
- Сквозная типизация — семантические типы, OpenAPI-схемы, DB constraints. Невалидные состояния обнаруживаются немедленно, а не в рантайме.
- Автоматизированный code review — стандарты проверяет агент, человек смотрит на решения. Процесс самообучается через уроки из PR.
- Закон Амдала — ускоряйте не только написание кода, а всю цепочку: планирование, ревью, тестирование, документацию.