Принципы Feature Sliced Design - полное практическое руководство

19 февраля 2026
Автор

Олег Марков

Введение

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

Здесь мы разберем именно принципы FSD — не просто «как сложить папки», а как думать о слоях, слайсах, зависимостях и изоляции. Смотрите, я покажу вам, как эти идеи постепенно складываются в систему, которую можно применять и в React, и в Vue, и в других SPA.

Чтобы статья была практичной, мы будем идти от базовой теории к конкретным правилам и примерам структуры проекта, с разбором, почему это важно и что будет, если эти принципы игнорировать.


Основные идеи Feature-Sliced Design

Бизнес-функциональность как основа архитектуры

Главная идея FSD: архитектура должна отражать функциональность приложения, а не технологии. Вместо того чтобы строить проект вокруг «pages», «components», «hooks», вы выстраиваете его вокруг:

  • доменов (области бизнеса — например, «Профиль пользователя», «Каталог товаров»)
  • сценариев использования (например, «оформление заказа»)
  • общих для системы политик и правил (например, «аутентификация», «управление доступом»)

Поэтому в FSD все крутится вокруг фич (features) и процессов (processes), а технические детали (UI, API, утилиты) становятся только инструментом.

Слои и слайсы: два измерения архитектуры

Feature-Sliced Design вводит два измерения:

  1. Слои (layers) — горизонтальное разделение по уровню абстракции.
  2. Слайсы (slices) — вертикальное разделение по доменам/функциям.

Давайте разберемся, как это выглядит.

Слои

Базовый набор слоев (часто используемая схема):

  • app — инициализация приложения, глобальная конфигурация
  • processes — сквозные процессы (например, onboarding, checkout)
  • pages — полноценные страницы, собирающие UI из фич и сущностей
  • features — законченное бизнес‑поведение (например, «лайкнуть пост», «оформить заказ»)
  • entities — бизнес‑сущности (User, Product, Order) и работа с ними
  • shared — переиспользуемые примитивы, не завязанные на конкретный домен

Важно: чем ниже слой, тем более «общим» и абстрактным он считается. Зависимости разрешены только сверху вниз, но не наоборот. То есть features может использовать entities и shared, но не app.

Слайсы

Слайс — это доменная «вертикаль». Например:

  • в entities могут быть слайсы user, product, order
  • в featuresadd-to-cart, edit-profile, like-post
  • в pageshome, product-details, cart

Внутри каждого слоя код разделяется на независимые слайсы по смыслу. Это помогает локализовать изменения: вы рефакторите «cart», не затрагивая «wishlist».


Принцип слоистой архитектуры

Правило направленных зависимостей

Одно из ключевых формальных правил FSD:

Слой может зависеть только от такого же или более «низкого» слоя.

Допустимые направления:

  • appprocessespagesfeaturesentitiesshared
  • внутри слоя — зависимости между слайсами регулируются дополнительными правилами (чуть позже разберем)

То есть, например:

  • features/add-to-cart может использовать entities/product и shared/ui/Button
  • но entities/product не имеет права импортировать features/add-to-cart

Нарушение этого правила приводит к «архитектурным циклам» и резкому усложнению поддержки.

Пример допустимого и недопустимого импорта

Давайте посмотрим, как это может выглядеть в React‑проекте:

// features/add-to-cart/ui/AddToCartButton.tsx

import { Product } from '@/entities/product';        // допустимо - слой entities ниже
import { Button } from '@/shared/ui/button';         // допустимо - слой shared ниже
import { useCartStore } from '@/entities/cart/model';// допустимо - тоже entities

export const AddToCartButton = ({ product }: { product: Product }) => {
  // Здесь мы реализуем фичу "добавить товар в корзину"
  const addToCart = useCartStore((state) => state.add);

  const handleClick = () => {
    // Добавляем товар в корзину
    addToCart(product);
  };

  return (
    <Button onClick={handleClick}>
      Добавить в корзину
    </Button>
  );
};

А вот так делать нельзя:

// entities/product/model/useProductWithCart.ts

// Такой импорт нарушает принцип слоев
import { AddToCartButton } from '@/features/add-to-cart/ui/AddToCartButton';
// entities не должен зависеть от features

// Здесь мы "подмешиваем" фичу в сущность - это ошибочный подход с точки зрения FSD

