Архитектура фронтенда под LLM-агентов: Feature-Sliced Design, жесткие границы и кодогенерация
Активное использование автогенерирующих нейросетевых агентов во фронтенд-разработке кардинально меняет скорость появления пользовательских интерфейсов. На начальном этапе создания веб-приложения продуктивность выглядит впечатляюще: экраны собираются за считанные минуты, а готовый JSX-код выглядит опрятно. Однако при увеличении объема клиентской базы и усложнении логики проявляется фундаментальная проблема: структура клиентского кода начинает деградировать значительно быстрее бэкенда. Разработка упирается в гигантские файлы компонентов, неконтролируемое дублирование элементов интерфейса и бесконечный каскад повторных рендеров.
Для сохранения стабильности инженерного конвейера требуется архитектурная модель, специально спроектированная под ограниченный размер контекстного окна нейросети. Применение адаптированного трехслойного Feature-Sliced Design в сочетании со строгим статическим анализом зависимостей позволяет удерживать высокий темп разработки без превращения репозитория в неконтролируемый монолит.
Причины ускоренной деградации фронтенд-кода под управлением LLM
Быстрый рост технического долга на клиентской стороне под управлением LLM-агентов обусловлен двумя ключевыми факторами: особенностями обучающих выборок моделей и спецификой декларативного синтаксиса JSX.
Во-первых, обучающая выборка современных моделей содержит вперемешку три различных поколения библиотеки React: устаревшие классовые компоненты, подходы с ручным вызовом эффектов при маунтинге компонента и современные серверные компоненты. Не имея жестких рамок и локальных эталонов в рамках конкретного проекта, модель начинает смешивать паттерны разных лет в одном файле.
Во-вторых, сама природа JSX позволяет объединять в одном модуле разметку, бизнес-логику, стилистическое оформление и управление состоянием. На бэкенде для нарушения границ слоев агенту требуется добавить невалидный импорт, который легко фиксируется линтером. На фронтенде модель всегда выбирает наименее затратный путь: добавить еще одно состояние useState и тридцать строк JSX в существующий файл вместо создания выделенного модуля. В результате компоненты страниц разрастаются до сотен строк за считанные дни.
Проектирование трехслойной структуры Feature-Sliced Design
Классическая методология Feature-Sliced Design (FSD) предлагает до шести горизонтальных слоев, что часто приводит к преждевременной абстракции в продуктах среднего размера. Для оптимизации работы LLM-агентов используется упрощенная трехслойная структура, минимизирующая объемы контекста:
- Слой приложения (
app/): содержит маршрутизацию Next.js и верхнеуровневую композицию. Выполняет роль тонких контроллеров, собирающих страницы из изолированных пользовательских сценариев. - Слой пользовательских сценариев (
src/features/): вертикальные слайсы, сгруппированные по продуктовому смыслу (upload-photo,buy-credits,cancel-task). Каждый слайс содержит собственную разметку, локальную логику и типы. - Слой фундамента (
src/shared/): глобальная инфраструктура, не обладающая знанием о продуктовом домене. Включает UI-кит базовых компонентов (shared/ui), API-клиент (shared/api), интернационализацию и вспомогательные утилиты.
Импорты разрешены строго сверху вниз: app → features → shared. Любые горизонтальные зависимости между слайсами внутри слоя features полностью запрещены. Если нескольким сценариям требуется общий компонент или логика, этот элемент спускается в слой shared. Каждая папка сценария предоставляет единую точку входа через index.ts, скрывая внутреннюю реализацию от внешнего мира.
Автоматический контроль архитектурных границ с помощью dependency-cruiser
Правила архитектуры, записанные исключительно в текстовых инструкциях, регулярно нарушаются нейросетевыми агентами. Для жесткого контроля связей между модулями применяется статический анализатор граф-зависимостей dependency-cruiser. Конфигурация .dependency-cruiser.cjs описывает недопустимые связи:
module.exports = {
forbidden: [
{
name: "feature-public-api",
severity: "error",
comment: "Внешние модули импортируют фичу строго через ее index.ts",
from: { path: "^app/" },
to: { path: "^src/features/", pathNot: "index\.ts$" }
},
{
name: "no-shared-to-features-app",
severity: "error",
comment: "Слой shared не может зависеть от верхних слоев features и app",
from: { path: "^src/shared/" },
to: { path: "^(src/features/|app/)" }
},
{
name: "no-cross-feature",
severity: "error",
comment: "Запрещены прямые зависимости между соседними фичами",
from: { path: "(^src/features/)([^/]+)/" },
to: { path: "^$1", pathNot: "$1$2/" }
},
{
name: "no-circular",
severity: "error",
comment: "Циклические зависимости запрещены",
from: {},
to: { circular: true }
}
]
};
Текстовое поле comment в конфигурации линтера формируется как лаконичное руководство для нейросети. При попытке совершить невалидный импорт агент получает точное текстовое сообщение об ошибке с пояснением, как именно следует исправить структуру кода.
Синхронизация бэкенд-контрактов через OpenAPI и TanStack Query
Для исключения ошибок при взаимодействии с бэкендом доменная модель на клиентской стороне полностью заменяется автогенерируемым API-клиентом. Бэкенд экспортирует спецификацию OpenAPI, из которой утилита orval автоматически генерирует TypeScript-типы и хуки для библиотеки TanStack Query.
Это гарантирует отсутствие ручного кода для отправки HTTP-запросов и исключает неверные имена полей в ответах. Любое изменение структуры данных на сервере приводит к ошибке компиляции TypeScript, давая агенту четкий сигнал для проведения рефакторинга.
Вторым критическим инвариантом является разделение управления состоянием. Все серверные данные и их кэширование находятся под управлением TanStack Query. В локальном состоянии useState или клиенте Zustand хранятся исключительно UI-флаги (активные вкладки, статус открытия модальных окон, введенные в формы значения). Копирование данных ответа сервера в локальный useState категорически запрещено для предотвращения рассинхронизации интерфейса.
Локализация стилей в Tailwind и визуальный контроль через Playwright
Использование традиционных CSS-файлов создает проблемы при работе LLM-агентов из-за необходимости удерживать в контексте два связанных файла (разметку и стили). Применение утилитарного фреймворка Tailwind CSS объединяет описание внешнего вида с разметкой в одной строке, устраняя возможность расхождения классов. Дискретный набор токенов Tailwind заставляет модель использовать строго определенную систему отступов и цветов.
Для решения проблемы "слепой верстки", когда формально валидный код создаёт визуальные дефекты на экране, в конвейер внедряются автоматизированные скриншотные тесты Playwright. Агент запускает безголовый браузер, выполняет скриншот ключевых сценариев и проверяет корректность отображения элементов перед отправкой изменений.
Практические правила для файла инструкций LLM-агента
Для повседневного применения сформирован наглядный список правил:
- Карта проекта:
app/(маршруты, композиция) →src/features/(продуктовые сценарии) →src/shared/(UI-кит, API, инфраструктура). - Единый источник серверных данных: использование хуков из
src/shared/api/generated. Ручное создание функцийfetchзапрещено. - Изоляция состояния: серверными данными управляет TanStack Query, в
useStateпомещаются только интерактивные UI-флаги. - Единственность базовых компонентов: перед созданием новых элементов интерфейса выполняется обязательный поиск по
src/shared/ui. - Запрет синхронизационных эффектов: вызовы
useEffectприменяются исключительно для интеграции с внешними браузерными API, но не для управления состоянием.

![Node.JS [ru]](/api/digests/it_development/daily/20260722/assets/sources/we-use-js.jpg)