Pull to refresh

Привет, я FSD, чем могу помочь?

Level of difficultyEasy
Reading time7 min
Views6.5K

Привет, странник👋

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

Я Туманова Ирина, фронтендер в компании VR Supersonic ✌️

Предыстория

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

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

Что ты такое, FSD?

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

Отличные материалы для ознакомления:

  1. Официальная документация - обзор

  2. Другими словами, все по полочкам

Базово пробежимся по основным понятиям, попробуем разобраться, а как оно совместимо с кодом.

Базовые понятия по документации с дополнениями

Архитектура FSD
Архитектура FSD

Слои

  1. shared — переиспользуемый код, не имеющий отношения к специфике приложения/бизнеса. (например, UIKit, libs, API). Этот код можно спокойно переносить с проекта на проект. Если при создании функции/компонента ты понимаешь, что это можно использовать для сайта интернет магазина и онлайн бухгалтерии, то, пожалуй, это shared :)

  2. entities (сущности) — бизнес-сущности. (например, User, Product, Order), они же бизнес-обьекты, присущие данному бизнесу. О том, что такое бизнес-сущность и как она зарождается, можно прочитать здесь

  3. features (фичи) — взаимодействия с пользователем, действия, которые несут бизнес-ценность для пользователя. (например, SendComment, AddToCart, UsersSearch). Фичи взаимодействуют с сущностями: изменяют, отправляют, удаляют и подобное. Все действия над сущностью выделяются в фичи 

  4. widgets (виджеты) — композиционный слой для соединения сущностей и фич в самостоятельные блоки (например, IssuesList, UserProfile). Также в виджеты можно выделять компоненты+логику, которые характерны для данного продукта, пускай даже без бизнес составляющей. Например, ThemeProvider+ThemeStore (тема сайта). Конечно, такой код можно поместить в shared, однако в то же время тема является чем-то уникальным для проекта, поэтому ее можно расположить на слое виджетов.

  5. pages (страницы) — композиционный слой для сборки полноценных страниц из сущностей, фич и виджетов.

  6. processes (процессы, устаревший слой) — сложные сценарии, покрывающие несколько страниц. (например, авторизация).

  7. app — настройки, стили и провайдеры для всего приложения.

Одной из ключевых особенностей Feature-Sliced ​​Design является его иерархическая структура. В этой структуре сущности не могут использовать фичи, поскольку фичи находятся выше в иерархии. Аналогично, фичи не могут использовать компоненты виджетов или процессов, поскольку слои выше могут использовать только слои ниже. Однако чем ниже модуль расположен в этой иерархии, тем опаснее производить его рефакторинг, поскольку это скажется на всех слоях выше

Небольшой лайфхак для разработки** если нет уверенности, куда поместить конкретную часть проекта, то начинаем с верхнего слоя (widgets). Если виджеты могут использовать эту логику, то перемешаем ниже на features или entitites в зависимости от наполнения - если есть логика, то в фичи, иначе в сущности. Если сущности или фичи могут использовать этот код, то опускаем на самый нижний слой - shared.

Срезы

Отличие от обычной модульной системы в том, что слои логично поделены по уровню своего влияния на проект, возникновение других побочных папок на верхнем уровне невозможно. В модульной архитектуре и в архитектуре “без архитектуры” очень часто случается некая “солянка” из папок api, lib, hooks, help, types, styles, consts, config, tests и подобных, из-за от папки к папке структура всегда “новая”.

Архитектура "Без архитектуры", она же Стандартная :)
Архитектура "Без архитектуры", она же Стандартная :)

Для выделения срезов используются бизнес-сущности (entities), действия над ними ( features), конкретные вещи (widgets, pages). Немного правил по срезам, а потом разберемся с сущностями (может, в виде гномиков):

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

  • В большинстве случаев следует избегать вложения при работе со срезами и применять только струтурное группирование по каталогам. Однако! Бывают случаи, когда можно использовать подкаталоги в срезах - если речь идет о подсущностях (нечто, что существует только в рамках верхнеуровневого нечто) - пример в документации

Пример срезов на каждом из слоев:

СУЩНОСТЬ - что это? А бизнес сущность? Когда я начинала изучать данную архитектуру, для меня это определение было мало понятным. Вы можете ознакомиться с определением, например, по этой ссылке. Однако как фронтендеры мы можем воспользоваться лайфхаком - использовать наших дорогих бекендеров, а точнее запросы, которые они нам пишут :) Бекендеры чаще нас оперируют обьектами и классами, и при грамотной архитектуре они отталкиваются от сущностей. Следовательно, по началу можно использовать то деление на сущности, какое используется на беке, например, user, post, result, report, group и подобное.

