Как выбрать архитектуру frontend приложения: сравнение подходов и критерии

22 апреля 2026 г.

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

Что такое архитектура frontend на самом деле

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

  • как разделяются ответственности (UI, бизнес-логика, работа с данными, маршрутизация);
  • как модули общаются друг с другом (прямые импорты, события, глобальное состояние, DI);
  • как управляется состояние и побочные эффекты (сетевые запросы, таймеры, WebSocket);
  • как масштабируется код при росте команды и функционала;
  • как тестируются изолированные части приложения.

Три ключевых аспекта архитектуры

Для практической работы я рекомендую оценивать архитектуру по трём осям:

  1. Связанность (coupling) — насколько изменение одного модуля требует изменения других. Низкая связанность — хорошо.
  2. Связность (cohesion) — насколько код внутри одного модуля решает одну чёткую задачу. Высокая связность — хорошо.
  3. Скорость онбординга — за сколько времени новый разработчик поймёт, куда добавить новую фичу.

Правильный выбор архитектуры напрямую влияет на скорость разработки, частоту багов и возможность переиспользовать код между проектами. В отличие от бэкенда, где архитектурные решения часто стандартизированы (чистая архитектура, гексагональная, DDD), фронтенд до сих пор переживает активный поиск «серебряной пули». И её нет. Но есть набор проверенных подходов.

Компонентный подход: база любого современного фронта

Все современные фреймворки (React, Vue, Svelte, Angular) построены вокруг компонентов. Компонент — это самодостаточная часть интерфейса со своей логикой и стилями. Компонентная архитектура сама по себе не решает всех проблем, но это фундамент, без которого остальные подходы не работают.

Атомная архитектура (Atomic Design)

Атомный дизайн (Брэд Фрост) предлагает иерархию: атомы → молекулы → организмы → шаблоны → страницы. Это способ организации компонентной архитектуры, а не отдельный архитектурный подход.

  • Атомы — базовые HTML-элементы: кнопка, инпут, лейбл.
  • Молекулы — комбинации атомов: поле поиска (инпут + кнопка).
  • Организмы — сложные блоки: шапка сайта (лого + навигация + поиск).
  • Шаблоны — каркасы страниц без данных.
  • Страницы — шаблоны с реальными данными.

На практике атомный дизайн хорошо работает в дизайн-системах (например, Material UI, Chakra UI), но часто избыточен для продуктовой разработки — вы рискуете утонуть в бесконечных переименованиях «атом/молекула/организм».

Практический совет: не пытайтесь насильно вписать каждый компонент в категорию. Лучше выделите только два уровня: ui/ (переиспользуемые примитивы — кнопки, инпуты, карточки) и features/ или widgets/ (бизнес-блоки, которые используют ui).

Пример организации папок

src/
  components/
    ui/
      Button/
        Button.tsx
        Button.module.css
      Input/
    features/
      ProductCard/
        ProductCard.tsx
        ProductCard.module.css
      CartIcon/
    pages/
      HomePage/
      ProductPage/
  hooks/
  utils/
  types/

Когда подходит: небольшие проекты (лендинги, админки на 5–10 экранов), прототипы, одностраничные приложения без сложной бизнес-логики. Команда до 3 человек может работать эффективно без дополнительных слоёв.

Когда начинает ломаться: когда компоненты начинают знать слишком много друг о друге, когда состояние «поднимается» на несколько уровней вверх, когда появляются «компоненты-боги» на 500+ строк, когда вы ловите себя на циклических импортах.

Модульная архитектура: изоляция и границы

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

  • фичей (например, «корзина», «профиль пользователя», «чат»);
  • слоем (например, API клиент, логирование, UI-kit);
  • доменом (если вы практикуете Domain-Driven Design на фронте).

Правила работы с модулями

Главное правило модульной архитектуры: модуль не должен напрямую импортировать из внутренностей другого модуля. Только через публичный API (index.ts).

// Плохо: импорт из внутренностей чужого модуля
import { formatPrice } from '../cart/utils/priceFormatter';

