В чем разница между модульной архитектурой и FSD?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между модульной архитектурой и FSD?
Модульная архитектура (Module Architecture) и Feature-Sliced Design (FSD) - два популярных подхода к организации кода фронтенда. Оба решают проблему масштабируемости, но работают по разным принципам.
Модульная архитектура
Модульная архитектура группирует файлы по типам (функциональность):
project/
├── components/
│ ├── Button/
│ ├── Modal/
│ ├── Card/
│ └── Header/
├── pages/
│ ├── Home.tsx
│ ├── Profile.tsx
│ └── Settings.tsx
├── hooks/
│ ├── useAuth.ts
│ ├── useApi.ts
│ └── useModal.ts
├── utils/
│ ├── api.ts
│ ├── constants.ts
│ └── helpers.ts
├── types/
│ └── index.ts
└── styles/
└── globals.css
Характеристики:
- Файлы группируются по типам (компоненты, хуки, утилиты)
- Простая структура для небольших проектов
- Компоненты переиспользуются везде
- Зависимости "снизу вверх" (utils -> components -> pages)
Feature-Sliced Design (FSD)
FSD группирует файлы по фичам (features), которые содержат всё необходимое:
project/
├── shared/
│ ├── ui/
│ │ ├── Button/
│ │ ├── Modal/
│ │ └── Card/
│ ├── lib/
│ │ ├── api.ts
│ │ └── utils.ts
│ └── types/
│ └── index.ts
├── features/
│ ├── auth/
│ │ ├── ui/
│ │ │ ├── LoginForm/
│ │ │ └── RegisterForm/
│ │ ├── model/
│ │ │ ├── authStore.ts
│ │ │ └── authSlice.ts
│ │ ├── api/
│ │ │ └── authApi.ts
│ │ └── index.ts (public API)
│ ├── profile/
│ │ ├── ui/
│ │ │ └── ProfileCard/
│ │ ├── model/
│ │ │ └── profileStore.ts
│ │ ├── api/
│ │ │ └── profileApi.ts
│ │ └── index.ts
│ └── products/
│ ├── ui/
│ ├── model/
│ ├── api/
│ └── index.ts
├── pages/
│ ├── home/
│ ├── profile/
│ └── not-found/
└── app/
├── App.tsx
├── layout.tsx
└── providers.tsx
Характеристики:
- Файлы организованы по слоям: ui, model (state, logic), api
- Каждая фича - независимый модуль
- Слои: shared <- features <- pages <- app
- Явный public API (index.ts) для каждой фичи
- Контролируемые зависимости
Основные различия
1. Организация кода
Модульная архитектура (по типам):
components/
Button.tsx <- используется везде
Modal.tsx <- используется везде
UserCard.tsx <- используется везде
ProductCard.tsx <- используется везде
FSD (по фичам):
features/
auth/
ui/
LoginForm.tsx <- только для auth
RegisterForm.tsx <- только для auth
products/
ui/
ProductCard.tsx <- только для products
2. Зависимости
Модульная архитектура - свободные зависимости:
// pages/Home.tsx может зависеть от любого компонента
import { Button, Modal, Card } from '../components';
import { useAuth } from '../hooks';
import { formatDate } from '../utils';
// Сложно отследить, кто от кого зависит
FSD - контролируемые зависимости:
// pages/home/Home.tsx может зависеть только от:
// 1. features/* (через index.ts)
// 2. shared/* (общие компоненты)
import { AuthWidget } from '@/features/auth';
import { ProductList } from '@/features/products';
import { Button } from '@/shared/ui/Button';
// Понятен граф зависимостей
3. Переиспользование компонентов
Модульная архитектура:
// UserCard используется везде
// components/UserCard.tsx
export interface UserCardProps {
user: User;
showStats?: boolean; // для Home
showActions?: boolean; // для Admin
showFollowButton?: boolean; // для Search
compact?: boolean; // для Mobile
// Растет число пропсов...
}
// Компонент становится перегруженным
FSD:
// Разные компоненты для разных фич
// features/profile/ui/UserCard.tsx
export interface UserCardProps {
user: User;
showStats: boolean; // Все пропсы релевантны для этой фичи
}
// features/search/ui/UserCard.tsx
export interface UserCardProps {
user: User;
onFollow: () => void; // Другие пропсы для поиска
}
// Компоненты специализированы
4. Масштабируемость
Модульная архитектура при росте:
components/ <- растет невероятно быстро
├── 50+ компонентов
├── Сложно ориентироваться
└── Конфликты в pull requests
hooks/ <- много пересекающейся логики
└── useUser, useUserForm, useUserEdit, useUserCreate
<- какой использовать когда?
FSD при росте:
features/
├── auth/
│ ├── ui/ <- 3-5 компонентов
│ ├── model/
│ └── api/
├── profile/ <- изолированная фича
└── products/
<- ясная структура, легко добавлять новые фичи
Практическое сравнение
Сценарий: Добавить новую фичу "Wishlist"
Модульная архитектура:
// 1. Создать компоненты
components/
WishlistButton.tsx
WishlistModal.tsx
WishlistItem.tsx
// 2. Создать хук
hooks/
useWishlist.ts
// 3. Создать утилиты
utils/
wishlistApi.ts
// 4. Обновить типы
types/
index.ts <- добавить Wishlist типы
// 5. Интегрировать везде
pages/
Home.tsx <- import WishlistButton
Product.tsx <- import WishlistButton
Search.tsx <- import WishlistButton
// Проблемы:
// - Файлы разбросаны по папкам
// - Можно неправильно импортировать
// - Вся логика Wishlist разделена
FSD:
// 1. Создать фичу
features/wishlist/
ui/
WishlistButton.tsx
WishlistModal.tsx
WishlistItem.tsx
model/
wishlistStore.ts
wishlistSlice.ts
api/
wishlistApi.ts
index.ts <- публичный API
// 2. Интегрировать везде
pages/home/Home.tsx
import { WishlistButton } from '@/features/wishlist';
pages/product/Product.tsx
import { WishlistButton } from '@/features/wishlist';
// Преимущества:
// - Вся логика Wishlist в одной папке
// - Понятный импорт из '@/features/wishlist'
// - Легко удалить фичу если не нужна
// - Четкая граница фичи
Сценарий: Переименовать компонент
Модульная архитектура:
// UserCard -> PersonCard
// Нужно найти все импорты
components/UserCard.tsx // переименовать
pages/Home.tsx
import { UserCard } from '../components'; // обновить
pages/Profile.tsx
import { UserCard } from '../components'; // обновить
pages/Search.tsx
import { UserCard } from '../components'; // обновить
hooks/useUserCard.ts // переименовать?
// Много мест для ошибки
FSD:
// Если PersonCard специфична для фичи profile
features/profile/ui/PersonCard.tsx
// Одна строка для изменения (index.ts)
features/profile/index.ts
export { PersonCard } from './ui/PersonCard';
// Все импорты автоматически обновляются
pages/profile/Profile.tsx
import { PersonCard } from '@/features/profile';
// Не нужно менять, потому что публичный API не изменился
Комбинированный подход
project/
├── shared/ <- FSD слой (модульная архитектура)
│ ├── ui/
│ │ ├── Button/
│ │ └── Modal/
│ ├── lib/
│ │ ├── api.ts
│ │ └── utils.ts
│ └── types/
│
├── features/ <- FSD слой
│ ├── auth/
│ ├── profile/
│ └── products/
│
├── pages/ <- FSD слой
│ ├── home/
│ ├── profile/
│ └── products/
│
└── app/ <- точка входа
├── App.tsx
└── providers.tsx
// Внутри каждого слоя - модульная архитектура
// features/auth/model содержит authStore.ts, authSlice.ts и т.д.
Когда использовать
Модульная архитектура подходит для:
- Маленьких проектов (<10 страниц)
- Прототипов и MVP
- Проектов с четкой разделением на componets/hooks/utils
- Когда не ясны границы фич
FSD подходит для:
- Больших проектов (10+ фич)
- Долгосрочных проектов
- Когда нужна масштабируемость
- Когда работает большая команда
- Когда есть четкие фичи/домены
Практическая рекомендация
// Гибридный подход
// FSD на макро-уровне (features), модульная на микро-уровне
project/
shared/
├── ui/ <- модульная архитектура
│ ├── Button/
│ ├── Modal/
│ └── Card/
├── lib/
├── hooks/
└── types/
features/ <- FSD на макро-уровне
auth/
ui/ <- модульная архитектура внутри
model/
api/
hooks/
types/
index.ts
// Это лучший баланс между масштабируемостью и простотой
Итоговое сравнение
| Аспект | Модульная | FSD |
|---|---|---|
| Простота | Выше | Ниже |
| Масштабируемость | Низкая | Высокая |
| Размер проекта | Маленький | Большой |
| Кривая обучения | Низкая | Средняя |
| Переиспользование | Максимальное | Контролируемое |
| Организованность | Разбросано | Структурировано |
| Удаление фичи | Сложно | Просто |
Рекомендация: начни с модульной архитектуры, при росте проекта переходи на FSD постепенно.