Если вам «очень нужно» использовать функциональность из верхнего слоя — это сигнал, что:

  • либо вы неправильно выбрали слой для этой логики
  • либо часть логики нужно опустить ниже по слоям, абстрагировав от конкретной фичи

Принцип единой точки входа слоя

Каждый слой должен иметь контролируемые точки входа. Обычно это реализуется через:

  • публичный API папки (например, index.ts в корне слайса)
  • выделение того, что можно использовать снаружи, а что остается внутренней реализацией

Например, для слайса entities/user:

// entities/user/index.ts
// Публичный API сущности User

export { UserCard } from './ui/UserCard';
// Экспортируем UI-компонент для отображения пользователя

export { useUser } from './model/useUser';
// Экспортируем хук для получения данных о пользователе

export type { User, UserId } from './model/types';
// Экспортируем типы, которые используются в других слоях

Внутренние детали (api, вспомогательные утилиты, приватные компоненты) не выносятся в API. Это позволяет:

  • ограничить зону «сломанного кода» при изменениях
  • упростить навигацию по проекту: вы сразу видите, чем «разрешено» пользоваться

Принцип domain‑first: сначала смысл, потом структура

Почему важен доменный взгляд

Feature-Sliced Design предлагает сначала ответить на вопросы:

  • какие у приложения домены
  • какие сущности в каждом домене
  • какие сценарии взаимодействия с ними

И только потом переходить к структуре слоев и файлов. Это называют domain-first подходом.

Например, интернет‑магазин:

  • домены: catalog, cart, order, user
  • сущности: Product, Category, Cart, Order, User, Address
  • фичи: поиск товаров, добавление в корзину, применение промокода, оплата заказа, редактирование профиля

Неправильный подход — сразу начинать создавать components, hooks, services без понимания доменной модели. Такой проект обычно быстро «разъезжается».

От домена к структуре проекта

Давайте разберемся на примере. Допустим, у нас есть домены:

  • user — профиль пользователя, авторизация
  • product — карточка товара, описание, характеристики
  • cart — корзина
  • order — заказ, оплата

Мы можем разложить их по слоям так:

  • entities/user, entities/product, entities/cart, entities/order
  • features/auth-by-email, features/add-to-cart, features/apply-promo, features/checkout
  • pages/cart, pages/product-details, pages/profile
  • processes/checkout-flow

Пример структуры (чуть упрощенный):

src/
  app/
    providers/
    routing/
    index.tsx
  processes/
    checkout-flow/
      ui/
      model/
      lib/
  pages/
    cart/
      ui/
      model/
      index.ts
    product-details/
      ui/
      model/
      index.ts
  features/
    add-to-cart/
      ui/
      model/
      api/
      index.ts
    auth-by-email/
      ui/
      model/
      api/
      index.ts
  entities/
    user/
      ui/
      model/
      api/
      index.ts
    product/
      ui/
      model/
      api/
      index.ts
    cart/
      ui/
      model/
      api/
      index.ts
  shared/
    ui/
    lib/
    api/
    config/

Как видите, домены проявляются в entities и features, а слои обеспечивают границы ответственности и порядок зависимостей.


Принцип инкапсуляции и публичного API слайса

Почему слайс — это модуль, а не папка «для красоты»

Каждый слайс в FSD — это модуль, который:

  • инкапсулирует внутренние детали реализации
  • предоставляет четко определенный публичный API
  • может развиваться почти независимо от других слайсов

Чтобы это работало, важно:

  • не импортировать файлы напрямую «вглубь» чужих слайсов
  • опираться только на публичные точки входа

Пример инкапсуляции фичи

Покажу вам, как это реализовано на практике.

features/
  add-to-cart/
    ui/
      AddToCartButton.tsx
    model/
      useAddToCart.ts
      events.ts
      types.ts
    api/
      cartApi.ts
    lib/
      getCartItemPayload.ts
    index.ts

Содержимое API слайса:

// features/add-to-cart/index.ts
// Публичный API фичи "добавить в корзину"

export { AddToCartButton } from './ui/AddToCartButton';
// Экспортируем компонент кнопки для использования на страницах

export { useAddToCart } from './model/useAddToCart';
// Экспортируем хук, если где-то нужен программный вызов добавления