// Хорошо: через публичный API
import { formatPrice } from '../cart';
// где в cart/index.ts:
// export { formatPrice } from './utils/priceFormatter';

Это позволяет менять реализацию модуля (например, переименовать priceFormatter.ts в format.ts) без каскадных изменений по всему проекту.

Инструменты для контроля границ

Без автоматической проверки модульная архитектура быстро превращается в «модульную на словах». Используйте:

  • eslint-plugin-boundaries — запрещает импорты из запрещённых путей;
  • dependency-cruiser — визуализирует граф зависимостей и находит циклы;
  • настройки tsconfig.json с paths — создайте алиасы вроде @modules/cart.

Когда выбирать: проекты среднего размера (20–50 экранов), команда 5–10 человек. Вы уже столкнулись с тем, что изменение одного компонента ломает три других, и хотите ввести дисциплину.

Feature-Sliced Design (FSD): архитектура для больших команд

Feature-Sliced Design — это методология, которая набирает популярность в крупных фронтенд-проектах (особенно в React-сообществе). FSD предлагает жёсткие слои и вертикальные слайсы (фичи). В отличие от модульной архитектуры, FSD не оставляет пространства для интерпретации — правила чётко прописаны.

Структура FSD изнутри

Стандартные слои снизу вверх (зависимости идут только сверху вниз):

src/
  app/                    # настройка приложения, роутинг, провайдеры
    store.ts
    router.tsx
    App.tsx
  pages/                  # страницы, собирают виджеты и фичи
    HomePage/
    ProductPage/
  widgets/                # крупные блоки интерфейса (шапка, футер, сайдбар)
    Header/
    CartSidebar/
  features/               # пользовательские сценарии (добавить в корзину, авторизация)
    addToCart/
    userLogin/
  entities/               # бизнес-сущности (пользователь, товар, заказ)
    User/
    Product/
  shared/                 # переиспользуемый UI-kit, утилиты, API клиент
    ui/
    api/
    lib/

Ключевое правило FSD: нижележащий слой не может импортировать из вышележащего. shared не знает об entities, entities не знает о features. Нарушение этого правила линтером блокируется.

Плюсы и минусы FSD на практике

Плюсы FSD:

  • стандарт для больших команд (новый разработчик быстро понимает, куда класть код);
  • жёсткие правила предотвращают хаос и циклические зависимости;
  • легко тестировать изолированно фичи (каждый слайс — потенциальный кандидат на module federation);
  • естественным образом ведёт к чистой архитектуре на фронте.

Минусы FSD:

  • оверхед на маленьких проектах (вы пишете больше структуры, чем кода);
  • сложно вводить постепенно (требует рефакторинга с нуля или почти с нуля);
  • сообщество ещё молодое, инструменты поддержки (плагины, кодогенерация) менее зрелые, чем у альтернатив;
  • не все согласны с границами «фича vs виджет» — частые споры на код-ревью.

Когда FSD — это перебор

Не используйте FSD если:

  • ваша команда меньше 8–10 человек (администрирование архитектуры съест время);
  • проект живёт меньше года (вы не успеете окупить рефакторинг);
  • у вас простое приложение с 2–3 маршрутами (лендинг, блог, форма обратной связи).

Когда выбирать: проекты enterprise-уровня (100+ экранов, 15+ разработчиков, срок жизни 3+ года, несколько команд, работающих над одним приложением).

Flux и Redux: управление состоянием как архитектурная основа

Flux (паттерн от Facebook) и его самая популярная реализация Redux часто воспринимаются как «архитектура всего приложения». Это не совсем так. Redux решает проблему управления глобальным состоянием, но не диктует, как организовывать компоненты или изолировать фичи. Тем не менее, в проектах на React + Redux архитектура часто строится вокруг хранилища.

Пример архитектуры на Redux

src/
  store/
    store.ts
    rootReducer.ts
  slices/
    cartSlice.ts      # состояние корзины + редьюсеры
    userSlice.ts
    productsSlice.ts
  hooks/
    useAppDispatch.ts
    useAppSelector.ts
  components/
    Cart/
      Cart.tsx
      Cart.module.css

