PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • 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 Собеседование
    • 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 для контроля и мигрируйте постепенно — через месяц вы не захотите возвращаться к плоской структуре.

    Иконка глаза2 706

    Комментарии

    0

    Постройте личный план изучения React state менеджер Zustand до уровня Middle — бесплатно!

    React state менеджер Zustand — часть карты развития Frontend

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

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

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

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

    Vue 3 и Pinia

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

    Next.js - с нуля

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

    Feature-Sliced Design

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

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

    Картинка поста Распределенные системы роутинга на примере Framework Foton
    Иконка аватараКонстантин
    Иконка календаря09 октября 2026
    распределениероутингfotonseniorИконка уровня senior

    Распределенные системы роутинга на примере Framework Foton

    Распределенные системы не только снижают нагрузку, но и формируют более прозрачную, тонкую и гибку архитектуру в монолитном приложении

    Иконка чипа0
    Иконка глаза36
    Иконка комментариев0
    Картинка поста OpenCode Desktop: установка и подключение Claude
    Иконка аватараАнтон
    Иконка календаря09 октября 2026
    AI-инструментыDevOpsopenai+ 2middleИконка уровня middle

    OpenCode Desktop: установка и подключение Claude

    OpenCode Desktop — графическое приложение OpenCode: тот же агент, что работает в терминале, но с оконным интерфейсом. Скачивается и ставится оно в России штатно, а вот подключить к нему Claude с первой попытки не выйдет, и дело не в блокировках: встроенная форма добавления своего провайдера в приложении не работает и отвечает ошибкой на любые данные. Рабочий путь — описать провайдера в opencode.json руками. Готовый OpenAI-совместимый эндпоинт с оплатой рублями даёт AI для кода от PurpleSchool. Ниже — установка OpenCode Desktop на macOS, Windows и Linux, разбор ошибки и конфиг целиком.

    Иконка чипа0
    Иконка глаза70
    Иконка комментариев0
    Картинка поста Настройка очередей с retray на laravel и Foton сравнение
    Иконка аватараКонстантин
    Иконка календаря08 октября 2026
    очередиlaravelretray+ 3middleИконка уровня middle

    Настройка очередей с retray на laravel и Foton сравнение

    Создание очередей с retray на примерах фреймворков Laravel и Foton

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