ADR-UI-002. Префикс, именование и конвенции

ADR Версия: 1.1 accepted

Чтобы исключить коллизии селекторов с другими Angular-приложениями и обеспечить предсказуемый стиль во всём проекте, нужен свой префикс и единый набор базовых конвенций. Правила опираются на актуальный стиль Angular 22 и учитывают переносимость собственного набора компонентов.

⟨/⟩ Исходник

1. Контекст и постановка задачи

Нужен свой префикс (чтобы селекторы и шаблонные идентификаторы не сталкивались с другими Angular-приложениями и заимствованным кодом) и единый набор конвенций — чтобы стиль был предсказуем, а будущая автоматизация (skills/codegen) опиралась на стабильные правила.

Учитываем переносимость: собственный набор компонентов (ui/) должен выноситься в другой проект без переписывания. Отсюда — префикс держим там, где он реально нужен (DOM-селекторы), а имена TypeScript-классов оставляем нейтральными.

2. Драйверы решения

  1. Отсутствие коллизий селекторов и шаблонных идентификаторов с другими приложениями.
  2. Единообразие ревью — стиль предсказуем, мелочи не обсуждаются в каждом PR.
  3. Опора на нативные средства Angular 22 — signals, native control flow, host в декораторе, OnPush по умолчанию.
  4. Переносимость набора — вынос ui/ в другой проект меняет минимум (префикс селекторов), не трогая имена классов.
  5. Автоматизация — генераторы компонентов/сервисов опираются на явные правила.

3. Рассмотренные варианты

4. Решение

Выбран Вариант B. Префикс icd — только в селекторах компонентов/директив и именах пайпов (шаблонные идентификаторы). Имена TypeScript-классов — чистый PascalCase без префикса и без суффикса (стиль Angular 22). При выносе ui/ в библиотеку меняется только префикс селекторов (в eslint.config.js и шаблонах) — классы переносятся нетронутыми.

4.1. Именование (стиль Angular 22 — без суффиксов)

Сущность Класс Селектор / имя Файл
Компонент Button icd-button (element, kebab-case) button.ts (+ .html, .scss)
Директива Highlight [icdHighlight] (attribute, camelCase) highlight.ts
Pipe DateYmd icdDateYmd (в шаблоне) date-ymd.ts
Сервис AuthStore auth-store.ts
Реестр маршрутов BaseRoutes <feature>.routes.ts
Папка фичи modules/<feature-kebab>/

Суффиксы Component / Directive / Pipe / Service не используются (актуальный стиль Angular). Файлы именуются по сущности (button.ts, не button.component.ts). Если имя сервиса коллизирует с типом/моделью — различаем смысловым суффиксом роли (Store, Api, Client), а не техническим Service.

4.2. Разрешение коллизий имён (UI ↔ API)

Имена UI-классов не префиксуются, поэтому теоретически возможно совпадение с типом api-модели (например, UI-контейнер Card и модель Card). На практике риск низкий: набор ui/ — это generic-виджеты (Button, Table, Input), а api-модели ICD — доменные (InformationCard, InputPacket, FundItem), пересечений почти нет. Разрешение:

Префикс на имена UI-классов не вводим (переносимость набора важнее); коллизии закрываются на стороне api-моделей. Детали контракта api-моделей — в отдельном ADR.

4.3. Базовые конвенции компонентов

4.4. Структура класса

Порядок членов класса — строгий, двухуровневый:

  1. По роли (внешняя ось): поля → конструктор → методы. Все поля — вверху класса, до конструктора; методы — после него.
  2. По области видимости (внутренняя ось, внутри полей и внутри методов): publicprotectedprivate.

Итоговая раскладка сверху вниз:

Группа
1 public-поля
2 protected-поля
3 private-поля
4 конструктор
5 public-методы
6 protected-методы
7 private-методы

Уточнения: static-члены идут перед экземплярными в своей группе; геттеры/сеттеры трактуются как методы соответствующей видимости. Для Angular-компонентов это ложится естественно: input() / output() (public-поля) → производное состояние computed() (protected-поля) → внедрённые зависимости inject() (private-поля) → методы.

4.5. Комментарии

4.6. TypeScript

5. Положительные следствия

6. Отрицательные следствия и компромиссы

7. Проверка

Связанные артефакты

Документы