DDD-дублирование между уровнем сервиса и репозиториями

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

для большинства операций на уровне сервиса, похоже, что это прямое сопоставление с операциями CRUD, GetAll, GetById, Create, Delete и т. д.. поток архитектуры находится внутри этих строк: у меня есть контроллер вызов a слой сервиса что называет хранилище что называет ОРМ о бэкэнд ..

например GetAll будет существовать как в SL, так и в репозитории. Теперь, если у нас есть изменение/бизнес-требование, чтобы GetAll игнорировал определенные элементы, как я должен это делать, должен ли я игнорировать их в репозитории, или это бизнес-логика, которая должна идти на уровне сервиса? Разве жизнь не была бы проще, если бы мы просто был уровень обслуживания, вызывающий ORM напрямую?

Подводя итог: я понимаю, что уровень сервиса может абстрагировать логику некоторых пользователей, но когда - в большинстве случаев - он имеет дело с простыми операциями CRUD, не было бы проще просто избавиться от репозитория? Но, что, если SL и содержит некоторые методы со сложной бизнес-логикой, должны ли они проходить через репозиторий? С точки зрения хорошего дизайна, я должен поддерживать согласованность и всегда проходить через репозиторий или просто держите его простым и используйте репозиторий только тогда, когда это не простое сопоставление один к одному с операцией CRUD.

PS: Я понимаю, что есть внешне похожие вопросы, но не нашел удовлетворительного ответа

4 ответов


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

это не запах кода, так как они делают разные вещи.

вы должны иметь в виду, что домен или службы приложений находятся на другом уровне, чем реализации репозитория. Слои существуют по причине - объекты в разных слоях не совпадают ответственность и не разговаривать с теми же соседями. Реализации репозитория тесно связаны со средствами сохранения ваших объектов. Они могут генерировать операторы SQL и разговаривать с реляционной базой данных, они могут разговаривать с вашим ORM... важно то, что они знать о том, как объекты хранятся, что не относится приложений.

Если ваш уровень услуг должен был вызвать ORM напрямую, он действительно сделал бы 2 большие вещи, нарушение принципа единой ответственности. Также было бы сложнее изменить ваш ORM на другой или на другое средство настойчивости.

Так, например, GetAll будет существовать как в SL, так и в репозитории. Теперь, если у нас есть изменение / бизнес-требование, которое GetAll должен игнорировать некоторые пункты, как я должен это сделать, должен ли я игнорировать их в репозитория, или это бизнес-логика, которая должна идти в сервис Слой?

Если GetAll () игнорирует определенные элементы, я настоятельно рекомендую переименовать его как в сервисе, так и в репозитории, чтобы отразить это, например : GetAllAllowedToUser(), GetAllBut...(). Таким образом, контракт метода будет ясен, и вы избежите недоразумений относительно того, что он должен вернуть. Кроме того, вы сможете сохранить оригинальный подлинный метод GetAll (), который все еще может быть полезен.


в большинстве случаев-он имеет дело с простыми операциями CRUD, не так ли будет проще просто избавиться от репозитория

IMHO, я бы не сказал, чтобы избавиться от репозитория. Я бы сказал, что если вы делаете CRUD, вам не нужен DDD (вообще). Если Вы читаете корпоративные шаблоны Фаулера или Эванса, они оба говорят, что DDD используется только тогда, когда у вас есть логика домена, которая значительно сложна. CRUD не является сложным и поэтому не требуется DDD.

что вы описываете запах кода. Но я не думаю, что это запах с DDD. Вы просто видите перестроенный фрагмент кода.


+1 для Dtryon, также:

теперь, если у нас есть изменение / бизнес-требование, что GetAll должен игнорировать определенный элемент

не напрямую связано, и я знаю, что вы просто использовали его в качестве примера, но я видел эту точную вещь. Пожалуйста, не заканчивайте с методами, называемыми GetAll, которые не получают все. Сохранить способность, это способность, то есть GetAllLive, или GetAllAvailable или что-то вроде того, что что это


возможно, "шаблон Finder" (не знаю, правильный ли это термин) может решить вашу проблему. Согласно принципу CQS(Command-Query-Separation), (IMO,) операции запроса вообще не являются "бизнес-логикой". Мы можем написать некоторые конкретные "искатели" на уровне инфраструктуры для выполнения различных запросов и оставить все операции без запросов(бизнес-логика) на уровне сервиса, а затем на стороне клиента мы рассматриваем искатели так же, как и сервисы.
извините за мой язык :-(.