Песочница для проверки различных гипотез в области организации структуры проекта.
Требования:
- приложение - коноль, несколько методов для чтения и записи данных
- данные модели хранятся удалённо, чтение и запись API / gRPC
Легенда. Виртуальная книжная полка, основные действия:
- загрузить на полку книгу (книги хранятся в удалённом репозитории, доступ через API)
- получить книгу с полки
- у книги есть Автор, связь один к одному (данные хранятся в локальном репозитории)
Структура:
- presentation Точка входа (Input/Output): API / CLI / gRPC / etc Собственно на этом уровне и живут http/cli framework, обязанность которых получить набор аргументов, минимально обработать согласно с общепринятой логикой и передать на следующий уровень - приложение (application).
- application Слой первичной валидации и подготовки конечного ответа. Получаем очищенные данные, с точки зрения типа и структуры данных, переводим данные в абстракции нашего домена, и через интерфейсы работаем с данными, согласно бизнес логике и при помощи infrastructure layer.
- domain Основная бизнес логика.
- infrastructure Код организующий связь между доменом и инфраструкторой. Следим чтобы сюда не просачивалась бизнес логика нашего домена. Здесь в основном работаем с внешними системами - базы данных, кеши, внешние ресурсы, шины данных и прочее.
- Где создавать агрегаты, как организовать связи между доменными моделями - в доменном сервисе или на уровне приложения? В настоящий момент склоняюсь к тому что Interactor на уровне application, а Aggregat на уровне domain.
- Правильно ли изолировать domain сервисы от репозиториев? Допускаю, что при сложной логике приложения не удасться избежать связи доменного сервиса и infrastructure.
- Где хранить вспомогательные классы - tools, например генератор UUID?
- Есть варианты когда даже на DTO заводят интерфейсы - на мой взгляд абсолютно бесмысленное занятие - DTO сама хорошо себя описывает, а иммутабельность защита от магии. Защиты от изменения кода, не может гарантировать и интерфейс.
- domain ничего не знает об application и не зависим от внешних библиотек, что отлично инкапсулирует логику от окружения;
- infrastructure так же в достаточной степени изолирована от application, через интерфейсы;
- framework agnostic
- достаточно легко написать тесты к любому слою приложения;
docker pull ghcr.io/kuaukutsu/php:8.3-cliContainer:
ghcr.io/kuaukutsu/php:${PHP_VERSION}-cli(default)jakzal/phpqa:php${PHP_VERSION}
make setupmake run-bookmake run-book-findmake run-authormake run-author-createThe code is statically analyzed with Psalm. To run static analysis:
make psalmmake phpstanmake checkmake phpcsmake rectorThe package is tested with PHPUnit. To run tests:
make phpunitphpunit, чтобы перейти на 11 версию, нужно отказываться от psalm, который цепляется за четвертую версию парсера от Никиты Попова (https://github.com/nikic/PHP-Parser). Плавно переезжаем на phpstan?.