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

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

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • Сообщество
    • 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 для контроля и мигрируйте постепенно — через месяц вы не захотите возвращаться к плоской структуре.

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

    Комментарии

    0

    Постройте личный план изучения Основы React, React Router и Redux Toolkit до уровня Middle — бесплатно!

    Основы React, React Router и Redux Toolkit — часть карты развития Frontend, Mobile

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

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

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

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

    Основы разработки

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    бесплатно
    Подробнее
    изображение курса

    React Native и Expo Router

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

    Основы Swift и iOS

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

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

    Картинка поста Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо
    Иконка аватараАнтон
    Иконка календаря10 апреля 2026
    typescriptreactnodejsmiddleИконка уровня middle

    Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Разбираем, как настроить монорепозиторий на Turborepo для React и NestJS: структура проекта, общие типы, pipeline задач и кэширование сборки.

    Иконка чипа0
    Иконка глаза64
    Иконка комментариев0
    Картинка поста CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг
    Иконка аватараАнтон
    Иконка календаря09 апреля 2026
    architecturetypescriptnodejsseniorИконка уровня senior

    CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг

    CQRS и Event Sourcing — архитектурные паттерны для сложных доменов. Разбираем реальные примеры на TypeScript и NestJS, критерии выбора и типичные ошибки внедрения.

    Иконка чипа0
    Иконка глаза98
    Иконка комментариев0
    Картинка поста NestJS: как организовать модули, чтобы проект не стал монолитом
    Иконка аватараАнтон
    Иконка календаря28 марта 2026
    nestjstypescriptarchitecturemiddleИконка уровня middle

    NestJS: как организовать модули, чтобы проект не стал монолитом

    Организация модулей в NestJS определяет масштабируемость проекта. Разберем принципы модульной архитектуры, разделение по доменам и типичные ошибки, превращающие проект в монолит.

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