Привет! Меня зовут Егор Подольский, я фронтенд-инженер в Авито. Знакомство с Feature-Sliced Design я начал не так давно. Её используют немногие, а я попробовал применить её, и влюбился. Решил рассказать о FSD, потому что считаю этот подход удобным и перспективным.

Featured-sliced Design — это свод правил и требований к организации кода, который делает разработку легче. Методология разработана для фронтенд-приложений, но отдельные концепции из FSD можно использовать и для бэкенда.

Лучше всего суть методологии раскрывается в проектах среднего размера, так как FSD — это про организацию. В одностраничных приложениях, с парой папок, не получится прочувствовать все преимущества методологии, а в слишком больших, наподобие Google Cloud, её будет недостаточно для построения архитектуры. Но FSD может стать отправной точкой, с которой можно начать разработку.

Featured-sliced Design не привязана к конкретному фреймворку или state-менеджеру, поэтому её можно внедрять в командах с разным стеком. Примеры проектов, которые применяют FSD, есть на сайте разработчиков методологии.

Структура Featured-sliced Design

Главное правило, на котором строится методология: все элементы кода разделены по зоне ответственности (слои), предметной области (слайсы) и техническому назначению (сегменты).

Семь слоёв делят код по зонам ответственности. Они строго стандартизированы во всех проектах: в любой команде каждый слой будет отвечать за одно и то же.

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

Направляясь по слоям от Shared к App, мы идём от абстрактности к предметной области
Направляясь по слоям от Shared к App, мы идём от абстрактности к предметной области

В каждом слое находятся слайсы. Они разделяют код по предметной области, к которой относится та или иная функция. Это облегчает поиск нужного элемента в проекте.

В слайсах находятся сегменты, которые делят код по техническому назначению. Один из них — Public API, который нужен для импорта других сегментов наружу. То есть, мы можем инкапсулировать логику внутри слайса. В остальном сегменты не стандартизированы. Чаще всего встречаются: 

  • ui — визуальное представление;

  • model — бизнес-логика;

  • lib — утилиты, хуки, функции-помощники;

  • constants;

  • types;

  • api — работа с API.

Какие бывают слои и зачем они нужны

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

Пример из документации FSD: на слое Shared располагаются иконки и кнопки
Пример из документации FSD: на слое Shared располагаются иконки и кнопки

Важное отличие слоя Shared от остальных: в нём нет слайсов. Он состоит из сегментов, которые мы можем многократно переиспользовать во всем приложении.

Пример из моего пет-проекта. Здесь нет слайсов, поэтому сегменты располагаются сразу в слое shared
Пример из моего пет-проекта. Здесь нет слайсов, поэтому сегменты располагаются сразу в слое shared

Entities — слой для конкретных бизнес-сущностей. Например, для приложения социальной сети это будут: пользователь, пост, комментарий.

Пример из документации. Карточка поста — это самостоятельная сущность
Пример из документации. Карточка поста — это самостоятельная сущность
Примеры сущностей из пет-проекта. В слое Entities — слайс Article, а внутри него — сегменты model и ui
Примеры сущностей из пет-проекта. В слое Entities — слайс Article, а внутри него — сегменты model и ui

Features — слой для элементов кода, которые определяют, как пользователь взаимодействует с бизнес-логикой. Это различные кнопки, выпадающие меню, селекты и всё остальное, что несёт бизнесовую логику и с чем можно взаимодействовать.

Пример из документации. Кнопка Following — это фича
Пример из документации. Кнопка Following — это фича

Есть важное правило: одна фича должна выполнять одну задачу. Мы не можем использовать её для разных случаев, иначе это нарушит концепцию инкапсуляции логики.

Пример из пет-проекта. Здесь есть фичи для добавления комментария и авторизации по имени пользователя
Пример из пет-проекта. Здесь есть фичи для добавления комментария и авторизации по имени пользователя

Widgets — опциональный слой, который связывает сущности и фичи. Он помогает собрать готовый смысловой блок из разных элементов.

Пример из документации. Готовая карточка поста собирается на слое Widgets
Пример из документации. Готовая карточка поста собирается на слое Widgets

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

Примеры виджетов из пет-проекта — Sidebar, PageLoader и LangSwitcher
Примеры виджетов из пет-проекта — Sidebar, PageLoader и LangSwitcher

Pages также композиционный слой. Он нужен, чтобы собирать из виджетов, сущностей и фичей полноценные страницы приложения. Главное правило для страниц — они должны быть максимально «тонкими», не содержать дополнительную бизнес-логику. Весь код мы должны реализовать на слоях ниже.

Пример из документации — готовая страница социальной сети
Пример из документации — готовая страница социальной сети
Пример из пет-проекта. В идеальной ситуации здесь были бы только импорты, но у меня есть ещё немного лишней логики
Пример из пет-проекта. В идеальной ситуации здесь были бы только импорты, но у меня есть ещё немного лишней логики

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

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

Пример из документации: процесс авторизации проходит через несколько страниц
Пример из документации: процесс авторизации проходит через несколько страниц

