Продвигает ли «Инверсия контроля» «Модель анемичного домена»?

32

Когда я использовал IoC Container в моем последнем проекте, я получил анемичные сущности и большую часть своей бизнес-логики в сервисах без сохранения состояния.

Я видел проекты, написанные другими разработчиками, которые используют «Inversion of Control», и они всегда «анемичны».

Поскольку «Модель анемичного домена» является анти-шаблонной, возможно ли использовать IoC и Rich Domain? Есть ли у них хорошие примеры, проекты с открытым исходным кодом, которые делают это?

Mag20
источник
Я думаю, что нам нужно увидеть некоторые конкретные примеры вашего конкретного случая, чтобы помочь.
Мартейн Вербург
1
Извините, я имел в виду фрагменты кода :)
Martijn Verburg

Ответы:

11

Для начала: DI и IoC не являются синонимами. Извините, но я должен указать на это (мне кажется, вы так думаете).

Что касается вашего запроса ... Ну, Dependency Injection - это всего лишь инструмент. То, как вы собираетесь использовать этот инструмент, совершенно отдельная вещь. Есть и другие инструменты (шаблоны проектирования), которые могут усугубить проблему. Например, я считаю, что широкое внедрение шаблона MVC является одним из ключевых компонентов формирования анти-шаблона Anemic Domain Model: контроллеры (в более простых приложениях, в более сложных, которые могут быть дополнительными уровнями обслуживания) берут на себя ответственность за проверку бизнес-правил усиливая их, а также превращая сущности БД во что-то полезное, тогда как бизнес-уровень превращается в простой уровень доступа к данным, который представляет собой простой ORM с однозначным сопоставлением сущностей базы данных.

Конечно, именно так вы разрабатываете свое приложение - вы можете создать правильную модель предметной области, если хотите, и все эти IoC, DI, MVC не останавливают вас. Что может остановить тебя, так это твоя команда. Вам как-то нужно убедить их использовать правильный путь, и это может быть сложно, так как многие разработчики программного обеспечения не имеют достаточного архитектурного опыта.

Павел Дида
источник
Я добавлю к этому, что, возможно, вы могли бы взглянуть на подход DDD, поддерживаемый Эриком Эвансом и соавторами.
Мартейн Вербург
1
Я прочитал книгу Эрика Эванса. Это хорошо для общей методологии и вездесущего языка, но несколько не хватает реальных примеров.
Mag20
Спасибо за указание на разницу между DI и IoC. Я думаю, что проблема была больше связана с IoC, чем с DI. Изменен вопрос, чтобы отразить это.
Mag20
В моем опыте с рамками DI / контейнеров (Spring DI, CDI, Unity), они действительно ли остановить вас от создания «правильной модели предметной области», который для меня означает , что разработчики не должны быть ограничены с использованием истинных (т.е. с сохранением состояния) объектов , Но я действительно не поддерживаю это.
Rogério
8

Большинство (если не все) приложения представляют собой сочетание инфраструктуры и проблем домена. Когда вы достигнете определенного уровня сложности, вам будет легче управлять, если домен будет отделен от инфраструктуры, чтобы его было легче рассуждать и развиваться независимо.

Конечно, модель домена все еще должна взаимодействовать с остальной частью системы, и обычно это происходит со службами без сохранения состояния (которые являются частью домена), в которые встраиваются проблемы инфраструктуры (например, доступ к базе данных). Использование контейнера IoC не удаляет эту зависимость, он перемещает свою конфигурацию в отдельную область, что снова упрощает анализ и поддержку.

Объекты хранят состояние и должны нести ответственность за бизнес-правила. Если ваши службы применяют все инварианты и другие бизнес-правила, вероятно, логика не в том месте.

Теперь, если вы располагаете логикой в ​​нужных местах и ​​при этом по-прежнему получаете сервисы, которые являются не более чем обертками вокруг объектов инфраструктуры и сущностей, которые являются просто пакетами свойств, тогда весьма вероятно, что домен не достаточно сложен, чтобы оправдать накладные расходы на собственную модель. Почти все, что вы прочтете о DDD, будет содержать заявление об отказе от ответственности, которое на самом деле предназначено только для сложных доменов, но об этом слишком часто забывают.

FinnNk
источник
7

