Публичное API модуля приложения
Каждая сущность методологии проектируется как удобный в использовании и интеграции модуль.
Цели
Удобство использования и интеграции модуля достигается через выполнение ряда целей:
- Приложение должно быть защищено от изменений внутренней структуры отдельных модулей
- Переработка внутренней структуры модуля не должна затрагивать другие модули
- Существенные изменения поведения модуля должны быть легко определяемы
Существенные изменения поведения модуля - изменения, ломающие ожидания сущностей-пользователей модуля.
Достичь этих целей позволяет введение публичного интерфейса (Public API), представляющего собой единую точку доступа к возможностям модуля и определяющего "контракт" взаимодействия модуля с внешним миром.
Структура сущности должна иметь единую точку входа, предоставляющую публичный интерфейс
└── features/ #
└── auth-form/ # Внутренняя структура фичи
├── ui/ #
├── model/ #
├── {...}/ #
└── index.ts # Энтрипоинт фичи с ее публичным API
export { Form as AuthForm } from "./ui"
export * as authFormModel from "./model"
Требования к публичному API
Выполнение этих требований позволяет свести взаимодействие с модулем к выполнению публичного интерфейса-контракта и, тем самым, достичь надежности и удобства в использовании модуля.
1. Контроль доступа
Public API должен осуществлять контроль доступа к содержимому модуля
- Другие части приложения могут использовать только те сущности модуля, которые представлены в публичном интерфейсе
- Внутренняя часть модуля за пределами публичного интерфейса доступны только самому модулю.
Примеры
Отстранение от приватных импортов
-
Плохо: Идет обращение напрямую к внутренним частям модуля, минуя публичный интерфейс доступа - опасно, особенно при рефакторинге модуля
- import { Form } from "features/auth-form/components/view/form"
-
Хорошо: API заранее экспортирует только нужное и разрешенное, разработчику модуля теперь нужно думать только о том, чтобы не ломать Public API при рефакторинге
+ import { AuthForm } from "features/auth-form"
2. Устойчивость к изменениям
Public API должен быть устойчивым к изменениям внутри модуля
- Изменения, ломающие поведения модуля, должны отражаться в изменении Public API
Примеры
Абстрагирование от реализации
Изменение внутренней структуры не должно приводить к изменению Public API
-
Плохо: перемещение или переименование этого компонента внутри фичи приведет к необходимости рефакторить импорты во всех местах использования компонента.
- import { Form } from "features/auth-form/ui/form"
-
Хорошо: интерфейс фичи не отображает её внутреннюю структуру, внешние "пользователи" фичи не пострадают от перемещения или переименования компонента внутри фичи
+ import { AuthForm } from "features/auth-form"
3. Интегрируемость
Public API должен способствовать легкой и гибкой интеграции
- Должен быть удобен для использования остальными частями приложения, в частности, решать проблему коллизии имен
Примеры
Коллизия имен
-
Плохо: будет коллизия имен
export { Form } from "./ui"
export * as model from "./model"export { Form } from "./ui"
export * as model from "./model"- import { Form, model } from "features/auth-form"
- import { Form, model } from "features/post-form" -
Хорошо: коллизия решена на уровне интерфейса
export { Form as AuthForm } from "./ui"
export * as authFormModel from "./model"export { Form as PostForm } from "./ui"
export * as postFormModel from "./model"+ import { AuthForm, authFormModel } from "features/auth-form"
+ import { PostForm, postFormModel } from "features/post-form"