Gernar
Frontend DeveloperАрхитектура frontend

Интервью-вопрос

Что такое Feature-Sliced Design

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

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 50 правильно

Как лучше объяснить FSD в начале ответа?

Вы отвечаете коротко и хотите сразу показать, что понимаете не только названия папок.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

Feature-Sliced Design помогает вам ответить на простой вопрос: где должен жить код, чтобы его было безопасно менять через полгода. Вместо папок только по типам файлов, например components, hooks и utils, FSD предлагает смотреть на бизнес-смысл и уровень ответственности.

Хороший короткий ответ можно построить так:

FSD это архитектурная методология для frontend. Она раскладывает код по слоям и бизнес-слайсам, а зависимости разрешает только сверху вниз. Это помогает фичам меньше цепляться друг за друга, а команде проще понимать, где менять код и какие импорты опасны.

Такой ответ звучит сильнее, чем перечисление папок. Он показывает практическую цель подхода. На интервью у вас часто проверяют именно это: понимаете ли вы границы, а не просто помните названия директорий.

Слои и правило зависимостей

В актуальной FSD-структуре чаще всего говорят о слоях app, pages, widgets, features, entities и shared. Верхние слои собирают приложение и сценарии. Нижние дают более стабильные и переиспользуемые части.

Пример структуры может выглядеть так:

src/
  app/
    providers/
    router/
  pages/
    profile/
  widgets/
    profile-card/
  features/
    update-profile/
  entities/
    user/
  shared/
    ui/
    api/
    lib/

Практическое правило простое: features может использовать entities и shared, но shared не должен импортировать features. Если нижний слой начинает знать о верхнем, общий код становится зависимым от конкретного сценария. После этого любое изменение фичи может сломать места, которые вообще не должны были о ней знать.

В старых материалах по FSD можно встретить слой processes. Если вас спросят о нем, безопаснее сказать, что он встречается в старых проектах или в командах с длинными пользовательскими сценариями. В новых структурах его часто избегают и решают задачу через pages, widgets и features.

Как выбрать место для кода

На собеседовании вас часто проверяют не определением, а практическим вопросом: куда вы положите новый код. Здесь лучше рассуждать от зависимостей и бизнес-смысла, а не от названия файла.

Как выбрать слой

1Код не знает о бизнесе и нужен в разных местах?
Положите в shared, например shared/ui, shared/lib или shared/api.
2Код описывает доменную сущность вроде user, product или order?
Положите в entities и отдавайте наружу только стабильный public API.
3Код реализует действие пользователя с понятной целью?
Положите в features, например add-to-cart, login или update-profile.
4Код собирает несколько фич и сущностей в крупный блок интерфейса?
Положите в widgets, если это переиспользуемый композиционный блок страницы.
5Код отвечает за роутинг, провайдеры, глобальные стили или bootstrap приложения?
Положите в app, потому что это уровень инициализации приложения.

Не выносите код вниз только потому, что он понадобился два раза. Если кусок знает о конкретной форме, статусе модалки или бизнес-правиле одной фичи, ранний перенос в shared создаст ложную общность. Потом этот код начнут менять разные команды, и он станет источником регрессий.

Для UI-компонентов это особенно заметно. Общая кнопка в shared/ui не должна сама решать, что делать после логина или добавления в корзину. Ее задача проще: сохранить базовую доступность, нормальный текст, type для формы, фокус и возможность передать aria-label, если видимой подписи нет.

Public API и безопасные импорты

В FSD у слайса должен быть понятный внешний контракт. Обычно его собирают через index.ts. Внешний код импортирует только то, что слайс явно разрешил, и не лезет во внутренние папки.

Плохой вариант:

import { userStore } from "@/entities/user/model/private-store";
import { formatUserName } from "@/entities/user/lib/format-user-name";

Такой код связан с внутренней структурой entities/user. Если команда переименует файл или поменяет модель, сломаются внешние импорты. Еще хуже, если внешний компонент берет приватный store напрямую. Он может пропустить нормальную обработку loading, error и отмену запроса, а пользователь увидит старые данные или мигающий интерфейс.