Внутренние детали (cartApi, вспомогательные функции, типы) остаются скрытыми. Снаружи их импортировать не следует:

// Плохо - прямой импорт внутренностей фичи
import { cartApi } from '@/features/add-to-cart/api/cartApi';
// Так мы обходим публичный API и создаем хрупкую зависимость

// Хорошо - использовать только публичный API
import { AddToCartButton } from '@/features/add-to-cart';

Такой подход делает фичу «самодостаточной»: если вы решите поменять реализацию add-to-cart, вам достаточно сохранить совместимый публичный API, а внутренности вы можете переписать без страха сломать другие модули.


Принцип явных зависимостей и изоляции

Явные зависимости вместо глобального состояния

FSD поощряет явно передавать зависимости:

  • через параметры компонентов
  • через публичные API слайсов
  • через конфигурацию на уровне app

А не «прятать» логику в:

  • глобальных синглтонах
  • неограниченно общих хуках из shared
  • неформальных соглашениях «все знают, что здесь можно так сделать»

Например, вместо «волшебного» доступа к текущему пользователю:

// Плохо - неявная зависимость от глобального состояния
import { useCurrentUser } from '@/shared/model/useCurrentUser';

export const ProfileMenu = () => {
  const user = useCurrentUser();
  // ...
};

Лучше сделать зависимость явной через сущность:

// Хорошо - зависимость от entities/user через публичный API

// entities/user/index.ts
export { useCurrentUser } from './model/useCurrentUser';

// features/profile-menu/ui/ProfileMenu.tsx
import { useCurrentUser } from '@/entities/user';

export const ProfileMenu = () => {
  const user = useCurrentUser();
  // ...
};

А если компонент является чистым UI, зависимость можно передать через пропсы:

// entities/user/ui/UserMenu.tsx

import type { User } from '../model/types';

interface UserMenuProps {
  user: User | null;
}

export const UserMenu = ({ user }: UserMenuProps) => {
  // Здесь компонент не знает, откуда пришел пользователь
  // Это делает его более переиспользуемым
};

Изоляция бизнес-правил

Еще один важный принцип: бизнес‑правила не должны размазываться по всему приложению. Они должны быть локализованы:

  • либо в слое entities (правила, связанные с конкретной сущностью)
  • либо в слое features (правила, связанные с конкретным поведением/сценарием)

Например, правило «товар нельзя добавить в корзину, если он не в наличии»:

// entities/product/model/isAvailable.ts

import type { Product } from './types';

// Здесь мы инкапсулируем бизнес-правило доступности товара
export const isProductAvailable = (product: Product) => {
  return product.stock > 0 && !product.isArchived;
};

Использование в фиче:

// features/add-to-cart/model/useAddToCart.ts

import { isProductAvailable } from '@/entities/product/model/isAvailable';
import { useCartStore } from '@/entities/cart/model';

export const useAddToCart = () => {
  const addToCart = useCartStore((state) => state.add);

  const handleAdd = (product) => {
    // Обратите внимание - бизнес-правило вынесено в entities
    if (!isProductAvailable(product)) {
      // Здесь мы можем выбросить доменную ошибку или показать уведомление
      throw new Error('Product is not available');
    }

    addToCart(product);
  };

  return { addToCart: handleAdd };
};

Такое разделение помогает:

  • избегать дублирования правил в разных местах
  • упростить тестирование (вы можете тестировать бизнес‑правила отдельно от UI)

Принцип независимых фич и слабой связанности

Фича как минимальная законченная единица

Фича в FSD — это:

  • законченный фрагмент поведения с ценностью для пользователя
  • не просто компонент, а сочетание UI + модель + взаимодействие с сущностями
  • элемент, который можно использовать на разных страницах или в разных процессах

Например, features/add-to-cart:

  • UI — кнопка, иконка, индикатор процесса
  • модель — состояние загрузки, эффекты, обработка ошибок
  • связи с доменом — работа с entities/cart и entities/product

То есть фича — это не «маленькая страничка», а «умная» единица поведения.

Избегаем «фич‑гигантов»

Распространенная ошибка: делать одну фичу слишком большой, просто по названию блока в UI, например features/profile и складывать туда:

  • редактирование профиля
  • смену пароля
  • загрузку аватара
  • привязку соцсетей