App — это самый верхний, инициализирующий слой. Он содержит корневой компонент, глобальные типы, стили, стейт и оборачивает приложение в провайдеры и контексты — то, что присуще проекту в общем.

Пример из пет-проекта. В слое App хранятся стили и провайдеры
Пример из пет-проекта. В слое App хранятся стили и провайдеры

Как понять, в какой слой поместить код

Не всегда бывает понятно, к какому слою отнести ту или иную сущность. А сделать это нужно сразу — до того, как начнёшь писать код. На такой случай в документации есть список вопросов, который помогает верно распределить сущности:

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

Почему FSD лучше обычного способа организации кода

Слои в Featured-sliced design группируются так, чтобы сделать поток данных в приложении линейным и однонаправленным. Это позволяет избежать неявных связей между модулями.

Можно понять, как это работает, если сравнить структуру кода в стандартном варианте и в варианте FSD.

Классическая структура: все элементы лежат в одном каталоге 
Классическая структура: все элементы лежат в одном каталоге 

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

Затем мне нужно поправить экшены, константы, другие элементы стейта, которые связаны с моим компонентом. Для этого каждый раз нужно выходить на верхний уровень вложенности в папку src, искать папку constants и в ней — нужные файлы. Затем переходить в actions и снова там искать нужный экшен. Так происходит, потому что в большинстве проектов нет разделения сущностей по бизнес-предназначению.

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

Поток данных в классической структуре приложения. Все компоненты влияют друг на друга
Поток данных в классической структуре приложения. Все компоненты влияют друг на друга

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

Неочевидные связи в приложении усложняют его поддержку и развитие
Неочевидные связи в приложении усложняют его поддержку и развитие

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

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

Проект, построенный по методологии FSD: на каждом слое строго определённые элементы кода
Проект, построенный по методологии FSD: на каждом слое строго определённые элементы кода

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

Методология FSD обеспечивает сильную связанность внутри модулей кода и слабую зацепленность между модулями
Методология FSD обеспечивает сильную связанность внутри модулей кода и слабую зацепленность между модулями

Такое свойство FSD возможно благодаря принципам объектно-ориентированного программирования: 

  • абстракция и полиморфизм — нижние слои не имеют привязки к предметной области, поэтому их можно использовать для разных целей и реализации разной функциональности;

  • инкапсуляция — Public API в каждом слое позволяет импортировать основную логику из модуля, а её реализация остаётся внутри;

  • наследование — вышележащие слои используют и расширяют нижележащие.

Стоит ли внедрять FSD в свой проект

У FSD есть несколько важных преимуществ:

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

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

  • Устойчивость к изменениям и рефакторингу. Код можно менять в каждом модуле отдельно, не затрагивая другие.

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

  • Активное комьюнити. В телеграме есть канал, в котором можно пообщаться с создателями методологии и единомышленниками. Там довольно быстро отвечают на любые вопросы и помогают разобраться в тонкостях FSD. Благодаря этому каналу я уже решил несколько своих кейсов.

Но, конечно, есть и недостатки:

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

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

  • Процесс внедрения FSD долгий и дорогой. Придётся создавать специальные линтеры, подходы к код-ревью, следить, чтобы вся команда следовала правилам методологии. Это требует осознанности от каждого человека, потому что если один из команды не станет следовать правилам, то весь проект не удастся поддерживать в рамках методологии.

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

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

Если вас заинтересовала методология Featured-Sliced Design, дополнительную информацию смотрите по ссылкам на этой странице.

Предыдущая статья: Домашка на лето: что почитать разработчику

Комментарии (10)


  1. eternal-struggler
    07.08.2023 19:42
    +2

    Крутая статья, информативно


  1. egorchh Автор
    07.08.2023 19:42

    Спасибо!


  1. GoodGod
    07.08.2023 19:42

    А как оказывается из примеров на сайте feature sliced design - todo app'ы. На udemy смотрел такие курсы "сайт кинофильмов за 4 часа".


    1. egorchh Автор
      07.08.2023 19:42

      Здравствуйте, не совсем понял суть комментария, не могли бы вы более подробно описать?


      1. GoodGod
        07.08.2023 19:42
        +1

        В простых приложениях, например Todo App на React (классика) очень хорошо работают многие паттерны - например можно разбить компоненты на мельчайшие части, прям компоненты по 1 строчке. Т.е. удается добиться максимального Single Responsibility. Однако это не значит что это сработает в продакшене.

        Хотелось бы по продакшеннее примера Feature-Sliced Design.


        1. 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. (можно удобно запустить на своем пк)


          1. GoodGod
            07.08.2023 19:42

            Пруфов нет.


            1. egorchh Автор
              07.08.2023 19:42

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

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

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


              1. GoodGod
                07.08.2023 19:42

                Как менеджер по продажам. "У нас в фирме качество." А что за качество, что там - непонятно.


                1. egorchh Автор
                  07.08.2023 19:42

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

                  Сожалею, если мне не удалось донести всех аспектов и раскрыть тему до конца. Буду учиться писать статьи более развернуто и аргументированно. Спасибо за мнение!