Призываю переименовать Layers в Feature-Sliced Design методологии
В статье я сначала коротко объясню, как лично я понимаю и использую FSD, для тех, кто не знаком с ней, или знаком, но хочет сравнить с чужим видением.
Однако, пишу я это в основном для того, чтобы обратить ваше внимание, что названия Layers подобраны не по алфавиту, и лично мне это мешает. Подумайте, может и вам мешает. На мой взгляд, их стоит переименовать в алфавитном порядке, даже жертвуя смыслом, чтобы они лучше отображались в файловой структуре проекта.
Краткий экскурс в FSD
FSD — это популярный способ разбиения кода по папкам в фронтенд проектах.
Оригинальные Layers на сайте Feature-Sliced Design методологии
Какую идею можно здесь увидеть?
Если смотреть идейно, то главное, что проект группируется по бизнес логике. Проектирование мысленно начинается с папок /src/entities (Понятия) и /src/features (Действия). Понятия — это те термины, которые вспыхивают в головах топ-менеджеров (пофантазируйте), когда они объясняют или рекламируют ваш продукт. В масштабе проекта их скорее мало, чем много. Такие термины можно найти в документации, тз или пользовательском соглашении. Действия — это действия над понятиями, которые могут совершать пользователи или ваша система.
Пример 1. Всплывающее напоминание в Дуолинго — это /src/entities/notification. Пользователь может их настроить (наверное, не знаю) — это /scr/features/notification-configure, Система умеет их отправлять — это /src/features/notification-send
Важно, что мы стараемся думать, как система выглядит снаружи. Такие серьезные, гордые и надутые предметы, как работа с беком или состоянием, не считаются у нас за понятия. И вдохновение мы черпаем не из более глубоких слоев (интерфейсов и схемы базы), а из внешних (юр. документов и презентаций). То есть в ситуациях Many-to-Many вспомогательные вещи, как users-roles, students-groups и проч., для которых в SQL создается отдельная таблица, а на беке отдельный интерфейс, за entity не считаются, и хранятся в feature ответственной за это отношение.
Какую практическую пользу это создает?
Первая цель такого разбиения — сделать импорты в проекте представимыми в виде водопада — они опускаются до низу любым путем, кроме горизонтального.
Я специально перегрузил схему, чтобы не вводить вас в заблуждение, чтобы в простой схеме вы не отыскали неверных следствий. Из схемы должен проистекать единственный вывод — стрелки никогда не идут вверх, влево или вправо.
Водопад. Схема перегружена специально, чтобы не вводить в заблуждение. Вы не должны делать никаких выводов, кроме одного — стрелки никогда не направлены вверх, влево или вправо, а только вниз. Эта мелочь уже огромное достижение.
Так вот обычно выглядят импорты. Когда нам удается задать им понятное направление, это уже почти чудо.
О каждом слое с примером
Пример 2. Делаем примитивную копию YouTube, скажем, для проекта в вузе.
Shared — базовые классы для Api, класс для работы с датами, библиотека компонентов, обертки над (желательно всеми) библиотеками. (video-player, http-client, myButton, myModal, date-lib).
Библиотеки и внешние компоненты всегда оборачиваю, чтобы можно было легко переехать на новую версию или на самописный вариант. Если api библиотеки слишком большое — искусственно его урезаю до применяемого минимума.
Entities — понятия, которые понятны бизнесу и пользователям. (video, channel, account, playlist, comment). Внутри у меня интерфейсы и самые простые представления этих интерфейсов. IVideo с ui/video-card, IChannel с ui/channel-description и т.д. Понятий относительно немного, они маленькие и причесанные.
Features — действия, что умеет делать программа, что сможет делать пользователь, что мы рекламируем и обещаем. (video-play, channel-create, channel-settings, video-upload, channel-subscribe, comment-create, comment-view, playlist).
Здесь появляется изолированная работа с апи, изолированное управление состоянием, изолированные формы.
Действия можно дробить по мере разрастания, сделать сначала просто comment, после, если что, разбить на comment-сreate/-view/-edit. Если у вас амбиции Ютуба, то можно, наверное, сразу дробить.
Widgets — куски UI, объединяющие разные понятия с разными действиями, реализующие пользовательские сценарии. (video-player, channel-settings, account-settings, playlist, comments-section).
Здесь у меня контейнерные компоненты (если кто еще помнит этот термин). В блоке комментариев на Ютубе соединяются апи комментариев, их стейт, создание, удаление комментариев, отображение аккаунтов пользователей, окно жалоб на спам, все это собирается из разных Понятий и Действий.
Pages — страницы. Слой работы с урл-адресами. (video/$id, channel/$id, /redesign/video/$id, /redesign/channel/$id, /my-channel/upload-video)
В них я обычно не делаю ничего, кроме работы с роутингом и лейаутом, все остальное внутри виджетов. Когда сметаешь это из всего остального проекта, получается достаточно ответственности.
Отсюда я пробрасываю в виджеты функции getVideoRoute (id), getChannelRoute (id), …, чтобы можно было проследить кто, куда и откуда идет.
Приятно, когда в pages ничего больше нет. Можно отследить, где используется эта страница, можно хранить разные версии виджетов на разных адресах, можно хранить одинаковую версию виджетов на разных адресах (такое мне приходилось делать для PWA).
App — глобальный слой, а значит должен быть самым маленьким. Тут подключение стейт менеджера, работа с языками, инициализация приложения, полифиллы языка. (i18n, state, polyfill, api-init).
Здесь я импортирую и регистрирую api из разных features, это, кстати, помогает их потом найти.
Вы могли заметить, что много раз у папок будут одинаковые имена (video, playlist, comment). Лично я решил с этим смириться.
Из чего сыр-бор? Что я хочу переименовать?
Мне не нравится, что имена слоев подобраны не в алфавитном порядке. На схеме в документации FSD они отсортированы по смыслу, а в меню вашего проекта будут по алфавиту.
Так Layers выглядят в IDE
Даже если сейчас подобраны самые правильные и точные английские названия, я все равно считаю, что надо переименовать слои с требованием, чтобы их иерархия шла в алфавитном (или обратном) порядке. У такого порядка два преимущества:
1) проще работать в активно растущем проекте — когда в одной ветке надо поменять пять из шести папок, начинает раздражать, что pages и shared лежат между features и widgets. Согласен, что мелочь, а неприятно. А решить легко.
Поверьте, куда удобнее, например, сделать все изменения в pages, на время о них забыть, и двигаться вглубь FSD.
2) онбординг — стажеру, бекендеру или иностранцу можно прямо в IDE объяснить, в каком направлении возможны импорты.
Я предлагаю такой вариант:
Мой вариант названий
Мне важны не эти конкретные имена, не в них дело, а в соответствии требованиям:
В алфавитном или обратном порядке
По-возможности далеки от словаря бизнеса и фронтенда
Хорошо, если короче
Хорошо бы меньше отличий от текущих
Как-то соответствуют смыслу (* тут я не уверен насчет своих gears. Думал еще про goods, gadgets или gems (как в руби)).
Вопрос: Почему я просто не переименовал папки в своих проектах?
Ответ: Переименовал. Но хочется, чтобы так было везде, на то и методология. Чтобы на новый проект пришел, а там имена по алфавиту.
Я считаю, что это не мой пустой каприз, а упущенное требование, о котором сразу не задумываешься, а потом становится поздно.
Подумайте, может и вам это мешает.