Лучше разделить фичи:

  • features/edit-profile
  • features/change-password
  • features/upload-avatar
  • features/connect-social-account

Каждая фича решает одну конкретную задачу. Тогда:

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

Принцип «pages собирают, но не думают»

Роль страницы в FSD

Слой pages в Feature-Sliced Design играет роль:

  • композиционного слоя, который собирает страницу из фич и сущностей
  • интеграционного слоя с роутингом
  • связывающего звена между URL и внутренними модулями

Главное правило: страницы не должны содержать сложную бизнес‑логику. Они только:

  • выбирают нужные фичи и компоненты
  • передают им параметры
  • подключают нужные процессы, если необходимо

Пример страницы

Давайте разберемся на примере страницы корзины:

// pages/cart/ui/CartPage.tsx

import { CartItemsList } from '@/entities/cart';
import { OrderSummary } from '@/entities/order';
import { ApplyPromoCode } from '@/features/apply-promo-code';
import { CheckoutButton } from '@/features/checkout';
import { PageLayout } from '@/shared/ui/layouts/PageLayout';

export const CartPage = () => {
  // Обратите внимание - в компоненте нет сложной логики
  // Он только компонирует уже готовые фичи и сущности

  return (
    <PageLayout title="Корзина">
      <CartItemsList />
      <OrderSummary />
      <ApplyPromoCode />
      <CheckoutButton />
    </PageLayout>
  );
};

Как видите, CartPage:

  • не знает, как именно применяется промокод
  • не знает, как именно считается итоговая сумма
  • не знает, как происходит переход к оплате

Все это инкапсулировано внутри entities и features. Страница только «собирает» их.

Это дает:

  • меньше дублирования логики между страницами
  • возможность переиспользовать фичи на разных страницах
  • лучшую изоляцию для тестирования отдельных частей

Принцип процессов: сквозные сценарии отдельно от фич

Когда не хватает только фич

Иногда в приложении есть сложные сценарии, проходящие через несколько страниц и фич. Например:

  • пошаговый onboarding
  • мастер оформления заказа (checkout)
  • сложный wizard настройки

Если попытаться «распихать» такой сценарий по отдельным фичам и страницам, логика может размазаться и стать плохо управляемой. Для этого в FSD существует слой processes.

Что такое process в FSD

processes — это:

  • сквозные сценарии, пересекающие несколько слоев
  • координация нескольких фич и сущностей
  • общие для сценария политики и состояния (например, текущий шаг, общий прогресс)

Покажу вам, как это выглядит в коде.

processes/
  checkout-flow/
    ui/
      CheckoutProgressBar.tsx
    model/
      useCheckoutFlow.ts
      steps.ts
    lib/
      validateStep.ts
    index.ts
// processes/checkout-flow/model/steps.ts
// Здесь мы описываем шаги процесса оформления заказа

export enum CheckoutStep {
  Cart = 'cart',
  Delivery = 'delivery',
  Payment = 'payment',
  Review = 'review',
}

// processes/checkout-flow/model/useCheckoutFlow.ts

import { useState } from 'react';
import { CheckoutStep } from './steps';

// Кастомный хук для управления шагами checkout-процесса
export const useCheckoutFlow = () => {
  const [currentStep, setCurrentStep] = useState<CheckoutStep>(CheckoutStep.Cart);

  const goToNextStep = () => {
    // Здесь мы описываем переходы между шагами
    // Детали опускаем для краткости
  };

  const goToPreviousStep = () => {
    // Переход назад
  };

  return {
    currentStep,
    goToNextStep,
    goToPreviousStep,
  };
};

Использование в страницах:

// pages/checkout/ui/CheckoutPage.tsx

import { CheckoutProgressBar } from '@/processes/checkout-flow';
import { CartStep } from '@/features/checkout-cart-step';
import { DeliveryStep } from '@/features/checkout-delivery-step';
import { PaymentStep } from '@/features/checkout-payment-step';

export const CheckoutPage = () => {
  // Страница связывает процесс и отдельные шаги-фичи

  return (
    <>
      <CheckoutProgressBar />
      {/* Здесь мы условно рендерим нужный шаг */}
      {/* Имплементация опущена для краткости */}
      <CartStep />
      <DeliveryStep />
      <PaymentStep />
    </>
  );
};

