Привет! Меня зовут Егор Подольский, я фронтенд-инженер в Авито. Знакомство с Feature-Sliced Design я начал не так давно. Её используют немногие, а я попробовал применить её, и влюбился. Решил рассказать о FSD, потому что считаю этот подход удобным и перспективным.
Featured-sliced Design — это свод правил и требований к организации кода, который делает разработку легче. Методология разработана для фронтенд-приложений, но отдельные концепции из FSD можно использовать и для бэкенда.
Лучше всего суть методологии раскрывается в проектах среднего размера, так как FSD — это про организацию. В одностраничных приложениях, с парой папок, не получится прочувствовать все преимущества методологии, а в слишком больших, наподобие Google Cloud, её будет недостаточно для построения архитектуры. Но FSD может стать отправной точкой, с которой можно начать разработку.
Featured-sliced Design не привязана к конкретному фреймворку или state-менеджеру, поэтому её можно внедрять в командах с разным стеком. Примеры проектов, которые применяют FSD, есть на сайте разработчиков методологии.
![](https://habrastorage.org/getpro/habr/upload_files/ddf/a89/359/ddfa89359e6bac8e878c78f824c61edf.png)
Структура Featured-sliced Design
Главное правило, на котором строится методология: все элементы кода разделены по зоне ответственности (слои), предметной области (слайсы) и техническому назначению (сегменты).
![](https://habrastorage.org/getpro/habr/upload_files/386/4d9/baa/3864d9baadac5a0b1d7de3237e119035.png)
Семь слоёв делят код по зонам ответственности. Они строго стандартизированы во всех проектах: в любой команде каждый слой будет отвечать за одно и то же.
Весь код проекта распределяется между слоями по принципу: чем выше слой, тем сильнее он привязан к предметной области конкретного приложения. Нижний слой наиболее абстрактный, поэтому его можно использовать для разных проектов.
![Направляясь по слоям от Shared к App, мы идём от абстрактности к предметной области Направляясь по слоям от Shared к App, мы идём от абстрактности к предметной области](https://habrastorage.org/getpro/habr/upload_files/9db/5ac/aec/9db5acaece720b025e16e42be71af99c.png)
В каждом слое находятся слайсы. Они разделяют код по предметной области, к которой относится та или иная функция. Это облегчает поиск нужного элемента в проекте.
В слайсах находятся сегменты, которые делят код по техническому назначению. Один из них — Public API, который нужен для импорта других сегментов наружу. То есть, мы можем инкапсулировать логику внутри слайса. В остальном сегменты не стандартизированы. Чаще всего встречаются:
ui — визуальное представление;
model — бизнес-логика;
lib — утилиты, хуки, функции-помощники;
constants;
types;
api — работа с API.
Какие бывают слои и зачем они нужны
Shared — слой для абстрактного, переиспользуемого кода. Это могут быть иконки, отображение кнопок, вспомогательные функции и утилиты, которые неоднократно применяются в разных местах приложения.
![Пример из документации FSD: на слое Shared располагаются иконки и кнопки Пример из документации FSD: на слое Shared располагаются иконки и кнопки](https://habrastorage.org/getpro/habr/upload_files/9fc/0a3/d43/9fc0a3d43d222d65f31ea465e371ef50.png)
Важное отличие слоя Shared от остальных: в нём нет слайсов. Он состоит из сегментов, которые мы можем многократно переиспользовать во всем приложении.
![Пример из моего пет-проекта. Здесь нет слайсов, поэтому сегменты располагаются сразу в слое shared Пример из моего пет-проекта. Здесь нет слайсов, поэтому сегменты располагаются сразу в слое shared](https://habrastorage.org/getpro/habr/upload_files/c4c/a51/cc0/c4ca51cc0f2668e38d33f7aecb387113.png)
Entities — слой для конкретных бизнес-сущностей. Например, для приложения социальной сети это будут: пользователь, пост, комментарий.
![Пример из документации. Карточка поста — это самостоятельная сущность Пример из документации. Карточка поста — это самостоятельная сущность](https://habrastorage.org/getpro/habr/upload_files/e8f/f79/0c4/e8ff790c49011ca28375c68bae07a4a1.png)
![Примеры сущностей из пет-проекта. В слое Entities — слайс Article, а внутри него — сегменты model и ui Примеры сущностей из пет-проекта. В слое Entities — слайс Article, а внутри него — сегменты model и ui](https://habrastorage.org/getpro/habr/upload_files/072/2bf/2ae/0722bf2ae239220797db85dd66e0ab72.png)
Features — слой для элементов кода, которые определяют, как пользователь взаимодействует с бизнес-логикой. Это различные кнопки, выпадающие меню, селекты и всё остальное, что несёт бизнесовую логику и с чем можно взаимодействовать.
![Пример из документации. Кнопка Following — это фича Пример из документации. Кнопка Following — это фича](https://habrastorage.org/getpro/habr/upload_files/d1c/83e/36c/d1c83e36c4ce82b58023efb70f6283c9.png)
Есть важное правило: одна фича должна выполнять одну задачу. Мы не можем использовать её для разных случаев, иначе это нарушит концепцию инкапсуляции логики.
![Пример из пет-проекта. Здесь есть фичи для добавления комментария и авторизации по имени пользователя Пример из пет-проекта. Здесь есть фичи для добавления комментария и авторизации по имени пользователя](https://habrastorage.org/getpro/habr/upload_files/343/717/6eb/3437176eb0b630ae15a15c845259b8d7.png)
Widgets — опциональный слой, который связывает сущности и фичи. Он помогает собрать готовый смысловой блок из разных элементов.
![Пример из документации. Готовая карточка поста собирается на слое Widgets Пример из документации. Готовая карточка поста собирается на слое Widgets](https://habrastorage.org/getpro/habr/upload_files/79e/fa5/1d9/79efa51d9dbe3f82f162c3c0525b54e9.png)
Виджеты позволяют расширять функциональность сущности. Например, пост в сообществе и пост на странице пользователя в социальной сети выглядят одинаково. При этом кнопки лайка на них выполняют немного разные функции. На странице пользователя кнопка отправляет уведомление конкретному человеку, а в сообществе — всем пользователям.
![Примеры виджетов из пет-проекта — Sidebar, PageLoader и LangSwitcher Примеры виджетов из пет-проекта — Sidebar, PageLoader и LangSwitcher](https://habrastorage.org/getpro/habr/upload_files/45f/e33/93a/45fe3393ad1758ac0ef6816b9eb717f2.png)
Pages — также композиционный слой. Он нужен, чтобы собирать из виджетов, сущностей и фичей полноценные страницы приложения. Главное правило для страниц — они должны быть максимально «тонкими», не содержать дополнительную бизнес-логику. Весь код мы должны реализовать на слоях ниже.
![Пример из документации — готовая страница социальной сети Пример из документации — готовая страница социальной сети](https://habrastorage.org/getpro/habr/upload_files/050/bd5/f5d/050bd5f5d15cda46c1aa47842cd63021.png)
![Пример из пет-проекта. В идеальной ситуации здесь были бы только импорты, но у меня есть ещё немного лишней логики Пример из пет-проекта. В идеальной ситуации здесь были бы только импорты, но у меня есть ещё немного лишней логики](https://habrastorage.org/getpro/habr/upload_files/cac/b82/34d/cacb8234d89187a7915f1ad99425b9e2.png)
Processes — опциональный слой, который используется крайне редко. Он нужен, если бизнес-логика предполагает использование несколько страниц в одном процессе.
Это может быть аутентификация пользователя по телефону. На одной странице человек вводит номер телефона и пароль, на другой — подтверждает номер, на третьей — вводит капчу.
![Пример из документации: процесс авторизации проходит через несколько страниц Пример из документации: процесс авторизации проходит через несколько страниц](https://habrastorage.org/getpro/habr/upload_files/693/074/c31/693074c31a0cf0fe0010ed208ed96b84.png)
App — это самый верхний, инициализирующий слой. Он содержит корневой компонент, глобальные типы, стили, стейт и оборачивает приложение в провайдеры и контексты — то, что присуще проекту в общем.
![Пример из пет-проекта. В слое App хранятся стили и провайдеры Пример из пет-проекта. В слое App хранятся стили и провайдеры](https://habrastorage.org/getpro/habr/upload_files/ae9/4b3/946/ae94b3946845ee2bf3672f0347199f6c.png)
Как понять, в какой слой поместить код
Не всегда бывает понятно, к какому слою отнести ту или иную сущность. А сделать это нужно сразу — до того, как начнёшь писать код. На такой случай в документации есть список вопросов, который помогает верно распределить сущности:
![](https://habrastorage.org/getpro/habr/upload_files/5de/1c4/371/5de1c43719ea1818976f8ca0bfd27cda.png)
Также в документации есть таблица импорта: какие слои можно импортировать в каждый из остальных слоев. Например, элементы Shared можно использовать на любом другом слое, но в него ничего нельзя добавить. Слой App, наоборот, способен принимать в себя все другие слои, но никуда не импортируется.
![](https://habrastorage.org/getpro/habr/upload_files/5a8/125/c98/5a8125c98df17ceaa213a28d4a73aa2b.png)
Почему FSD лучше обычного способа организации кода
Слои в Featured-sliced design группируются так, чтобы сделать поток данных в приложении линейным и однонаправленным. Это позволяет избежать неявных связей между модулями.
Можно понять, как это работает, если сравнить структуру кода в стандартном варианте и в варианте FSD.
![Классическая структура: все элементы лежат в одном каталоге Классическая структура: все элементы лежат в одном каталоге](https://habrastorage.org/getpro/habr/upload_files/9a2/b0e/e01/9a2b0ee01363c3b5736b41e54ebfe99e.png)
Допустим, у меня есть задача изменить один компонент. Для этого мне нужно найти его в папке «компоненты» — это само по себе бывает непросто, если их много.
Затем мне нужно поправить экшены, константы, другие элементы стейта, которые связаны с моим компонентом. Для этого каждый раз нужно выходить на верхний уровень вложенности в папку src, искать папку constants и в ней — нужные файлы. Затем переходить в actions и снова там искать нужный экшен. Так происходит, потому что в большинстве проектов нет разделения сущностей по бизнес-предназначению.
Получается, что изменяя один компонент, я затрагиваю область всего проекта. Я вынужден исправлять что-то в разных частях кода и постоянно рискую повлиять на что-нибудь ещё.
![Поток данных в классической структуре приложения. Все компоненты влияют друг на друга Поток данных в классической структуре приложения. Все компоненты влияют друг на друга](https://habrastorage.org/getpro/habr/upload_files/793/f6e/376/793f6e3769d81921e2c46318a3df9b17.png)
Такое состояние приложения можно охарактеризовать как слабую связанность и слабую зацепленность. То есть, между модулями нет понятных и явных связей.
![Неочевидные связи в приложении усложняют его поддержку и развитие Неочевидные связи в приложении усложняют его поддержку и развитие](https://habrastorage.org/getpro/habr/upload_files/e5e/e4d/9e6/e5ee4d9e6e713c3b8da37e1c742a62a4.png)
В отличие от обычной структуры, FSD поддерживает сильную связанность внутри модуля.
Например, у нас есть страница продукта, которая использует в себе фичи и виджеты. Фичи используют сущности, а те, в свою очередь, Shared-слои.
![Проект, построенный по методологии FSD: на каждом слое строго определённые элементы кода Проект, построенный по методологии FSD: на каждом слое строго определённые элементы кода](https://habrastorage.org/getpro/habr/upload_files/f5a/3d8/a42/f5a3d8a42aeecb67b8a41cb0d49d45a7.png)
Если мне нужно будет что-то изменить в деталях продукта, то я не смогу повлиять на рекомендации, потому что эти сущности не связаны. Можно даже полностью убрать одну ветку и остальное приложение не пострадает.
![Методология FSD обеспечивает сильную связанность внутри модулей кода и слабую зацепленность между модулями Методология FSD обеспечивает сильную связанность внутри модулей кода и слабую зацепленность между модулями](https://habrastorage.org/getpro/habr/upload_files/84e/3ee/ee7/84e3eeee785acdc41e8a31c31b2d021b.png)
Такое свойство FSD возможно благодаря принципам объектно-ориентированного программирования:
абстракция и полиморфизм — нижние слои не имеют привязки к предметной области, поэтому их можно использовать для разных целей и реализации разной функциональности;
инкапсуляция — Public API в каждом слое позволяет импортировать основную логику из модуля, а её реализация остаётся внутри;
наследование — вышележащие слои используют и расширяют нижележащие.
Стоит ли внедрять FSD в свой проект
У FSD есть несколько важных преимуществ:
Единообразие. В любой команде, которая следует методологии, код будет организован по одним и тем же правилам. Архитектура стандартизируется и новым разработчикам легче влиться в проект.
Контролируемое переиспользование логики. Каждый компонент архитектуры имеет свое назначение и список зависимостей.
Устойчивость к изменениям и рефакторингу. Код можно менять в каждом модуле отдельно, не затрагивая другие.
Ориентированность на потребности бизнеса и пользователей. Весь код разбит на бизнес-домены, поэтому просто определить, в какой его части расположена та или иная фича. Это позволяет легко адаптировать элементы проекта под разные задачи.
Активное комьюнити. В телеграме есть канал, в котором можно пообщаться с создателями методологии и единомышленниками. Там довольно быстро отвечают на любые вопросы и помогают разобраться в тонкостях FSD. Благодаря этому каналу я уже решил несколько своих кейсов.
Но, конечно, есть и недостатки:
Высокий порог входа по сравнению с классическим способом построения архитектуры. Разработчику нужно постоянно думать, как декомпозировать задачу и к какому слою отнести тот или иной модуль.
Нельзя начать писать компоненты, а потом отрефакторить код. Вместо этого нужно сразу определить, какие сущности, фичи, виджеты будут использоваться в проекте.
Процесс внедрения FSD долгий и дорогой. Придётся создавать специальные линтеры, подходы к код-ревью, следить, чтобы вся команда следовала правилам методологии. Это требует осознанности от каждого человека, потому что если один из команды не станет следовать правилам, то весь проект не удастся поддерживать в рамках методологии.
FSD ещё разрабатывается, поэтому в документации описаны не все возможные кейсы. Но этот минус нивелируется активностью сообщества — разработчики быстро помогают решить сложности и описывают в документации разные сложные ситуации.
FSD — это непростая методология. Для работы с ней нужно подготовить команду и дополнительные инструменты. В перспективе внедрение FSD может ускорить и упростить разработку, но необходимость в нём нужно оценивать, исходя из болей и задач конкретной команды разработчиков.
Если вас заинтересовала методология Featured-Sliced Design, дополнительную информацию смотрите по ссылкам на этой странице.
Предыдущая статья: Домашка на лето: что почитать разработчику
Комментарии (10)
GoodGod
07.08.2023 19:42А как оказывается из примеров на сайте feature sliced design - todo app'ы. На udemy смотрел такие курсы "сайт кинофильмов за 4 часа".
egorchh Автор
07.08.2023 19:42Здравствуйте, не совсем понял суть комментария, не могли бы вы более подробно описать?
GoodGod
07.08.2023 19:42+1В простых приложениях, например Todo App на React (классика) очень хорошо работают многие паттерны - например можно разбить компоненты на мельчайшие части, прям компоненты по 1 строчке. Т.е. удается добиться максимального Single Responsibility. Однако это не значит что это сработает в продакшене.
Хотелось бы по продакшеннее примера Feature-Sliced Design.
egorchh Автор
07.08.2023 19:42Согласен, на сайте FSD достаточно простые примеры, которые нужны там скорее для ознакомления с базовыми концепциями методологии. Однако методология хорошо себя показывает в рамках моей компании, несколько проектов переведены на FSD.
К сожалению, не могу привести пример проектов по соображениям NDA, однако предлагаю вам ознакомиться с примерами реальных проектов, которые предоставлены на официальной странице гитхаба Feature Sliced Design: https://github.com/feature-sliced/examples (эти примеры и много другое также можно найти по ссылке с доп. информацией в конце статьи https://github.com/egorchh/Feature-Sliced-Design-information#примеры)
Также вы можете ознакомиться с моим пет-проектом. Крупное приложение построенное на FSD - https://github.com/egorchh/production-project. (можно удобно запустить на своем пк)GoodGod
07.08.2023 19:42Пруфов нет.
egorchh Автор
07.08.2023 19:42FSD предлагает более удобную для разработки структуру приложения. Когда все разложено по полочкам, легче найти место для новой фичи или экрана. Сложно спорить с тем, что порядок в структуре проекта более выгоден для разработки.
Даже если мы разобьем весь проект на компоненты по одной строчке, как в вашем примере выше, это не значит что структура будет расширяемой и гибкой. Мы все еще можем столкнуться с высокой связностью модулей проекта между собой, что чревато сайд эффектами при внедрении нового функционала и тд.
Если заинтересованы методологией, советую попробовать внедрить ее в свой проект или написать его с нуля, тогда, уверен, что вы почувствуете преимущества.GoodGod
07.08.2023 19:42Как менеджер по продажам. "У нас в фирме качество." А что за качество, что там - непонятно.
egorchh Автор
07.08.2023 19:42Цель статьи не прорекламировать FSD, а рассказать о ней, описать минусы и плюсы. Использовать ее или нет - решение каждого разработчика.
Сожалею, если мне не удалось донести всех аспектов и раскрыть тему до конца. Буду учиться писать статьи более развернуто и аргументированно. Спасибо за мнение!
eternal-struggler
Крутая статья, информативно