Более безопасный вариант:

import { formatUserName, useUser } from "@/entities/user";

Здесь entities/user сам решает, что является публичным контрактом. Это не делает архитектуру идеальной автоматически, но снижает риск случайной зависимости от деталей реализации.

Чем FSD помогает на практике

Главная польза FSD заметна в растущих продуктах. Когда команда добавляет новую фичу, вам проще понять, какие сущности уже есть, какие UI-блоки можно переиспользовать и где нельзя импортировать код. Конфликтов становится меньше, потому что изменения чаще остаются внутри одного слайса.

Еще один плюс виден на онбординге. Новому разработчику легче искать код по бизнес-сценарию: профиль пользователя, корзина, авторизация, оформление заказа. В структуре только по типам файлов тот же сценарий может быть размазан между десятками папок.

Но FSD не должен быть самоцелью. Если проект маленький, команда одна, а бизнес-логики мало, полная структура может добавить лишнюю сложность. В сильном ответе стоит признать этот trade-off и предложить применять методологию постепенно.

Как внедрять FSD без лишнего риска

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

Безопасное внедрение
  1. 1Выберите одну болезненную зону проекта
  2. 2Опишите границы слоя и правила импортов
  3. 3Соберите public API для слайсов
  4. 4Добавьте линтинг или review-чек на запрещенные импорты
  5. 5Расширяйте подход после первых успешных изменений
Рискованный путь
  1. 1Переименуйте все папки за один большой PR
  2. 2Перенесите код без ясных правил зависимостей
  3. 3Сделайте shared новой папкой для всего подряд
  4. 4Разрешите глубокие импорты во внутренние файлы
  5. 5Получите те же связи, но в более сложной структуре

На практике правила импортов стоит поддерживать не только договоренностями, но и инструментами. Команда может использовать ESLint-правила, алиасы, code review checklist и запрет глубоких импортов. Иначе архитектура быстро начинает зависеть от памяти конкретных разработчиков.

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Называть FSD набором папок

    Папки сами по себе не дают архитектуры. Если нет правил зависимостей, public API и понятного смысла слоев, проект быстро возвращается к старым связям с новыми названиями. На интервью лучше говорить про границы модулей и последствия для изменений.

  2. 2

    Сбрасывать все в shared

    shared должен быть независимым и общим, а не складом спорного кода. Если туда попадает логика конкретной фичи, нижний слой начинает знать о бизнесе верхнего слоя. Потом изменение в одной фиче неожиданно ломает другие места.

  3. 3

    Делать глубокие импорты

    Импорт вида @/entities/user/model/private-store обходит контракт слайса. Такой код ломается при обычном рефакторинге внутренней структуры. В React он еще может обойти согласованный хук, кеш или подписку. Тогда экран покажет устаревшего пользователя или сделает лишний запрос. Безопаснее экспортировать нужное через index.ts и импортировать только из public API.

  4. 4

    Прятать бизнес-сценарий в shared/api

    shared/api должен быть транспортным слоем, а не местом для сценариев приложения. Если общий клиент импортирует auth-feature, сам обновляет профиль или меняет UI-loading, появляются лишние запросы, сложные race condition и риск отправить токен не туда. Безопаснее держать базовый HTTP-клиент в shared, а конкретные запросы, отмену, loading и error state оформлять в feature или entity.

  5. 5

    Связывать фичи напрямую

    Когда одна feature импортирует другую, независимость фич исчезает. Это часто приводит к циклам, сложным тестам и конфликтам в командной разработке. Общую часть лучше вынести ниже, например в entities или shared, если она не принадлежит одной фиче.

  6. 6

    Внедрять FSD большим переписыванием

    Массовый перенос файлов дает много конфликтов и мало пользы, если команда не изменила правила работы. Лучше начать с одной зоны, договориться о критериях и постепенно укреплять границы. Так меньше риск остановить разработку ради косметической миграции.

Follow-up

Что могут спросить дальше

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

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.

Содержание