image

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

Вот почему в этой статье мы хотим рассказать вам об архитектуре FSD (Feature-Sliced Design, дословно «послойное проектирование фич»), одной из самых современных, надёжных и спроектированной специально для фронтенд-проектов. Она подходит почти для любых бизнес-условий, позволяет решать повседневные проблемы и интуитивно понятна разработчикам-новичкам.

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

Обзор архитектуры


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

Огромное преимущество этого подхода, выделяющее его на фоне других архитектур для фронтенда – это бизнес-ориентированность. Поэтому архитектура хорошо подходит почти для любого проекта и позволяет поддерживать порядок в ходе добавления новых возможностей. Более того, эту архитектуру можно внедрять постепенно, а это не может не радовать – ведь это значит, что её можно реализовать в уже существующем продукте. Правда, не забывайте, что эта методология проектировалась для использования только на фронтенде.

В FSD-архитектуре проект состоит из уровней (layers), каждый уровень состоит из срезов (slices), а каждый срез состоит из сегментов (segments). Прежде, чем подробнее познакомиться со слоями, срезами и сегментами, предлагаю взглянуть, как эта архитектура выглядит глобально (см. ниже).

image

Слои


Каталоги верхнего уровня в «FSD» называются «слоями», и это первый уровень дробления приложения. У нас есть строго определённое число возможных слоёв, некоторые из них опциональные. Слои стандартизируются, и в настоящее время выделяется семь таких слоёв:
  • Разделяемый уровень. Содержит различные ресурсы для повторного использования, не зависящие от функционирования бизнес-логики. Отличные примеры таких элементов – инструменты для работы с UI, вспомогательные функции, логгеры.
  • Уровень объектов. Он содержит бизнес-объекты, специфичные для проекта. Например, User, Payments, Products и т.д.
  • Уровень фич. Содержит пользовательские истории. Код, ценный с точки зрения бизнеса. Например, ChangePassword, MakePayment, BuyProduct.
  • Уровень виджетов. Содержит компоненты, из которых составляются объекты и фичи. Например, UserSettings, PaymentsList, ProductsList.
  • Уровень страниц. Содержит страницы приложения. Это композиционный уровень, собираемый из объектов, фич и виджетов.
  • Уровень процессов. Содержит сложные внутристраничные сценарии, например, механизмы аутентификации и капчу.
  • Уровень приложения. Содержит настройки приложения, стили и провайдеры. Например, withAuth.

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

image

Чем ниже модуль расположен в этой иерархии, тем опаснее производить его рефакторинг. Например, если вы измените компонент Modal на разделяемом уровне, это сильнейшим образом скажется на всём приложении.

Срезы


Теперь давайте поговорим о «срезах». Это просто подкаталоги в каждом из слоёв, они зависят от специфики проекта, от команды и технологического стека. Кроме того, они не привязаны к таким абстрактным сущностям как слои, каждый срез соответствует конкретной вещи. Можете считать, что это модули, для которых определён набор правил, и этим правилам нужно следовать:
  • Срезы, относящиеся к одному и тому же слоя, не могут напрямую использовать друг друга.
  • Композиция конкретного слоя должна быть описана в слое, расположенном прямо над ним.
  • В большинстве случаев следует избегать вложения при работе со срезами и применять только струтурное группирование по каталогам.

Вот как могут выглядеть срезы на каждом из возможных слоёв:

├── app/
|   # Слой композиции приложения
|   # Содержит только абстрактную логику инициализации и статические ресурсы – следовательно, не содержит никаких срезов
|
├── processes/
|   # Срезы, реализующие потоки задач, не зависящие от страниц, такие, в выполнение которых вовлечено множество страниц 
|   ├── auth
|   ├── payment
|   ├── quick-tour
|
|
├── pages/
|   # Срезы, реализующие полные представления для этого приложения
|   ├── feed
|   |
|   ├── profile
|   |   # Из-за специфики маршрутизации в этом слое могут содержаться вложенные структуры 
|   |   ├── edit
|   |   └── stats
|   |
|   ├── sign-up
|
|
├── widgets/
|   # Срезы, реализующие различные комбинации абстрактных и/или бизнес-блоков с нижележащих слоёв,
|   # для предоставления изолированных атомарных фрагментов пользовательского интерфейса
|   ├── chat-window
|   ├── header
|   ├── feed
|
|
├── features/
|   # Срезы, реализующие пользовательские сценарии; обычно здесь приходится оперировать бизнес-объектами 
|   ├── auth-by-phone
|   ├── create-post
|   ├── write-message
|
|
├── entities/
|   # Срезы, реализующие бизнес-блоки в терминах того, какая бизнес-логика приложения сработает 
|   ├── account
|   ├── conversation
|   ├── post
|   ├── wallet
|
|
├── shared/
|   # Этот слой – набор абстрактных сегментов
|   # Это означает, что на нём недопустимы какие-либо бизнес-блоки или логика, имеющая отношение к бизнесу 

Сегменты


Каждый срез состоит из более мелких модулей, именуемых «сегментами». Они помогают разделить код внутри среза в зависимости от технического назначения этого кода. Вот список наиболее распространённых сегментов, но здесь можно проявлять гибкость – добавлять или удалять какие-либо сегменты
  • Сегмент UI. Просто содержит логику пользовательского интерфейса
  • Сегмент моделей. Содержит бизнес-логику, в частности, операции сохранения, действия, эффекты
  • Библиотечный сегмент. Содержит инфраструктурную логику, в частности, утилиты и вспомогательные функции
  • Конфигурационный сегмент. Содержит конфигурацию среза
  • Сегмент API. Содержит логику запросов к API, в частности, описывает сами запросы или экземпляры API