Таким образом, процессы позволяют:

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

Принцип shared‑слоя: общий, но не «помойка»

Назначение shared

Слой shared — это:

  • общие примитивы, не завязанные на конкретный домен
  • компоненты, которые можно использовать в любом контексте
  • утилиты, которые не знают про бизнес‑логику

Примеры:

  • shared/ui/Button, shared/ui/Modal, shared/ui/Input
  • shared/lib/formatDate, shared/lib/debounce
  • shared/api/baseClient
  • shared/config/env

Но важно: shared — не место, куда «складывается все, что не влезло в другие слои». У этого слоя также есть четкие правила.

Принцип «shared не должен знать о домене»

Компоненты и функции в shared не должны зависеть от:

  • entities, features, pages, processes
  • доменных типов или бизнес‑правил

Например, такой код в shared — ошибка:

// Плохо - shared/ui/ProductCard знает о сущности Product

import type { Product } from '@/entities/product';

interface ProductCardProps {
  product: Product; // зависимость от домена
}

export const ProductCard = ({ product }: ProductCardProps) => {
  // ...
};

Лучше вынести такой компонент в entities/product/ui/ProductCard. А в shared оставить только действительно общие элементы, вроде:

// shared/ui/Card.tsx

interface CardProps {
  children: React.ReactNode;
  // Здесь нет зависимостей от доменов
}

export const Card = ({ children }: CardProps) => {
  // Простой визуальный контейнер
  return <div className="card">{children}</div>;
};

Тогда ProductCard можно реализовать так:

// entities/product/ui/ProductCard.tsx

import { Card } from '@/shared/ui/card';
import type { Product } from '../model/types';

interface ProductCardProps {
  product: Product;
}

export const ProductCard = ({ product }: ProductCardProps) => {
  // Здесь мы компонируем доменные данные и общий UI-примитив
  return (
    <Card>
      <h3>{product.name}</h3>
      <p>{product.price} ₽</p>
    </Card>
  );
};

Принцип адаптивности под проект и эволюции

Методология, а не жесткий шаблон

Важно понимать: FSD — это набор принципов, а не строгий шаблон с жестко зафиксированными папками. В небольшой pet‑проект не обязательно сразу тащить все слои и процессы.

Подход такой:

  • сначала выделите хотя бы shared, entities, features, pages
  • постепенно добавляйте processes, app и дополнительные детали по мере роста проекта
  • адаптируйте структуру под ваши домены и команду, не ломая базовые принципы (направление зависимостей, инкапсуляция, domain‑first)

Эволюционное внедрение

Давайте разберемся на примере миграции существующего проекта к FSD.

  1. Шаг 1. Ввод базовых слоев

    • создаете папки shared, entities, features, pages, app
    • настраиваете алиасы импортов (@/shared, @/entities, и так далее)
    • новые модули создаете уже по FSD
  2. Шаг 2. Постепенный перенос существующего кода

    • сущности (типы данных, модели, API) переносите в entities
    • переиспользуемые компоненты — в shared/ui
    • сценарные компоненты (конкретные действия пользователя) — в features
  3. Шаг 3. Ввод процессов

    • когда замечаете сквозные сценарии, выносите их в processes
    • постепенно чистите страницы и фичи от «сквозной» логики
  4. Шаг 4. Уточнение публичных API

    • добавляете index.ts во все слайсы
    • ограничиваете импорты только через них
    • подключаете линтер, чтобы контролировать правила зависимостей

Так вы можете внедрить принципы FSD без «большого взрыва».


Типичные ошибки при применении принципов FSD

Ошибка 1. Архитектура «по папкам, но не по смыслу»

Распространенная ситуация: в проекте есть папки app, entities, features и так далее, но:

  • в features лежат просто «красивые компоненты»
  • в entities лежат случайные типы и хелперы
  • бизнес‑логика размазана по pages

Формально структура соблюдена, но принципы доменной декомпозиции и инкапсуляции — нет.

Чтобы этого избежать:

  • для каждой фичи явно формулируйте: какую бизнес‑задачу она решает
  • для каждой сущности формулируйте: какие бизнес‑правила к ней относятся
  • выносите логику со страниц в фичи и сущности

Ошибка 2. Слишком универсальный shared