Перейти к источнику. Начните с статьи Фаулера о моделях анемичных доменов . Он ссылается на управляемый доменом дизайн Эрика Эвана как пример хорошей практики. Исходный код для этого здесь . Загрузить.

Обратите внимание, что он использует Inversion of Control (поиск по @Autowired), имеет классы обслуживания (BookingService) и классы «бизнес-процессов» (например, ItineraryUpdater).

Оригинальная статья Фаулера начинается с примера, который вы ищете.

Джей
источник
Это пример приложения, на самом деле, не соответствует DDD, как описано в книге. Конкретное противоречие с книгой состоит в том, что она полностью нарушает концепцию «инфраструктуры», позволяя ей содержать специфичный для предметного кода код; например, VoyageRepositoryHibernateкласс, который был помещен в уровень инфраструктуры, но на самом деле зависит от уровня домена.
Rogério
Да, в книге говорится на странице 73, что уровень инфраструктуры находится «ниже» уровня домена и «он не должен иметь специальных знаний о домене, который он обслуживает». Это просто никогда не имело смысла для меня. Рассмотрим проект, который имеет две реализации VoyageRepository: VoyageRepositoryHibernate и класс VoyageRepositoryJDBC. Их реализации обязательно сильно различаются и зависят от технологии. Они принадлежат на уровне домена? Или уровень инфраструктуры? В нашем коде, согласно книге, мы делаем это в обратном направлении: уровень инфраструктуры может ссылаться на уровень домена, но не наоборот.
Джейми
Они принадлежат на уровне домена, да. Реализация на основе JDBC будет содержать код SQL, привязанный к таблицам и столбцам в базе данных приложения, которые относятся к конкретному домену. Помещать любой код домена или приложения на уровне инфраструктуры просто неправильно, так как «код инфраструктуры» должен использоваться только для решения технических проблем и должен (в идеале) быть полностью повторно используемым между различными приложениями и доменами. Решение иметь «низкоуровневый» код (например, SQL) на уровне домена состоит не в том, чтобы полностью его удалить, а в том, чтобы реализовать его поверх лучшей инфраструктуры, такой как ORM.
Рожерио
Для меня реализация save (MyDomainObject foo) является чисто технической задачей. YMMV.
Джейми
Только если это не приведет к нарушению основного правила многоуровневой архитектуры: нижний уровень не может зависеть от более высокого уровня. Таким образом, если вы реализовали save(foo)код, который может изменяться при изменении модели домена (например, если в него добавлен новый атрибут MyDomainObject), то он должен (по определению) принадлежать слою домена; в противном случае вы просто не можете больше говорить о наличии «слоев».
Rogério
7

Можно ли использовать IoC и Rich Domain? Есть ли у них хорошие примеры, проекты с открытым исходным кодом, которые делают это?

Я предполагаю, что вы имеете в виду DI вместо IoC, а в проекте, над которым вы работали, используется контейнер DI, такой как Spring. IoC имеет два основных варианта: шаблон DI и шаблон Locator. Я не понимаю, почему шаблон локатора должен быть проблемой, поэтому давайте сосредоточимся на DI.

Я не думаю, что это возможно, или, по крайней мере, было бы очень непрактично. Основной аспект DI-контейнеров заключается в том, что они контролируют создание объектов, когда они внедряют их в другие («управляемые объекты»). Набор управляемых объектов, который действует во время выполнения проектов, не зависит от того, какие элементы домена существуют в вашем проекте, но зависит от того, как объекты связаны, и какие области (синглтон, прототип) назначены им.

Вот почему вы не хотите, чтобы DI-контейнер управлял вашими объектами домена. Но если вы создаете объекты вручную (с помощью new), вы не можете добавить другие объекты к объектам вашего домена. (Оставляя в стороне потенциальные обходные пути с ручным подключением.) Поскольку эти внедрения необходимы для замены реализаций другими, вы не можете заменить функциональность объектов расширенного домена с помощью DI. Следовательно, вы не захотите размещать функциональность в доменных объектах, иначе вы потеряете функции DI.

Я не понимаю, как может работать гипотетический DI-контейнер, который не управляет вашими объектами, и ни одна из существующих реализаций не позволяет этого. Поэтому справедливо утверждать, что DI полагается на управление объектами. Поэтому он всегда будет искушать вас разделить потенциальные объекты Rich Domain на один анемичный класс и один или несколько классов сценариев транзакций.

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