Перейти к содержанию

Сегменты

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

Место в модели

Сегмент появляется только внутри уже определённого модуля:

text
Слой → [Группа*] → Модуль → [Сегмент*]

Группа классифицирует модули внутри слоя. Сегмент классифицирует код одного модуля. Ни группа, ни сегмент не являются владельцами.

Все файлы, framework-компоненты, состояние, зависимости и lifecycle-код сегмента принадлежат ближайшему модулю. Исключением является только вложенный модуль, который начинает собственную границу владения.

Назначение

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

text
profile/
├── index.ts          # Публичный фасет
├── profile.tsx       # Главная реализация
├── components/       # Возможный сегмент
├── hooks/            # Возможный сегмент
├── services/         # Возможный сегмент
├── stores/           # Возможный сегмент
├── types/            # Возможный сегмент
└── styles/           # Возможный сегмент

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

Сегмент:

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

Локальный index.ts может использоваться во внутренней единице сегмента. Он не превращает эту единицу или сегмент в модульную границу.

Framework-компоненты

Framework-компоненты являются обычным внутренним кодом модуля. Они могут выполнять визуальные и невизуальные роли, включая Provider, Guard или Error Boundary, если используемый фреймворк считает соответствующую сущность компонентом.

Помимо опционального главного framework-файла в корне, остальные компонентные единицы размещаются на одном внутреннем уровне относительно модуля. Каталог такой единицы может содержать локальные styles, types, hooks, tests и внутренний index.ts, но не содержит другие компонентные единицы или вложенные модули.

text
header/                              # Модуль
├── index.ts                         # Публичный фасет
├── header.tsx                       # Главная реализация
└── components/                      # Сегмент
    ├── button-submit/
    │   ├── index.ts                 # Локальная точка входа
    │   ├── button-submit.tsx
    │   ├── styles/
    │   ├── types/
    │   └── hooks/
    └── icon.tsx                     # Соседняя компонентная единица

ButtonSubmit может рендерить Icon, но их файловые области не вкладываются друг в друга. Ограничение относится к файловой структуре, а не к runtime-дереву.

Внешний код не импортирует components/button-submit. Если компонент нужен снаружи, модуль-владелец реэкспортирует его через собственный публичный фасет.

Вложенные модули

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

text
landing/                  # Родительский модуль
└── modules/              # Сегмент
    └── hero/             # Вложенный модуль
        ├── index.ts      # Публичный фасет вложенного модуля
        ├── hero.tsx      # Главная реализация hero
        └── modules/      # Допустимая модульная рекурсия
            └── media/
                └── index.ts

Компонентный каталог не содержит components или modules. Рекурсивная структурная вложенность допускается только через вложенные модули. Имена components и modules являются примерами локального стайлгайда, а не обязательными соглашениями SLM.

Выбор размещения

СитуацияРешение
Код относится к существующему владельцу и группируется по назначениюСегмент
Вспомогательный код нужен только одной компонентной единицеКолоцировать в её локальном каталоге
Выделена отдельная framework-компонентная единицаРазместить на общем внутреннем уровне модуля
Код нужен нескольким внутренним единицам модуляПоднять в ближайший общий сегмент
Появилась самостоятельная связная подответственностьСоздать вложенный модуль
Файл однозначно является главной реализацией или сборкой ответственностиДопустимо разместить в корне модуля
Файл не является главным или его роль неоднозначнаРазместить в подходящем сегменте

Размер каталога и количество файлов не определяют модульную границу. Её создаёт только самостоятельная ответственность и назначение нового владельца.

Связанные правила

Документация SLM Design