Немного отвлечемся - разберем пример сущности, фичи и виджета на примере гномика

Надеюсь, комикс понятный и наглядный 🙂

Сегменты

Очень хорошее описание + пример в документации

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

  • Сегмент ui - компоненты пользовательского интерфейса, функции форматирования данных

  • Сегмент model - бизнес-логика и хранилища данных, функции для обработки этих данных

  • Cегмент lib - инфраструктурный код, в частности, утилиты и вспомогательные функции

  • Сегмент api- взаимодействие с внешними API, API-методы бэкенда

Не забываем про Public API

Каждый срез и сегмент имеет общедоступный API. Public API представлен файлом index.js или index.ts, который содержит импорты только необходимой функциональности, изолируя ненужную функциональность. 

Правила для публичного API:

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

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

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

От общего к локальному: как?

Небольшой раздел по моим “почемучкам” во время изучения архитектуры(может дополняться)

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

Подробное описание каждого слоя от авторов

Если после описания слоев все равно остаются сомнения, используем принцип “Чем выше, тем лучше”. Порядок действий:

  1. Положим компонент в виджеты. Почему не выше по слоям? Страницы и общие по всему приложению конфиги определить не так сложно, проблемы возникают ниже

  2. Нам нужно использовать этот виджет в других виджетах? Если да, читаем дальше

  3. Кладем компонент в фичи. 

  4. Нам нужно использовать эту фичу в других фичах? Если да, опускаем еще ниже - сущность

  5. По аналогии с 2-4 пунктами проверяем, если опять находим пересечением на одном уровне, то кидаем в shared и не беспокоимся 🙂 

То же самое работает в обратную сторону: если entity использует другую entity, то нужно поднимать ее по слоям выше (помним про елочку зависимостей)

А теперь поговорим о применении

Уже было представлено много ссылок для полного понимания архитектуры, но все познается на практике. Я думала, что поняла FSD, пока не начала переписывать редактор сценария в проекте компании.

Сразу дам полезные ссылочки - сборники проектов, которые написаны по FSD❤️:

  1. https://feature-sliced.design/examples 

  2. https://github.com/feature-sliced/documentation/issues/131 

Как применяли у себя в проекте

Мы шли четко по алгоритму из документации https://feature-sliced.design/docs/get-started/overview#incremental-adoption:

  1. Выделяем shared и app + выносим api на уровень фич. На этом этапе срез фичи может состоять только из апи и моделей, необязательно сразу выделять весь ui, lib и подобное

  2. Выделяем pages + widgets

  3. Выделяем из widgets entities и features

Далее расскажу немного о полезностях, которые ускоряют разработку или делают ее просто немного удобнее :)

Так как все наши фронтендеры работают в WebStorm, мы написали классные шаблоны для папок и файлов, чтобы создание новой фичи/сущности занимало минимум времени. 

Как это выглядит:

Шаблон среза. Все забито empty файлами, чтобы создать удобную систему папок, потом лишние файлы удалятся. Верхний файл - это public api с заготовленными ссылками на все папки среза. Такой шаблон действительно сильно ускоряет процесс разработки, так как не нужно каждый раз вспоминать, какие же папки должны быть в срезе :)

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

Хорошо, разработку мы ускорили, но как быть, если есть проблемы именно с дроблением какого-то огромного компонента на подкомпоненты? Мне помог очень классный способ продумывания структуры, посоветованный коллегой - схема. Я делаю это в MindMaster, потому что красиво.

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

Какие выводы для себя сделала

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

Что дает данная архитектура:

  1. Четкая структура

  2. Контролируемое переиспользование логики

  3. Стабильность при внесение изменений или рефакторинге

  4. Удобство при тестировании (при подьеме “наверх” по слоям тестов становится меньше, так как нет повторных проверок функционала компонента из нижнего слоя)

  5. Масштабируемость

  6. Компоненты легко заменять друг на друга благодаря модульности

Но что-то архитектура и забирает:

  1. Высокий порог входа

  2. Необходимость согласовывать дробление по слоям в команде, четкий контроль

  3. Отхождения от архитектуры должны исправлять сразу

  4. Избыточен для небольших проектов, поскольку на “короткой дистанции” польза архитектуры можно не почувствовать, а вот время разработки увеличится в разы

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

Будьте осторожны, вызывает привыкание!!!

Благодарю тебя за твое уделенное время, надеюсь, было интересно и полезно :) Обязательно пиши обратную связь, допилим статью вместе

Tags:
Hubs:
Total votes 10: ↑10 and ↓0+10
Comments13

Articles