Предлагаемая архитектура проекта
Библиотека Steroids Nest предполагает создание приложений с модульной архитектурой, при этом внутри каждого модуля используется луковичная архитектура.
Основные понятия
Модульная архитектура — это подход к разработке программного обеспечения, в котором приложение разбивается на независимые компоненты — модули. Каждый модуль выполняет определенную функцию и имеет свою логику и интерфейс для взаимодействия с другими модулями. Проект состоит из модулей, каждый из которых отвечает за определённую предметную область (авторизация, работа с файлами, управление пользователями и т.д.). Также стоит отметить, что эти модули соответствуют модулям NestJS.
Луковичная архитектура — это подход к построению программного обеспечения, направленный на разделение кода на слои, чтобы минимизировать зависимость от конкретных технологий и обеспечить удобство поддержки и тестирования. Зависимости между слоями этой архитектуры имеют форму ациклического графа и могут быть направлены только в одну сторону, что достигается благодаря принципу инверсии зависимостей.
Принцип инверсии зависимостей - принцип объектно-ориентированного программирования, суть которого состоит в том, что модули верхнего уровня не должны зависеть от модулей нижнего уровня, вместо этого оба типа модулей должны зависеть от абстракций, а абстракции не должны зависеть от деталей реализации.
Каждый модуль делится на две основные части: доменную логику (папки domain и usecases) и инфраструктурный код (папка infrastructure).
Эти два слоя (доменный и инфраструктурный) и один подслой (юзкейсы) имеют следующее направление зависимостей:
Инфраструктурный слой -> (Юзкейсы -> Доменный слой)
Такая архитектура обеспечивает:
- Гибкость и масштабируемость
- Независимость бизнес-логики от инструментов реализации
- Упрощение поддерживания
- Легкость тестирования
- Читаемость и структурированность кода
Доменная часть
В доменной части находится основная бизнес-логика приложения: модели, сервисы, интерфейсы и валидаторы.
Кроме того, к этой части относятся юзкейсы (usecases) — классы, отвечающие за отдельные сценарии взаимодействия с системой.
Код, расположенный в доменной части приложения, не может напрямую обращаться к коду инфраструктурной части. Взаимодействие с инфраструктурной частью осуществляется через соответствующие интерфейсы, реализации которых определены в инфраструктурной части.
Файловая структура
Файловая структура доменной части обычно содержит следующие директории:
- constants - константы текущего модуля предметной области
- dto - классы DTO (data transfer object)
- enums - классы словарей, относящиеся к текущему модулю
- helpers - классы или чистые функции, реализующие переиспользуемый в других участках кода функционал
- interfaces - интерфейсы зависимостей (как правило, инфраструктурных), которые используются бизнес-логикой для взаимодействия с классами, реализующими данные интерфейсы
- models - модели предметной области. Представляют собой классы с набором полей, объявленных с помощью Fields декораторов
- services - классы, реализующие определенную бизнес-логику, экземпляры которых находятся в DI контейнере приложения. В данной директории, как правило, находятся CRUD-сервисы, реализующие базовые операции взаимодействия с моделью и наследованные от базового сервиса CrudService.
- validators - классы или функции, отвечающие за валидацию (см Валидация)
- usecases - классы юзкейсов
Юзкейсы (UseCases)
Юзкейс - класс, реализующий отдельный сценарий взаимодействия с системой (например, создать/отменить заказ, сменить пароль, отправить сообщение и т.д.). Данный класс, как правило, содержит один публичный метод вызова.
Юзкейсы могут содержать в своих зависимостях другие юзкейсы. Однако при проектировании бизнес-логики и юзкейсов следует тщательно избегать создания циклических зависимостей.
Инфраструктурная часть
В инфраструктурной части находятся сервисы, обеспечивающие взаимодействие приложения с "внешним миром": контроллеры для HTTP/WS-запросов и консольных команд, слушатели событий, сервисы интеграций со сторонними API, а также репозитории для работы с базой данных и файловой системой. Код из данной части может использовать код из доменной части напрямую, без использования интерфейсов.
Файловая структура
Файловая структура инфраструктурной части обычно содержит следующие директории:
- controllers - HTTP-контроллеры приложения
- decorators - декораторы
- guards - гарды, относящиеся к данному модулю
- migrations - классы миграций
- repositories - репозитории приложения. Как правило, это CRUD-репозитории реализующие базовые операции взаимодействия с моделью из домена и наследованные от базового сервиса CrudRepository.
- services - классы, реализующие инфраструктурную логику приложения (обращения к внешним источникам, использование внешних зависимостей и т.д.)
- subscribers - слушатели событий, генерируемых с помощью EventEmitter
- tables - классы сущностей, необходимые для работы ORM. Как правило, здесь находятся Entity классы для TypeORM