Ответ
В чистой архитектуре микросервисов зависимости строятся по принципу «зависимости направлены внутрь» (Dependency Inward Rule). Это означает:
Направление зависимостей:
Инфраструктурный слой → Слой приложения → Доменный слой
(внешний) (промежуточный) (внутренний)
↑ ↑ ↑
Зависит от Зависит от НЕ зависит ни от кого
Конкретные примеры для PHP-микросервиса:
-
Доменный слой (Domain Layer) – содержит бизнес-сущности и правила:
// Order.php - сущность class Order { private string $id; private float $total; private OrderStatus $status; public function markAsPaid(): void { $this->status = OrderStatus::PAID; } } -
Слой приложения (Application Layer) – содержит use cases:
// PayOrderHandler.php class PayOrderHandler { public function __construct( private OrderRepositoryInterface $repository ) {} public function handle(PayOrderCommand $command): void { $order = $this->repository->find($command->orderId); $order->markAsPaid(); $this->repository->save($order); } } -
Инфраструктурный слой (Infrastructure Layer) – реализует интерфейсы:
// DoctrineOrderRepository.php class DoctrineOrderRepository implements OrderRepositoryInterface { public function __construct(private EntityManagerInterface $em) {} public function find(string $id): ?Order { return $this->em->find(Order::class, $id); } }
Почему это важно:
- Доменный слой не зависит от фреймворков, БД или внешних сервисов – его можно тестировать изолированно
- Легко менять инфраструктуру – заменить Doctrine на Eloquent, REST на GraphQL, не затрагивая бизнес-логику
- Четкое разделение ответственности – каждый слой решает свою задачу
В микросервисной архитектуре этот принцип особенно критичен, так как позволяет независимо развивать и масштабировать отдельные сервисы.
Ответ 18+ 🔞
Слушай, а вот это реально важная штука, про которую половина народа нихуя не помнит, пока в проект не вляпается. Чистая архитектура в микросервисах — это как раз тот случай, когда если накосячить с зависимостями, потом будешь ебаться с этим кодом, как дурень с писаной торбой.
Представь себе такую слоёную конструкцию, как торт «Птичье молоко». Только перевёрнутую. Главное правило — «зависимости смотрят внутрь». То есть, самый сок, ядро — это доменный слой. Он, блядь, неприкасаемый, как икона. Он нихуя не знает ни про какую базу данных, ни про какой HTTP, ни про какой фреймворк. Он просто содержит бизнес-правила, и всё. Это святое.
Дальше идёт слой приложения — это уже use cases, хендлеры команд, вся эта движуха. Он зависит от доменного слоя, потому что использует его сущности. Это логично, ёпта.
А самый внешний, инфраструктурный слой — это уже всякая техническая хуйня: работа с БД, отправка запросов куда-то, консольные команды. Этот слой зависит от слоя приложения, реализуя его интерфейсы. Получается такая матрёшка, где все зависимости заглядывают внутрь, к ядру, а не наоборот.
Вот смотри на примере, чтобы не было, как у мартышлюшки, всё в одну кучу:
-
Доменный слой (ядро, него никто не трогает): Тут живут твои бизнес-сущности. Просто классы с данными и логикой. Никаких
EntityManagerилиRequestтут, блядь, быть не должно. Чистая правда.// Order.php - вот она, священная корова class Order { private string $id; private float $total; private OrderStatus $status; // Вот она, бизнес-логика. "Пометить как оплаченный". Больше ничего. public function markAsPaid(): void { $this->status = OrderStatus::PAID; } } -
Слой приложения (промежуточный, использует ядро): Тут живут сценарии использования. Например, «оплатить заказ». Он знает про репозиторий (интерфейс!), чтобы достать заказ, и вызывает у него метод из домена.
// PayOrderHandler.php class PayOrderHandler { // Видишь? Не конкретная реализация, а интерфейс! Это ключ, ёпта! public function __construct( private OrderRepositoryInterface $repository ) {} public function handle(PayOrderCommand $command): void { // Достаём сущность из ядра $order = $this->repository->find($command->orderId); // Вызываем метод из ядра $order->markAsPaid(); // Говорим репозиторию сохранить изменения $this->repository->save($order); } } -
Инфраструктурный слой (внешний, реализует интерфейсы приложения): А вот тут уже живёт вся грязь реального мира. Допустим, репозиторий на Doctrine. Он реализует тот самый
OrderRepositoryInterface, который ждал хендлер. Он зависит от слоя приложения (от его интерфейса), а не наоборот!// DoctrineOrderRepository.php class DoctrineOrderRepository implements OrderRepositoryInterface { // А вот тут уже можно и EntityManager, это его дом public function __construct(private EntityManagerInterface $em) {} // Реализуем метод из интерфейса, используя Doctrine public function find(string $id): ?Order { return $this->em->find(Order::class, $id); } }
А нахуя это всё, спросишь? Да затем, чувак, чтобы не охуеть потом!
- Домен независим. Его можно тестировать в полной изоляции, без поднятия базы и прочей ерунды. Просто создал объект и проверил логику. Красота.
- Инфраструктуру — налево и направо. Надоел тебе Doctrine, который жрёт память, как не в себя? Хочешь на Eloquent переехать или вообще на чистый PDO? Без проблем! Пишешь новую реализацию
OrderRepositoryInterface, меняешь строчку в конфиге контейнера — и всё, остальной код, включая всю бизнес-логику, даже не чихнул. Это и есть доверия ебать ноль к внешним штукам, и это правильно. - Всё на своих местах. Не будет у тебя в сущности
OrderметодаsaveToDatabase(). Это же пиздец, прости господи. Каждая сущность знает своё место.
В микросервисах это вообще архиважно. Один сервис можно переписать на другом фреймворке, поменять базу данных — и если ты не накосячил с архитектурой, то ядро, сама бизнес-логика, останется нетронутой. Иначе будешь потом, как полупидор, ползать по всему коду и выковыривать зависимости. Не доводи до этого, делай сразу по-человечески.