DDD — Как повторно использовать код на прикладном уровне?

#domain-driven-design

#дизайн, управляемый доменом

Вопрос:

Как повторно использовать код на прикладном уровне без сопоставления?

Давайте создадим службу приложений OrderService с методом AddOrder (OrderDto). Этот метод используется rest api. Метод контроллера вызывает OrderService.AddOrder(OrderDto) и сопоставляет параметр OrderDto с объектом Order. Затем объект Order добавляется в репозиторий. Сопоставление выполняется там, потому что OrderService и AddOrder — это интерфейс приложения.

Было бы неплохо повторно использовать код и вызвать OrderService.AddOrder(OrderDto) не только из контроллера, но и из другого метода в OrderService или даже из другой службы приложений.

Однако всегда требуется сопоставление объекта с DTO внутри метода службы приложений, прежде чем вызывать другой метод приложения, а затем отображать результат обратно из DTO в объект.

=> Бесполезное сопоставление на том же уровне. Когда система становится больше, она заканчивается отображением из и в DTO везде. ПЛОХО.

Было бы неплохо избежать сопоставления внутри и делать это только в верхней части интерфейса приложения. Мы могли бы написать службу, принимающую модель домена (сущность) вместо DTO в параметрах: OrderDomainService .AddOrder (порядок).

Это решает «проблему сопоставления». Службы домена могут вызывать друг друга без сопоставления, а службы приложений также могут вызывать службы домена. Однако это означает, что служба домена должна использовать репозиторий с уровня инфраструктуры для загрузки данных, потому что мы переместили код из метода службы приложений в метод службы домена. Это создает зависимость от уровня домена к уровню инфраструктуры.

=> Неправильная зависимость. Инфраструктура должна зависеть от домена, а не домена от внутренней структуры.

Как это решить?

Служба приложений не должна содержать методы с параметрами типов моделей предметной области. Служба домена не может использовать репозиторий.

Где тогда писать повторно используемый код?

Или я ошибаюсь, и служба домена может использовать репозиторий. Через интерфейс на уровне домена он не будет напрямую зависеть от уровня инфраструктуры. Однако тогда это приведет к тому, что метод контроллера вызовет метод службы приложений, вызывающий метод службы домена.

Ответ №1:

Я думаю, что вы на правильном пути, продвигаясь к доменным службам, когда дело доходит до повторного использования логики. Службы приложений подходят для организации конкретных вариантов использования и вызывают различные действия только в правильном порядке. Логика домена всегда должна быть на уровне домена.

Что касается зависимости от инфраструктуры: для использования репозиториев в DDD (или чистой архитектуре) интерфейсы репозитория должны находиться на уровне домена, в то время как конкретная реализация этих интерфейсов находится на уровне инфраструктуры.

Тогда и прикладной уровень, и уровень домена должны зависеть от интерфейсов, а не от уровня инфраструктуры.

Служба домена не может использовать репозиторий.

Таким образом, он может использовать репозиторий, будучи зависимым от интерфейса репозитория, в то время как конкретный репозиторий инфраструктуры вводится во время выполнения после внедрения зависимостей.

Однако тогда это приведет к тому, что метод контроллера вызовет метод службы приложений, вызывающий метод службы домена.

Если нет оправдания для службы приложений, поскольку не требуется реальной оркестровки, вы, по крайней мере, не нарушаете никаких правил зависимостей, позволяя контроллеру напрямую вызывать классы домена, например, если вариант использования слишком прост и не требуется абстракция между уровнем API (здесь контроллер) и уровнем домена. Но обычно мне больше нравится использовать службы приложений, поскольку они делают уровень домена независимым от этого внешнего уровня и позволяют как уровню домена, так и уровню API развиваться независимо друг от друга.

Комментарии:

1. Если служба домена может использовать код инфраструктуры (через интерфейс на уровне домена), чтобы он мог использовать репозитории, его можно использовать в качестве оркестратора вместо метода службы приложений. Это может работать так, что приложение может состоять в основном из кода в доменных службах, и если метод службы домена должен быть открыт из приложения, он может быть «обернут» методом службы приложений, содержащим код сопоставления. Это было бы здорово с практической точки зрения, но верно ли, что логика оркестровки будет находиться в методе службы домена, где должна быть бизнес-логика?

2. Как я уже говорил в своем ответе, службы приложений подходят для организации конкретных вариантов использования. Доменные службы и классы модели домена содержат логику бизнес-домена. Службы приложений организуют такие вещи, как сопоставление DTO (например, команд) с представлениями модели домена, извлечение объектов домена из репозиториев, вызов определенных (или более) методов для агрегатов или служб домена и повторное указание репозиторию сохранить измененный агрегат. Это не должно происходить в службе домена.

3. Для лучшего понимания служб приложений и служб домена вы можете ознакомиться с этим блогом: enterprisecraftsmanship.com/posts /.

4. Спасибо. Я прочитаю это, хотя у меня есть идея, как это работает. Мне интересно, как повторно использовать код службы приложений = код оркестровки и как избежать сопоставления объекта с dto и наоборот, когда методы службы приложений вызываются друг с другом, потому что, похоже, это полезно для выполнения на одном уровне. Разве это невозможно в DDD, если я не могу использовать службу домена?

5. DDD предоставляет только стратегические шаблоны (повсеместный язык, ограниченные контексты и т. Д.) И тактические шаблоны (агрегаты, репозитории, доменные службы и т. Д.), Которые вы можете применить, Если это соответствует вашим потребностям. Не существует правил, которые мешали бы вам организовать службы приложений таким образом, чтобы вы могли повторно использовать код. Я бы посоветовал вам реализовать это так, чтобы это наилучшим образом соответствовало вашим потребностям, в основном сосредоточившись на том, чтобы не вводить какие-либо прямые зависимости инфраструктуры в ваши сервисы.