Типичный поток данных: компонент → dispatch(action) → store → reducer → обновление состояния → перерисовка компонентов. Бизнес-логика живёт в редьюсерах и сайд-эффектах (redux-thunk, redux-saga, RTK Query).

Когда Redux помогает архитектуре:

  • когда у вас сложное глобальное состояние, которое обновляется из разных мест (корзина, пользователь, уведомления, кэш);
  • когда нужен time-travel debugging и предсказуемость изменений (Redux DevTools);
  • когда команда уже знает Redux и может поддерживать дисциплину (единый источник истины).

Когда Redux мешает:

  • если вы используете Redux для всего, включая локальное состояние формы (оверкилл);
  • если вы не используете Redux Toolkit (рискуете написать тонны бойлерплейта);
  • если у вас простое приложение, где можно обойтись Context API или сигналами.

Современные альтернативы Redux

Для проектов, где Redux кажется тяжёлым, рассмотрите:

  • Zustand — минимальный API, меньше бойлерплейта, работает вне React (можно использовать в утилитах);
  • Jotai — атомарное состояние, отлично для сложных форм и локальных состояний с зависимостями;
  • Valtio — мутабельный API с прокси (ближе к Vue, но для React).

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

MVC на фронтенде: классика, которая всё ещё работает

Model-View-Controller пришёл на фронтенд из бэкенда и десктопной разработки.

MVC в Angular

Angular (до сих пор) — яркий пример MVC/MVVM на фронте. Компонент Angular — это Controller + View, а сервисы играют роль Model. Это работает и масштабируется, но требует дисциплины.

MVVM во Vue и Svelte

Паттерн Model-View-ViewModel живёт во Vue и Svelte (реактивные данные). ViewModel — это реактивные свойства компонента, Model — бизнес-логика в композаблах (Vue) или stores (Svelte).

Практический вывод: не пытайтесь внедрить классический MVC в React — это будет бороться с парадигмой (React — это View + побочные эффекты). Но идея «отделяй данные от представления» остаётся золотым правилом. Держите бизнес-логику в хуках/сервисах, а не внутри JSX.

Сравнение архитектур по ключевым критериям

Полная таблица сравнения

Критерий Компонентная Модульная FSD Redux как архитектура
Размер команды 1–3 чел. 4–10 чел. 10+ чел. любая (если нужно глобальное состояние)
Количество экранов/фич < 20 20–80 80+
Сложность бизнес-логики низкая средняя высокая высокая (глобальное состояние)
Нужна ли изоляция фич для тестирования нет да да, строгая частично
Срок жизни проекта < 6 мес 6–24 мес 2+ года
Готовность к оверхеду низкая средняя высокая средняя
Скорость онбординга (часы) 2–4 8–16 16–24 4–8 (если знают Redux)
Сложность рефакторинга при смене подхода низкая средняя очень высокая высокая (если состояние везде)

Метрики для выбора архитектуры

Я рекомендую собирать метрики с вашего текущего проекта, чтобы принимать решение об архитектуре на основе данных, а не ощущений:

  • Время добавления новой фичи (от задачи до PR) — растёт ли оно линейно с размером кодовой базы?
  • Частота багов при изменении общего модуля (например, правка в API клиенте ломает 5 компонентов).
  • Количество циклических зависимостей (инструменты вроде madge или dependency-cruiser).
  • Testability — сколько времени уходит на моки для unit-тестов? Если вы мокаете 10 модулей на тест — связанность высокая.

Как выбрать архитектуру frontend приложения: пошаговый чек-лист

Алгоритм действий от MVP до enterprise

Шаг 1. Начинайте с компонентного подхода + папка shared/ui. Этого достаточно для MVP и первых 3–6 месяцев разработки. Не думайте о FSD и Redux, пока у вас нет 10+ экранов.

Шаг 2. Введите модульную архитектуру, когда почувствуете боль. Сигналы: компонент A импортирует из компонента B, а B из A (циклические зависимости); изменение в одном модуле ломает три других; вы тратите больше 20% времени на поиск файлов, а не на написание кода.

