PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Feature-Sliced Design на реальном проекте: до и после рефакторинга

    Feature-Sliced Design на реальном проекте: до и после рефакторинга

    Аватар автора Feature-Sliced Design на реальном проекте: до и после рефакторинга

    Антон Ларичев

    Иконка календаря12 апреля 2026
    architecturereactvuemiddleИконка уровня middle
    Картинка поста Feature-Sliced Design на реальном проекте: до и после рефакторинга

    Введение

    Feature-Sliced Design (FSD) — это архитектурная методология, которая решает одну из главных проблем фронтенд-разработки: хаотичную организацию кода в растущих проектах. Если ваш проект дорос до десятков экранов и сотен компонентов, а файл helpers.ts стал свалкой утилит, пора задуматься о рефакторинге на Feature-Sliced Design.

    В этой статье мы разберём реальный кейс: как выглядел проект до и после миграции на FSD, какие решения принимались по ходу рефакторинга, и какие результаты это принесло команде. Все примеры — на React и TypeScript, но подход одинаково применим к Vue и другим фреймворкам.

    Что было до рефакторинга: типичная структура проекта

    Рассмотрим структуру проекта интернет-магазина с каталогом, корзиной, личным кабинетом и админкой. До рефакторинга фронтенда проект выглядел так:

    src/
      components/
        Header.tsx
        Footer.tsx
        ProductCard.tsx
        CartItem.tsx
        UserProfile.tsx
        AdminTable.tsx
        Modal.tsx
        Button.tsx
        ... (ещё 80 компонентов)
      pages/
        Home.tsx
        Catalog.tsx
        Cart.tsx
        Profile.tsx
      helpers/
        utils.ts        // 1200 строк
        api.ts          // все запросы в одном файле
        formatters.ts
      store/
        index.ts
        userSlice.ts
        cartSlice.ts
        productsSlice.ts
      styles/
        global.css
    

    Проблемы этой структуры

    Первая проблема — папка components превратилась в плоский список из 80+ файлов. Кнопка Button лежит рядом с AdminTable, хотя у них нет ничего общего. Второй болевой точкой стал файл utils.ts на 1200 строк, где функция форматирования цены соседствовала с валидацией email. Третья проблема — неявные зависимости: ProductCard импортирует напрямую из store, helpers и других компонентов, создавая паутину связей.

    // components/ProductCard.tsx — до рефакторинга
    import { useAppSelector } from '../store';
    import { addToCart } from '../store/cartSlice';
    import { formatPrice } from '../helpers/utils';
    import { fetchProductReviews } from '../helpers/api';
    import { Modal } from './Modal';
    import { Button } from './Button';
    import { ReviewList } from './ReviewList';
    

    Семь импортов из разных частей проекта. Компонент знает о корзине, API, хранилище и модальных окнах одновременно. Масштабируемость проекта при такой структуре стремится к нулю.

    Структура проекта после миграции на FSD

    После рефакторинга тот же проект приобрёл чёткую слоистую архитектуру FSD:

    src/
      app/
        providers/
        styles/
        index.tsx
      pages/
        catalog/
        cart/
        profile/
        home/
      widgets/
        header/
        product-list/
        cart-summary/
      features/
        add-to-cart/
        search-products/
        toggle-favorite/
      entities/
        product/
          model/
          ui/
          api/
          index.ts       // public API
        cart/
        user/
      shared/
        ui/
          Button.tsx
          Modal.tsx
          Input.tsx
        lib/
          format-price.ts
          format-date.ts
        api/
          base-api.ts
        config/
    

    Каждый слой FSD имеет чёткую ответственность. Shared содержит только переиспользуемый код без бизнес-логики. Entities описывают бизнес-сущности. Features — пользовательские действия. Widgets — составные блоки интерфейса. Pages — маршруты приложения.

    Как выглядит компонент после рефакторинга фронтенда

    Тот же ProductCard после миграции на FSD:

    // entities/product/ui/ProductCard.tsx
    import { formatPrice } from '@/shared/lib/format-price';
    import { Button } from '@/shared/ui';
    import type { Product } from '../model/types';
    
    interface ProductCardProps {
      product: Product;
      actions?: React.ReactNode; // слот для фич
    }
    
    export const ProductCard = ({ product, actions }: ProductCardProps) => {
      return (
        <div className="product-card">
          <img src={product.image} alt={product.name} />
          <h3>{product.name}</h3>
          <span>{formatPrice(product.price)}</span>
          {actions}
        </div>
      );
    };
    

    Компонент стал чистым: он знает только о shared-слое и своей сущности. Действия вроде "добавить в корзину" передаются через слот, а не импортируются напрямую. Это и есть ключевой принцип FSD — слои могут зависеть только от нижележащих слоёв.

    Как перейти на Feature-Sliced Design постепенно

    Миграция на FSD не требует остановки разработки. Вот стратегия, которая сработала на нашем проекте:

    Шаг 1: создать слой shared

    Начните с выделения общих UI-компонентов и утилит в shared/. Разбейте монолитный utils.ts на отдельные модули с понятными именами. Каждый модуль экспортирует public API через index.ts:

    // shared/lib/format-price.ts
    export const formatPrice = (price: number, currency = 'RUB'): string => {
      return new Intl.NumberFormat('ru-RU', {
        style: 'currency',
        currency,
      }).format(price);
    };
    

    Шаг 2: выделить entities

    Определите бизнес-сущности проекта. В нашем случае это product, cart, user и order. Для каждой создайте слайс с подпапками model/, ui/, api/ и файлом index.ts как public API.

    Шаг 3: извлечь features

    Пользовательские действия — add-to-cart, search-products, toggle-favorite — выносятся в отдельные фичи. Каждая фича инкапсулирует логику действия и его UI:

    // features/add-to-cart/ui/AddToCartButton.tsx
    import { Button } from '@/shared/ui';
    import { useAddToCart } from '../model/use-add-to-cart';
    
    export const AddToCartButton = ({ productId }: { productId: number }) => {
      const { add, isLoading } = useAddToCart();
      return (
        <Button onClick={() => add(productId)} disabled={isLoading}>
          В корзину
        </Button>
      );
    };
    

    Шаг 4: собрать widgets и pages

    Виджеты комбинируют entities и features. Страницы компонуют виджеты. На этом этапе паутина зависимостей распутывается окончательно.

    Результаты рефакторинга: что изменилось

    После трёх недель постепенной миграции команда получила измеримые результаты:

    • Онбординг новых разработчиков сократился с 2 недель до 3 дней — структура проекта FSD самодокументируема
    • Количество конфликтов при мерже снизилось на 70% — команды работают в изолированных слайсах
    • Время на код-ревью уменьшилось на 40% — понятно, где что лежит и что от чего зависит
    • Линтер Steiger автоматически проверяет соблюдение правил FSD и не пропускает нарушения в CI

    Частые ошибки при внедрении FSD

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

    Вторая ошибка — нарушение правила зависимостей. Если entities/product импортирует что-то из features/ — это сигнал, что логику нужно вынести в shared или пересмотреть границы слайсов.

    Третья ошибка — отсутствие public API. Каждый слайс должен экспортировать только то, что нужно внешним потребителям, через index.ts. Прямые импорты из внутренних файлов слайса создают хрупкие связи.

    Заключение

    Feature-Sliced Design — это не серебряная пуля, а инструмент, который работает на проектах с несколькими разработчиками и растущей кодовой базой. Рефакторинг на FSD требует дисциплины, но результат — предсказуемая модульная архитектура, в которой каждый файл имеет своё место. Начните с shared-слоя, подключите Steiger для контроля и мигрируйте постепенно — через месяц вы не захотите возвращаться к плоской структуре.

    Иконка глаза629

    Комментарии

    0

    Постройте личный план изучения HTML и CSS - полный курс по вёрстке с нуля до уровня Middle — бесплатно!

    HTML и CSS - полный курс по вёрстке с нуля — часть карты развития Frontend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Продвинутый JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    TypeScript с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Как стать frontend-разработчиком в 2025: дорожная карта
    Иконка аватараАнтон
    Иконка календаря10 мая 2026
    frontendкарьераjavascript+ 2juniorИконка уровня junior

    Как стать frontend-разработчиком в 2025: дорожная карта

    Дорожная карта frontend-разработчика 2025: какие технологии учить, в каком порядке и как собрать портфолио для первой работы.

    Иконка чипа0
    Иконка глаза287
    Иконка комментариев1
    Картинка поста JWT аутентификация в Node.js: access и refresh токены
    Иконка аватараАнтон
    Иконка календаря27 мая 2026
    Node.jsJWTАутентификация+ 2middleИконка уровня middle

    JWT аутентификация в Node.js: access и refresh токены

    JWT аутентификация в Node.js: разбираем работу access и refresh токенов, генерацию, валидацию и безопасное хранение на практике.

    Иконка чипа0
    Иконка глаза52
    Иконка комментариев0
    Картинка поста WebSocket на Node.js: строим real-time чат с нуля за час
    Иконка аватараАнтон
    Иконка календаря26 мая 2026
    Node.jsWebSocketJavaScript+ 2middleИконка уровня middle

    WebSocket на Node.js: строим real-time чат с нуля за час

    WebSocket на Node.js: пошаговое руководство по созданию real-time чата с библиотекой ws, обработкой подключений и broadcast-сообщений.

    Иконка чипа0
    Иконка глаза109
    Иконка комментариев0
    Иконка чипа0