← Назад к вопросам

Как строил архитектуру до Feature-Sliced Design?

2.3 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Эволюция архитектуры до Feature-Sliced Design

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

Монолитная структура по типам файлов (по технологии)

В начале 2010-х доминировал подход группировки файлов по их технологической принадлежности — классическая структура, унаследованная от бэкенда.

project/
├── css/
│   ├── main.css
│   └── reset.css
├── js/
│   ├── utils.js
│   ├── components.js
│   └── app.js
├── images/
└── index.html
  • Проблемы: При росте проекта папки css/ и js/ превращались в "свалку". Поиск кода, связанного с одной фичей (например, "корзины покупок"), требовал рысканья по всем директориям. Связность кода была низкой, а зацепление — высоким.

Подход с компонентами (с появлением React/Vue)

С приходом React и идеологии "компонентов" структура улучшилась, но часто оставалась плоской или слабо организованной.

src/
├── components/    # Все компоненты в одной куче
│   ├── Button.jsx
│   ├── Header.jsx
│   ├── ProductCard.jsx
│   └── ShoppingCart.jsx
├── containers/    # "Умные" компоненты
├── redux/         # Вся логика хранилища в одном месте
│   ├── actions.js
│   ├── reducer.js
│   └── store.js
├── utils/         # Общие утилиты
└── App.js
  • Недостатки: Директория components/ быстро раздувалась до сотен файлов. Компоненты, связанные с одной бизнес-логикой, были разбросаны. Redux-сторе становился "божественным объектом", куда сваливались экшены и редьюсеры со всего приложения. Тестирование и рефакторинг усложнялись.

Группировка по фичам (Feature-Based Folders)

Следующим логическим шагом стала группировка по бизнес-доменам или фичам — ранний прообраз FSD.

src/
├── cart/                   # Фича "Корзина"
│   ├── components/
│   │   ├── CartItem.jsx
│   │   └── CartSummary.jsx
│   ├── redux/
│   │   ├── actions.js
│   │   └── reducer.js
│   └── index.js           # Публичный API фичи
├── product/               # Фича "Продукт"
│   ├── components/
│   ├── redux/
│   └── api/
├── shared/                # Переиспользуемые ресурсы
│   ├── ui/
│   └── lib/
└── App.js

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

  • Где хранить общие компоненты (Button, Modal)? В shared/ui? А если они используются только в 2-3 фичах?
  • Как быть с кодом, который не относится к фиче, но нужен многим (например, formatDate)? Он попадал в shared/lib, которая со временем становилась "мусорным ведром".
  • Отсутствовали четкие правила взаимодействия между слоями. Фича cart могла импортировать что угодно из product, создавая скрытые зависимости.

Внедрение концепции "Слоев" (Layers)

Чтобы навести порядок в зависимостях, я начал явно разделять код по типу ответственности (слоям), часто вдохновляясь Clean Architecture и DDD.

// Пример слоистой структуры внутри фичи
src/features/cart/
├── model/          # Бизнес-логика, хранилище (Redux slice/MobX store)
├── ui/             # Компоненты, специфичные для этой фичи
├── lib/            # Вспомогательная логика фичи
└── api/            // Запросы к бэкенду, специфичные для корзины

Ключевое правило: Допустимы только нисходящие зависимости (например, ui может зависеть от model, но не наоборот). Это повышало тестируемость (бизнес-логику можно тестировать изолированно) и переиспользуемость.

Проблемы, которые оставались до FSD

Несмотря на все улучшения, несколько системных проблем сохранялись:

  1. Непоследовательность (Inconsistency): В каждом новом проекте или команде эти "лучшие практики" интерпретировались по-разному. Не было единого стандарта.
  2. Сложность масштабирования: При добавлении новых типов сущностей (например, hooks, constants) не было очевидно, куда их поместить.
  3. "Провал" общих ресурсов: Слой shared/ или common/ становился точкой хаотичного связывания удаленных частей приложения.
  4. Слабые границы модулей: Запрет на циклические зависимости и контроль направления импортов требовал ручного код-ревью и дисциплины, а не был встроен в архитектуру.

Итог и переход к FSD

Таким образом, эволюция шла от технологической группировки к бизнес-ориентированной, а затем к слоистой внутри бизнес-логики. Мы интуитивно стремились к высокий связности (cohesion) внутри модулей и низкому зацеплению (coupling) между ними.

Feature-Sliced Design стал закономерным и долгожданным итогом этого пути. Он систематизировал все эти наработки в единую, хорошо документированную методологию с:

  • Четкими слоями (app, processes, pages, features, entities, shared), определяющими уровень ответственности.
  • Жесткими правилами зависимостей (сверху вниз).
  • Сегментацией (slices) внутри features и entities, что окончательно решало проблему "раздутых" папок.
  • Публичным API каждого модуля для контроля инкапсуляции.

Опыт построения архитектуры "до FSD" бесценен — он позволяет по-настоящему оценить, какие боли решает эта методология, и осмысленно применять её принципы, а не слепо следовать правилам.