Шаг 3. Добавьте глобальное хранилище (Redux/Zustand) по потребности. Не делайте это «на всякий случай». Глобальное состояние нужно, когда данные используются в нескольких несвязанных компонентах на разных страницах.

Шаг 4. Рассмотрите FSD, если: команда выросла до 15+ человек; несколько фич-команд работают над одним репозиторием; вы тратите часы на Code Review из-за споров «куда положить этот компонент»; вам нужна возможность вынести фичу в отдельный micro-frontend.

Принятие решения по балльной системе

Оцените свой проект от 1 до 5 по каждому критерию и сложите баллы. Рекомендация — та архитектура, которая набрала максимум.

Критерий Компонентная Модульная FSD
Команда <= 3 человека +3 +1 0
Команда 4–10 человек +1 +3 +1
Команда 10+ человек 0 +2 +5
Срок жизни < 1 года +3 +2 0
Срок жизни > 2 лет +1 +3 +5
Частота изменения требований (высокая) 0 +2 +4
Нужен быстрый прототип +5 0 0

Антипаттерны и типичные ошибки

Топ-5 ошибок при выборе архитектуры

Ошибка 1. Выбор FSD для лендинга или пет-проекта. Вы потратите 80% времени на организацию кода вместо реализации фич. FSD даёт ценность только на масштабе 15+ человек и 2+ года разработки.

Ошибка 2. Игнорирование архитектуры вообще («просто скину всё в components/»). Это работает первые 2 месяца. На шестом месяце у вас будет 200 компонентов в одной папке, и вы не сможете найти, где лежит кнопка «Купить». Вы начнёте дублировать код, потому что «проще скопировать, чем искать».

Ошибка 3. Смешивание слоёв в FSD. Например, импорт из features в shared или из pages в entities. FSD запрещает импорт сверху вниз. Нарушайте это правило — и архитектура развалится. Используйте eslint-plugin-fsd для автоматической проверки.

Ошибка 4. Дублирование бизнес-логики в компонентах. Когда одна и та же логика расчёта скидки скопирована в трёх местах, любой баг фиксится трижды. Выносите логику в хуки или сервисы. Пример:

// Плохо: логика внутри компонента
function ProductCard({ price, discount }) {
  const finalPrice = price * (1 - discount / 100);
  return <div>{finalPrice}</div>;
}

// Хорошо: вынесено в хук или утилиту
function useFinalPrice(price, discount) {
  return price * (1 - discount / 100);
}

Ошибка 5. Выбор архитектуры под влиянием хайпа. «Все пишут на FSD, давай и мы». Оценивайте трезво: сколько у вас разработчиков, как долго живёт проект, как часто меняются требования. Помните: архитектура должна решать ваши проблемы, а не создавать новые.

Как исправлять последствия

Если вы уже выбрали неподходящую архитектуру, не пытайтесь переписать всё за один спринт. Действуйте постепенно:

  1. Введите архитектурные границы только для новой кодовой базы (новые фичи пишите на новой архитектуре).
  2. Постепенно рефакторьте старые модули, когда вы их трогаете (boy scout rule — «оставь место чище, чем нашёл»).
  3. Используйте feature flags, чтобы постепенно переключать старую и новую реализацию.
  4. Не стесняйтесь оставить старый код как есть, если он стабилен и не мешает разработке.

Вывод: не переусложняйте, но планируйте рост

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

Помните: архитектура — это инструмент, а не религия. Если через месяц вы поймёте, что выбрали не тот подход, рефакторинг — это нормально. Но если вы на старте добавили FSD и Redux для трёх экранов, рефакторить придётся всё, включая дизайн-систему. И это будет больно.

И последнее: лучшая архитектура — та, которую понимает вся команда, а не только её автор. Документируйте соглашения (например, в docs/architecture.md), автоматически проверяйте правила (линтерами), и ваше приложение проживёт долго и счастливо. А если вы не уверены — начните с компонентной архитектуры и модульных границ через index.ts. Это даст 80% пользы при 20% усилий.