Common
Common — уровень, определяющий сущности для общего переиспользования. Это сущности, которые не привязаны к конкретной бизнес-логике и могут использоваться в любом месте проекта. А также одиночные сущности которые сложно причислить к какому-то конкретному модулю.
Важно
Несмотря на сходство common из FEOD и shared из FSD, они имеют разные цели и правила использования. Подробнее об отличии еще будет ниже.
Посколько это блок наибольших заблуждений, то тут будет множество отсылок на FSD, но если вы не знакомы с FSD, то это не проблема, пометки в первую очередь стоят чтобы именно привыкшие к FSD разработчики не путали common и shared из FSD.
Возможное альтернативное название:
shared— привычнее для пользователей FSD. Но стоит осознавать, что это не совсем то же самое что это не тот же самыйsharedиз FSD.
Важность уровня
На самом деле данный уровень является опциональным и утилитарным. Он решает задачу: «куда положить сущности которые не привязаны ни к чему не привязаны и слишком мелкие чтобы стать полноценным модулем».
На самом деле common решается множество задач которые могут быть затруднительными если от него избавиться:
модуль ради модуля
Благодаря данному слою множество модулей которые вмещались бы в 1 файл и сложно объединить в один модуль будут иметь своё место. Вам не придется создавать новый модуль ради одной сущности.
Благодаря данному слою мы можем сильно сократить список модулей в проекте спася его от загрязнения. При этом правила для common достаточно строгие и защищают common от загрязнения самого себя.
Также оно дает время сформироваться полноценному модулю для этой сущности. Когда он станет более явным вы сможете спокойно вынести его в модуль.
Плавное привыкание после FSD
После перехода с FSD многие разработчики могут испытывать дискомфорт от отсутствия shared слоя в модульной архитекутре. common является разумным компромиссом между модульной архитектурой и слоистой.
Как понять, что сущность — это часть Common?
- Это не привязанная к конкретным бизнес-фичам логика
- Если сущность привязана к бизнес-фиче, то лучше переместить её в соответствующий модуль
- Вмещается в один файл
- Если сущности необходимо разделить на несколько файлов, то лучше переместить её в отдельный модуль
- В теории может быть использована в любом месте
- Если это не универсальная сущность, то лучше переместить её в соответствующий модуль
- Ей не нужно взаимодействовать с сущностями уровня Module
- Если сущность взаимодействует с сущностями уровня Module, то лучше переместить её в соответствующий модуль или использовать IoC
Важные правила
- В отдельных случаях возможно использование двух и более файлов на одну сущность, но рекомендуется этого избегать и предпочитать в этом случае Module
- Common могут взаимно использовать друг друга, пока это не создаёт слишком жёсткие связи
- Сущности в Common не могут использовать индексные файлы
Почему запрещено использовать индексные файлы?
- Это создаёт ненужные файлы, которые не несут в себе смысловой нагрузки
- Меньше ненужных действий для создания сущности (не нужно создавать индексный файл и добавлять в него все импорты + следить за этим)
- Это мотивирует при необходимости использовать модули
- Это косвенно вынуждает держать уровень common тонким и не засорять его
Структура
Примеры сущностей Common
Единый пример собирает UI, композаблы, утилиты и типы в одном дереве и наборе файлов.
Выберите файл в дереве слева
Использование Common в проекте
Правильный импорт
// OK Правильно
import Button from '@/common/ui/Button.vue'
import { formatDate } from '@/common/utilities/formatDate'
import { useDebounce } from '@/common/composables/useDebounce'
// ❌ Неправильно (индексные файлы запрещены)
import { Button, formatDate, useDebounce } from '@/common'Использование IoC для работы с модулями
Если common сущность нуждается в функциональности из модуля, используйте IoC:
interface NotificationService {
show(message: string): void
}
export function useNotification(service?: NotificationService) {
const notify = service?.show || console.log
return {
notify
}
}FAQ
Строгий ли запрет на index.ts в Common?
Нет. Но это настоятельная рекомендация, которая помогает держать common уровень тонким и не засорять его. Мы настаиваем, чтобы вы 10 раз подумали перед тем, как начать использовать индексные файлы в common.
Это решение было принято для нескольких целей:
- Сборщику придётся меньше бороться с
barrel-файлами, что улучшает производительность проекта. В случае модулей мы вынуждены использоватьindex.ts-файлы, чтобы обеспечить публичный интерфейс модуля, но уcommonтакой необходимости нет - Это мотивирует при необходимости использовать модули, так как связывать сущности между собой становится сложнее
- Это косвенно вынуждает держать уровень
commonтонким и не засорять его, так как при разрастании импорты изcommonстановятся более громоздкими
Если вы взвесили все за и против, то ваше право сохранить использование индексных файлов и здесь. Но мы настоятельно рекомендуем избегать этого.
Когда выносить сущности из Common?
- Когда несколько common-сущностей сцепливаются между собой, то, скорее всего, они реализуют какую-то общую задачу. Их лучше вынести в модуль.
- Когда сущность привязывается плотно к бизнес-логике. Например, функция регистрации вряд ли будет Common.
- Когда сущность вынуждена использовать сущности из других уровней, кроме Global
Это нормально если по мере жизни проекта вы будете выносить эти сущности в модули. Во многом это и есть задача common слоя.
Как использовать сущность из модуля, если это необходимо в Common?
Для этого можно применить IoC (Inversion of Control). И прокинуть необходимую сущность в Common.
UI-модуль и Common
Так как UI предполагает между собой тесно связанные элементы, то лучше держать его в отдельном модуле, а common оставить для примитивных сущностей. Однако нам часто необходимо использовать компоненты из UI-модуля в common-уровне. В этом случае у нас есть несколько путей: IoC или же исключение из правила про запрет на импорты modules из common. Да, это плохо. Но лучшее — враг хорошего: порой лучше поступиться, чем значительно усложнить проект. Либо же оформить его как псевдо-модуль внутри common.
Common как модуль
Может возникнуть вопрос, почему Common не является модулем сам по себе?
- Common не является модулем, потому что он не предназначен для взаимодействия с другими модулями.
- Common предназначен для хранения общих сущностей, которые могут быть использованы в любом месте проекта без особой специфики.
- Для common действуют особые правила экспорта, противоречащие правилам модулей (запрет на использование индексных файлов).
- Это позволяет поддерживать количество модулей минимально необходимым для проекта.
- Дополнительные правила в common служат противовесом для загрязнения общего уровня.
Однако существуют модификации FEOD, которые позволяют common быть модулем. Подробнее об этом вы можете прочитать в разделе Common Module.
Design System — это Common?
- Design System не вполне укладывается в common-уровень.
- Однако из-за сильной связанности элементов между собой, лучше держать его в отдельном модуле, а common оставить для примитивных сущностей.
- Однако если это просто набор базовых компонентов для отображения, не образующих дизайн-систему, то это может быть Common.
- Если вы используете стороннюю библиотеку компонентов, то вы вполне можете держать здесь переопределения компонентов и прочие донастройки.
Отличия common из FEOD и shared из FSD
Самое важное отличие, что ориентированный на слои абстракции FSD использует common как самый базовый уровень из которого строятся остальные. В это время FEOD ориентирован на модули и использует common как отправную точку для того, что еще не сформировалось в модуль.
- Common из FEOD и shared из FSD являются уровнем для общих сущностей, которые могут быть использованы в любом месте проекта без особой специфики.
- Common из FEOD и shared из FSD могут взаимно использовать друг друга, пока это не создаёт слишком жёсткие связи.
- Common из FEOD и shared из FSD имеют запрет на импорты из других уровней.
Далее отличия:
- Common из FEOD имеет запрет на использование индексных файлов, в то время как shared из FSD наоборот заставляет их использовать.
- Common из FEOD не пытается быть отдельным слоем абстракции, в то время как shared из FSD пытается сделать его таковым.
Соответственно типичный паттерн мышления: если я хочу организовать взаимодействия между сущностями верхних слоев, то я могу использовать низлежащий такой как shared для этого. В случае FEOD же мы не рекомендуем делать таким же образом: это ведет к тому что связанные сущности будут сильно оторванны друг от друга по принципу абстракции, а не логике.
В FEOD common это как перевалочный пункт для сущностей которые еще не сформировались в модуль. И как только придет момент они могут быть перемещены в модуль и удалены из common. В то время как в FSD shared это слой в первую очередь уровня абстракции, поэтому элементы из него могут быть перенесены в крайне редких случаях.