Что такое FSD и зачем он нужен
Что такое FSD и зачем он нужен
Представьте: вы открываете проект, которому год. В папке components — 200 файлов. Половина называется Card, CardNew, CardV2, CardFinal. Хочешь найти логику авторизации — она размазана между hooks/useAuth.ts, services/authService.ts и components/LoginForm. Хочешь добавить новую фичу — боишься, потому что непонятно, что сломается. Знакомо? Именно эту боль решает Feature-Sliced Design.
Проблема, которую решает FSD
Большинство фронтенд-проектов начинаются одинаково: папки components, pages, hooks, utils. Это работает, пока проект маленький. Но когда команда растёт, фич становится больше, а требования меняются — структура начинает работать против вас.
Конкретные симптомы:
- Новый разработчик не может понять, куда добавить код, не спросив коллегу
- Изменение одного компонента ломает три других в неожиданных местах
- Один и тот же бизнес-объект (например, «пользователь») описывается в пяти разных местах
- Импорты превращаются в спагетти:
componentsимпортирует изpages,pagesизhooks,hooksизcomponents
Это называют "big ball of mud" — архитектурный антипаттерн, когда у кода нет структуры, только хаос, который нарастает со временем.
Что такое Feature-Sliced Design
Feature-Sliced Design (FSD) — это архитектурная методология для фронтенд-приложений, которая организует код вокруг бизнес-функциональности, а не технических деталей.
Проще говоря: вместо того чтобы складывать файлы по типу («все компоненты сюда, все хуки туда»), вы складываете их по смыслу — «всё, что связано с корзиной, — сюда; всё, что связано с профилем пользователя, — туда».
FSD вводит два измерения организации кода:
- Слои (layers) — горизонтальное разделение по уровню абстракции. Это фиксированный набор папок верхнего уровня:
shared,entities,features,widgets,pages,processes,app. - Слайсы (slices) — вертикальное разделение внутри слоя по доменам. Например, внутри
featuresбудут слайсыadd-to-cart,auth-by-email,edit-profile.
Внутри каждого слайса код делится на сегменты (segments) по технической роли: ui, model, api, lib, config.
Аналогия из жизни: представьте большой офис. Слои — это этажи здания (бухгалтерия на 2-м, разработка на 3-м, менеджмент на 4-м). Слайсы — это отделы на каждом этаже. Сегменты — это конкретные рабочие места внутри отдела. Каждый знает, где что находится, и никто не ходит на чужой этаж без причины.
Главное правило: зависимости только вниз
Ключевой принцип FSD — однонаправленные зависимости. Слой может импортировать только из слоёв, которые находятся ниже него в иерархии. Никогда — из слоёв выше.
Иерархия слоёв (от верхнего к нижнему):
app → processes → pages → widgets → features → entities → shared
Это значит: features может использовать entities и shared, но не может импортировать из pages или app. Нарушение этого правила создаёт циклические зависимости и превращает проект в тот самый клубок спагетти.
Пример нарушения, которое выглядит невинно, но разрушает архитектуру:
// ❌ entities/product/model/useProduct.ts
// Сущность импортирует из features — это запрещено!
import { AddToCartButton } from '@/features/add-to-cart';
Правильный подход — сущность ничего не знает о фичах. Фича сама знает о сущности:
// ✅ features/add-to-cart/ui/AddToCartButton.tsx
import { Product } from '@/entities/product'; // features → entities: разрешено
import { Button } from '@/shared/ui/button'; // features → shared: разрешено
Публичный API слайса
Второй фундаментальный принцип — каждый слайс общается с внешним миром только через публичный API. Это файл index.ts в корне слайса, который явно экспортирует только то, что разрешено использовать снаружи.
// features/add-to-cart/index.ts — публичный API фичи
export { AddToCartButton } from './ui/AddToCartButton';
export { useAddToCart } from './model/useAddToCart';
// Внутренние детали (cartApi, вспомогательные функции) НЕ экспортируются
Снаружи импортируем только через публичный API:
// ✅ Правильно
import { AddToCartButton } from '@/features/add-to-cart';
// ❌ Неправильно — прямой доступ к внутренностям
import { cartApi } from '@/features/add-to-cart/api/cartApi';
Зачем это нужно? Если вы решите переписать внутреннюю реализацию фичи, публичный API останется прежним — и ничего снаружи не сломается. Это как розетка в стене: вам не важно, как проложена проводка внутри, важно, что штепсель подходит.
Как FSD решает реальные проблемы
Вернёмся к симптомам из начала статьи и посмотрим, что меняется с FSD.
| Проблема без FSD | Решение в FSD |
|---|---|
| Непонятно, куда добавить код | Чёткая иерархия слоёв и слайсов даёт однозначный ответ |
| Изменение ломает неожиданные места | Публичный API и изолированные слайсы ограничивают зону влияния |
| Бизнес-объект описан в 5 местах | Сущность (entity) — единственный источник правды о домене |
| Циклические импорты | Правило однонаправленных зависимостей делает циклы невозможными |
| Долгий онбординг | Структура отражает бизнес-логику — новый разработчик понимает её интуитивно |
Команда из flaton.systems описывает это так: они адаптировали FSD под свой page-based подход и зафиксировали ключевой принцип — «держим связанные элементы рядом до тех пор, пока они не потребуются в другом месте». Это и есть суть FSD: локальность кода до момента, когда переиспользование становится реальной необходимостью.
Для каких проектов подходит FSD
FSD — не серебряная пуля. Для лендинга из трёх страниц он избыточен. Но как только проект переходит определённый порог сложности, FSD начинает окупаться.
FSD хорошо подходит, если:
- Проект живёт дольше 3–6 месяцев и продолжает развиваться
- В команде больше одного разработчика
- Приложение имеет несколько доменных областей (пользователи, заказы, каталог и т.д.)
- Требования часто меняются и нужна гибкость при рефакторинге
FSD работает с любым фреймворком — React, Vue, Angular, Svelte. Это методология, а не библиотека. Она не диктует стейт-менеджер или способ работы с API — только то, где должен жить код.
Первый шаг: думать доменами, а не файлами
Самое важное изменение при переходе на FSD — это не структура папок, а способ мышления. Прежде чем создавать файл, задайте себе вопросы:
- К какому домену относится этот код? (пользователь, заказ, корзина?)
- Это переиспользуемый примитив, бизнес-сущность или конкретное поведение пользователя?
- Кто должен знать об этом коде — весь проект или только одна страница?
Ответы на эти вопросы укажут на правильный слой и слайс. В следующей статье мы разберём каждый слой подробно — с примерами кода и конкретными правилами для shared, entities и features.