Еще одна типичная проблема — превращение shared в мусорную корзину:

  • туда попадает все, что «жалко положить в entities»
  • появляются доменные зависимости
  • shared начинает знать про конкретные бизнес‑сценарии

Как ориентир: если элемент хоть как‑то зависит от предметной области — это уже не shared. Лучше разместить его в соответствующем домене (entities или features), а потом, если он действительно окажется универсальным, вынести в shared с минимальными зависимостями.

Ошибка 3. Прямые импорты вглубь слайсов

Например:

// Плохо - импортируем конкретный файл из чужого слайса
import { something } from '@/features/add-to-cart/model/useAddToCart';

// Хорошо - импортируем только из публичного API
import { useAddToCart } from '@/features/add-to-cart';

Такая ошибка приводит к:

  • хрупкости кода (любое изменение структуры ломает импорты)
  • обходу контрактов модулей
  • неявным связям между модулями

Решение: ввести жесткое правило — импортировать только из корней слайсов (index.ts) и контролировать это линтером.


Краткое резюме принципов Feature-Sliced Design

Чтобы зафиксировать основные идеи, соберем их в одном месте:

  • Слои — разделяют код по уровням абстракции, зависимости идут только сверху вниз.
  • Слайсы — разделяют код по доменам/функциям, внутри каждого слоя.
  • Domain‑first — сначала проектируете домены и сценарии, затем структуру кода.
  • Модули с публичным API — каждый слайс — модуль с четко определенной внешней поверхностью.
  • Явные зависимости — избегаете скрытых связей и глобальных синглтонов, завязанных на бизнес‑логику.
  • Фичи как единицы поведения — фича = UI + модель + связи с сущностями для конкретной задачи.
  • Pages без бизнес‑логики — страницы собирают фичи и сущности, но не содержат сложных правил.
  • Processes для сквозных сценариев — сложные многошаговые сценарии выносятся в отдельный слой.
  • Shared без домена — общий слой не должен знать о предметной области.
  • Эволюционное внедрение — методология адаптируется под размер и стадию проекта.

Если вы будете держать в голове эти принципы и проверять по ним свои архитектурные решения, структура проекта станет более предсказуемой, а изменения — менее болезненными.


Частозадаваемые технические вопросы по теме и ответы

Как контролировать соблюдение слоев и запрет «обратных» импортов?

Используйте ESLint с плагином для контроля импортов, например eslint-plugin-boundaries или eslint-plugin-import. Настройте правила так, чтобы:

  • запрещать импорты «вверх по слоям»
  • разрешать только импорты через публичные API (index.ts слайса)

Сначала включите правила в режиме предупреждений, затем переведите в ошибки.

Как быть с кросс‑доменными сущностями например Order который связан и с user и с cart?

Выберите главный домен для сущности (например, order) и разместите ее в entities/order. Связи с другими сущностями оформите через типы и адаптеры, но избегайте циклических зависимостей. Если домены слишком тесно связаны, рассмотрите объединение их в один укрупненный домен.

Где хранить общий стейт например глобальную тему или локаль?

Глобальную инфраструктурную конфигурацию (тема, локаль, конфиг API) храните в app или shared:

  • провайдеры React контекстов — в app/providers
  • хуки и вспомогательные функции — в shared/lib или shared/config

При этом бизнес‑логика, завязанная на эти параметры, должна оставаться в entities и features.

Как организовать тесты с учетом FSD?

Размещайте тесты рядом с кодом в том же слайсе:

  • ui‑компоненты тестируйте через компонентные тесты
  • model (сторы, хуки) — через unit‑тесты
  • процессы — через интеграционные тесты, проверяющие переходы между шагами

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

Что делать с legacy‑кодом который трудно сразу разложить по слоям?

Оставьте его в отдельной зоне, например legacy/, и постепенно выносите куски логики в FSD‑слои:

  • новые фичи сразу делайте по FSD
  • при изменении legacy‑модуля старайтесь вырезать оттуда часть логики в entities или features
  • постепенно объем legacy‑кода будет сокращаться, не блокируя развитие проекта
Стрелочка влевоСтруктура проекта в Go GolangАрхитектурные слои - принципы проектирования и практические примерыСтрелочка вправо

Все гайды по Feature-sliced_design

Открыть базу знаний

Отправить комментарий