Публичный API


У каждого «среза» и «сегмента» должно быть собственное объявление «публичного API». Это просто файл индекса, представляющий собой точку доступа к внутренней структуре модуля и определяющий, как можно взаимодействовать с этим модулем извне.

└── features/ # 
 ├── auth-form / # внутренняя структура фичи
 | ├── ui/ #
 | ├── model/ #
 | ├── {…}/ #
 | ├── index.ts # Входная точка и ей публичный API 

Поскольку «Публичный API» является входной точкой в модуль, есть несколько правил, которым вы должны следовать при работе с ним:
  • Другие элементы приложения могут использовать только те объекты модуля, которые представлены в публичном интерфейсе.
  • Внутренняя часть модуля, не относящаяся к публичному интерфейсу, открыта для доступа только из пределов самого модуля.

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

За и против этой архитектуры


Несомненно, “Feature Sliced Design” – это очень ценная находка. Он блещет по сравнению с другими подходами почти в любом практическом случае. Его основные достоинства таковы:
  • Ориентированность на потребности пользователя и бизнеса
  • Контролируемое повторное использование логики
  • Стабильность при внесении изменений и рефакторинге
  • Высокая масштабируемость как на уровне архитектуры, так и на уровне команды
  • Постепенный переход на эту архитектуру
  • Независимость от технологического стека
  • Высокая стандартизация
  • Отличная документация и большое сообщество

Недостатки:
  • С самого начала требует от разработчика подробнее знать проект, поскольку при таком подходе придётся сразу приносить пользу. Но, если честно, этот подход также сокращает объём необходимых знаний о проекте, так как хорошо стандартизирован.
  • Не подходит для минимально жизнеспособных моделей (MVP) или короткоживущих проектов, так как удлиняется необходимое для разработки проекта, а на короткой дистанции достоинств этого подхода можно и не почувствовать.
  • Требует воспитывать в команде особую культуру и строго проводить ревью кода, чтобы в нём соблюдались все архитектурные принципы.

В целом «Feature Sliced Design» – мощный подход, который пойдёт вашему проекту только на пользу. Разбивая приложение на мелкие модульные компоненты, можно создавать слабосвязанный код, обладающий высоким сцеплением.

Замечание: стоит упомянуть, что для работы с FSD вам идеально подойдёт такой набор инструментов с открытым исходным кодом, как Bit. Когда выявите общие компоненты, действующие во всех ваших микрофронтендах и изолируете их, можете воспользоваться Bit для управления, версионирования и совместного использования этих компонентов в разных проектах. Это элегантное и удобное в поддержке решение, которое поспособствует как масштабированию, так и многоразовому использованию, а также улучшит коллаборацию между разными командами. Подробнее о нём рассказано здесь.

image

«FSD» слабая связность и высокое сцепление кода

Сравнение с «простой модульной» архитектурой


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

Представляется, что в любых сложных и среднесложных проектах следует отдавать предпочтение «Feature Sliced Design» перед «простой модульной архитектурой». Ведь FSD действительно решает множество фундаментальных архитектурных проблем и почти не имеет недостатков.

В простоте и скорости разработки «простая модульная архитектура» выигрывает у FSD. Если вам нужна минимальная жизнеспособная модель, или вы разрабатываете короткоживущий проект, то простая модульная архитектура может быть более приемлемой.

Если вы хотите подробнее изучить «Feature Sliced Design», то почитайте официальную документацию.

imageЕсли же вы хотите больше узнать про архитектуру программного обеспечения, то вашему вниманию мы предлагаем книгу Марка Ричардса и Нила Форда «Фундаментальный подход к программной архитектуре: паттерны, свойства, проверенные методы»:

» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — Архитектура
По факту оплаты бумажной версии книги на e-mail высылается электронная книга.

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


  1. GerrAlt
    29.06.2023 14:00
    +1

    Feature-Sliced Design, дословно «послойное проектирование фич»

    мне кажется что дословно "дизайн нарезанный по фичам" (если мы конечно считаем что feature можно переводить как фича)


  1. Vadiok
    29.06.2023 14:00
    -1

    А какое преимущество деления на 3 ограниченных уровня вложенности? Почему бы не использовать условно бесконечную глубину по мере надобности?


    1. MANAB
      29.06.2023 14:00
      +1

      Предположу, что сложно запомнить бесконечную иерархию. Почти тоже самое, что запоминать спагетти-код)


      1. Vadiok
        29.06.2023 14:00
        -1

        Чтобы не говорить абстрактно, возьмём в пример компоненты. Есть список товаров с фильтром по некоторым параметрам. В этом фильтре каждое числовое значение можно сравнить на больше, больше или равно и т.д.

        Такой компонент хранился бы в Product/List/Filter/Parameter/ParameterComparator.vue. И мне совершенно не зачем что-то помнить, по иерархии понятно, где это находится.


  1. dedmagic
    29.06.2023 14:00

    Уровень processes авторы методологии уже пару месяцев как отменили.


    1. Bone
      29.06.2023 14:00

      Хорошо. Как раз этот уровень я меньше всего понял из статьи.


  1. LyuMih
    29.06.2023 14:00

    Многие реальные проекты: Нет архитектуры — нет проблем