DDD: Как организовать взаимодействие Enity и Repository
От: perekrestov Украина  
Дата: 17.11.10 14:00
Оценка:
Добрый день,

Возник вопрос о том, как Entity взаимодействуют с репозиториями.

Иногда, сложная бизнес логика требует взаимодействия с БД и "хитрой" выборкой данных.

Например, в конкретной сущности у меня есть метод DoSomethingComplex()

И в этом методе мне требуются дополнительные данные, которые не принадлежат текущей сущности.

Как организовать обращение Entity к репозиториям?

Стоит ли инжектить необходимые репозитории в Entity?

И стоит ли использовать, вообще, IoC относительно Entity?

Спасибо.
Re: DDD: Как организовать взаимодействие Enity и Repository
От: Sinix  
Дата: 17.11.10 15:13
Оценка:
Здравствуйте, perekrestov, Вы писали:

P>Добрый день,


P>Возник вопрос о том, как Entity взаимодействуют с репозиториями.

Как вам нравится На практике всё оперделяется задачей/типом приложения/используемыми средствами/религиозными предпочтениями разработчика. Например Эванс (при всём уважении к нему как к популяризатору DDD) — последовательно примазывался к яваистам, затем раскланивался с agile до такой степени, что окончательно опошлил светлые идеалы DDD, а щас агитирует за NoSQL. Евангелист, работа такая. Поэтому все заветы гурей(ов?) неплохо бы делить на 256.

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

Например, я очень люблю data-driven подход (хоть и несколько вынужденно: когда основная фича системы — согласованная работа с данными в весьма разных клиентах, по-другому не попляшешь) и проектирование от модели предметной области заказчика. Если щас появится ув gandjustas — он будет агитировать за более практично-приземлённый подход "делать щас что надо а там разберёмся" (я передёргиваю и вообще заведомо неправ ). Что нравится вам — то и выбирайте.

Как делаем мы — писал тут
Автор: Sinix
Дата: 10.02.09
(только этот конкретный пост, последующая простыня унылого флейма ничего ценного в себе не несёт).

P>Иногда, сложная бизнес логика требует взаимодействия с БД и "хитрой" выборкой данных.

P>Например, в конкретной сущности у меня есть метод DoSomethingComplex()

Я предпочитаю отделять мухи от котлет: модель данных — отдельно, поведение приложения — отдельно (в контроллерах). Соответственно, DoSomethingComplex() у меня жило бы в каком-нить ComplexController, который сам бы разруливал работу с данными в зависимости от бизнес-логики. Бонус — при изменении логики модель данных портить не надо

Да, в результате репозитария как такового нет
Re[2]: DDD: Как организовать взаимодействие Enity и Reposito
От: perekrestov Украина  
Дата: 17.11.10 16:02
Оценка: 9 (1)
Здравствуйте, Sinix, Вы писали:

P>>Иногда, сложная бизнес логика требует взаимодействия с БД и "хитрой" выборкой данных.

P>>Например, в конкретной сущности у меня есть метод DoSomethingComplex()

S>Я предпочитаю отделять мухи от котлет: модель данных — отдельно, поведение приложения — отдельно (в контроллерах). Соответственно, DoSomethingComplex() у меня жило бы в каком-нить ComplexController, который сам бы разруливал работу с данными в зависимости от бизнес-логики. Бонус — при изменении логики модель данных портить не надо


А это не приводит к анемичной модели со всеми вытикающими последствиями?


S>Да, в результате репозитария как такового нет
Re: DDD: Как организовать взаимодействие Enity и Repository
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 17.11.10 16:03
Оценка:
Здравствуйте, perekrestov, Вы писали:

P>Добрый день,


P>Возник вопрос о том, как Entity взаимодействуют с репозиториями.


P>Иногда, сложная бизнес логика требует взаимодействия с БД и "хитрой" выборкой данных.


P>Например, в конкретной сущности у меня есть метод DoSomethingComplex()


P>И в этом методе мне требуются дополнительные данные, которые не принадлежат текущей сущности.


P>Как организовать обращение Entity к репозиториям?


P>Стоит ли инжектить необходимые репозитории в Entity?


P>И стоит ли использовать, вообще, IoC относительно Entity?




Во расскажи для начала какие задачи решают твои entity и репозитарии?

По мне так вообще entity не нужны. В крайнем случае dto-подобные классы для переноса данных, остальное можно ридерами.
При наличии Linq, все еще проще: типизированныая модель данных создается автоматом, типизрованные проекции тоже есть.

Методы БЛ получают на вход ровно тот набор данных, который необходим. Репозитарии отдают данные из базы в ответ на некоторый query object.
Re[2]: DDD: Как организовать взаимодействие Enity и Reposito
От: perekrestov Украина  
Дата: 17.11.10 16:25
Оценка:
Здравствуйте, gandjustas, Вы писали:



G>Во расскажи для начала какие задачи решают твои entity и репозитарии?


Основная цель, которую я перед собой поставил — определить возможность хранения БЛ совместно с сущностями, за что и агитирует Эванс.
Проблема в том, что эта логика может требовать некоторой обработки данных, которые не всегда можно получить тривиальным способом.
Например, есть сущность Customer

Нам нужно определить является ли этот кастомер GoldCustomer.

(Опустим Specification Pattern, т.к. он проблемы в описываемом случае не решает.)

class Customer
{
public bool IsGoldCustomer(){
// Вот тут нам понадобятся данные за какаой-то период времени или что=-т подобное
// И очень вероятно, нам нужно будет обратиться в базу со сложным запросом
}
}


+ еще хочется реализовать это так, чтобы эту логику можно было тестировать. Другими словами, я хотелбы мочить (от слова mock) репозитории.

Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

Вопрос состоит в том, насколько "красивым"/"правилиным" является такое решение. У меня нет опыта написания приложений с использованием DDD, вот меня и интересует,

как поступают коллеги при решении описанной проблемы.
Re[3]: DDD: Как организовать взаимодействие Enity и Reposito
От: Sinix  
Дата: 17.11.10 16:34
Оценка: +1
Здравствуйте, perekrestov, Вы писали:

P>А это не приводит к анемичной модели со всеми вытикающими последствиями?

Озвучите последствия — озвучу как мы с ними боремся (или не боремся)

У нас модель данных отвечает за структуру и инварианты предметной области (разумеется речь не о всей модели, а об её представлении для конкретного клиента), контроллеры — за поведение приложения в соответствии с БЛ заказчика. Каждая часть решает свою задачу, смешивать их не хотим.
Re[4]: DDD: Как организовать взаимодействие Enity и Reposito
От: perekrestov Украина  
Дата: 17.11.10 17:00
Оценка: 9 (1)
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, perekrestov, Вы писали:


P>>А это не приводит к анемичной модели со всеми вытикающими последствиями?

S>Озвучите последствия — озвучу как мы с ними боремся (или не боремся)


Ну, о приимуществах/недостатках повторяться не хочется. Тут
Автор: GlebZ
Дата: 27.05.09
все хорошо обсудили

Могу, конечно, скопипастить с wiki

  • Logic cannot be implemented in a truly object-oriented way unless wrappers are used, which hide the anemic data structure.
  • Violation of the encapsulation and information hiding principles.
  • Necessitates a separate business layer to contain the logic otherwise located in a domain model. It also means that domain model's objects cannot guarantee their correctness at any moment, because
  • their validation and mutation logic is placed somewhere outside (most likely in multiple places).
  • Necessitates a global access to internals of shared business entities increasing coupling and fragility.
  • Facilitates code duplication among transactional scripts and similar use cases, reduces code reuse.
  • Necessitates a service layer when sharing domain logic across differing consumers of an object model.
  • Makes a model less expressive and harder to understand.

    Но, меня не сильно интересует вопрос Anemic vs Rich domain model.

    Меня интересует реализация. Как реализовать/спроектировать упомянутую мною проблему следуя DDD.

    S>У нас модель данных отвечает за структуру и инварианты предметной области (разумеется речь не о всей модели, а об её представлении для конкретного клиента), контроллеры — за поведение приложения в соответствии с БЛ заказчика. Каждая часть решает свою задачу, смешивать их не хотим.
  • Re[5]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Ziaw Россия  
    Дата: 17.11.10 17:47
    Оценка:
    Здравствуйте, perekrestov, Вы писали:

    P>Меня интересует реализация. Как реализовать/спроектировать упомянутую мною проблему следуя DDD.


    Следуя DDD ваша сущность должна включать в себя или иметь путь ко всем нужным для логики данным.

    Т.е. ей надо замапить ленивую коллекцию строк хитрой выборки.

    Впрочем это тоже не серебряная пуля, с таким подходом все равно рано или поздно понадобится прямой
    доступ к ORM из модели. Как вариант запоминать точку доступа в thread local контексте.
    Re[3]: DDD: Как организовать взаимодействие Enity и Reposito
    От: gandjustas Россия http://blog.gandjustas.ru/
    Дата: 17.11.10 18:44
    Оценка: +2
    Здравствуйте, perekrestov, Вы писали:

    P>Здравствуйте, gandjustas, Вы писали:




    G>>Во расскажи для начала какие задачи решают твои entity и репозитарии?


    P>Основная цель, которую я перед собой поставил — определить возможность хранения БЛ совместно с сущностями, за что и агитирует Эванс.

    Так не стоит делать. Эванс мягко говоря обманывает. Если посмотреть примеры приложений в стиле DDD, то там всегда существует некоторый слой, где данные отделены от методов.

    P>Проблема в том, что эта логика может требовать некоторой обработки данных, которые не всегда можно получить тривиальным способом.

    P>Например, есть сущность Customer

    P>Нам нужно определить является ли этот кастомер GoldCustomer.


    P>(Опустим Specification Pattern, т.к. он проблемы в описываемом случае не решает.)


    P>class Customer

    P>{
    P> public bool IsGoldCustomer(){
    P> // Вот тут нам понадобятся данные за какаой-то период времени или что=-т подобное
    P> // И очень вероятно, нам нужно будет обратиться в базу со сложным запросом
    P> }
    P>}

    А почему не
    public bool IsGoldCustomer(int customerId)

    ?

    иди даже получать статус кастомера при запросе его из базы.

    P>+ еще хочется реализовать это так, чтобы эту логику можно было тестировать. Другими словами, я хотелбы мочить (от слова mock) репозитории.

    Если у тебя репозиторий отдает IQueryable<T>, то тестируется он отлично.


    P>Вопрос состоит в том, насколько "красивым"/"правилиным" является такое решение. У меня нет опыта написания приложений с использованием DDD, вот меня и интересует, как поступают коллеги при решении описанной проблемы.


    "Красивость" и "правильность" это не те критерии, которыми стоит руководствоваться.
    Re[3]: DDD: Как организовать взаимодействие Enity и Reposito
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 17.11.10 21:13
    Оценка:
    Здравствуйте, perekrestov, Вы писали:

    P>Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

    По-простому конкретно в NHibernate вы можете пойти по относительно кривому пути rich model, то есть IsGoldCustomer сделать readonly-свойством и атрибутами попросить NHibernate заполнять его значение результатом соответствующего SQL-запроса (не HQL); разумеется, лениво. Но это не хорошо, так как если заказчик сам по себе не владеет информацией о том, золотой он или нет (на уровне определенных domain model, это не про жизнь, конечно), то этот метод не является областью его ответственности, соответственно, должно быть вне его.

    Инача, можно определять DAO-объекты в виде наследников общего интерфейса IDAO<T> (это вам поможет и с mock-ами, и с DI), содержащие кроме CRUID-операцией (обычно легко вынести в базовую типизированную реализацию DAO<T>: IDAO<T>). В конструктор соответствующего DAO-объекта передавать интерфейсным контрактом зависимые IDAO<T> (constructor injection, потом можно собирать IoC-контейнером), которые он будет использовать для выполнения комплексных запросов к хранилищу (кроме графа связанных объектов предметной области получится также граф связанных DAO-объектов). К примеру, CustomerDAO: IDAO<Customer> принимает в конструктор IDAO<CustomerHistoryDAO> и предоставляет методы вроде GetAllGoldCustomers() и IsGoldCutomer(Customer obj).
    Re[5]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Sinix  
    Дата: 18.11.10 01:26
    Оценка: 2 (1) +2 -1
    Здравствуйте, perekrestov, Вы писали:

    P>>>А это не приводит к анемичной модели со всеми вытикающими последствиями?

    S>>Озвучите последствия — озвучу как мы с ними боремся (или не боремся)
    P>Ну, о приимуществах/недостатках повторяться не хочется. Тут
    Автор: GlebZ
    Дата: 27.05.09
    все хорошо обсудили

    P>Могу, конечно, скопипастить с wiki
    А, абстрактные страшилки Не, с ними не боремся Большинство аргументов в списке из разряда "Дайте игрушку индусокодеру и он её сломает. Чугуний надёжней."

    Ну как, скажите мне, разделение кода по слоям может привести к "Facilitates code duplication among transactional scripts"? Рефакторинг не нужен(с)? Остальной бред комментировать не хоцца.


    P>Меня интересует реализация. Как реализовать/спроектировать упомянутую мною проблему следуя DDD.

    Так вы определитесь, какой DDD вам нужен Я про один DDD, Ziaw — про другой, он предлагает смешивать в модели и предметную область, и бизнес-логику. У всех личные тараканы в голове, у каждого приёма — тыщща толкователей.

    А на практике никто не оглядывается на паттерны, и делает так, как правильно/принято/удобно в текущих условиях, с существующей системой и с используемыми технологиями.

    P>Основная цель, которую я перед собой поставил — определить возможность хранения БЛ совместно с сущностями

    Зря. Цикл жизни данных на порядки больше, чем БЛ и для заказчика они куда важнее самой бесценной системы.
    Re[3]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Аноним  
    Дата: 18.11.10 11:32
    Оценка:
    Здравствуйте, perekrestov, Вы писали:

    P>class Customer

    P>{
    P> public bool IsGoldCustomer(){
    P> // Вот тут нам понадобятся данные за какаой-то период времени или что=-т подобное
    P> // И очень вероятно, нам нужно будет обратиться в базу со сложным запросом
    P> }
    P>}

    Я понимаю что это не общее, а частное решении для проблемы (а может и не решение вовсе).
    Что если сделать такой атрибут в бд (isGoldCustomer) и сделать шедулер который обновляет этот атрибут с заданной периодичностью.

    Выигрыш в производительности как бонус (допускаю что не очень ощутимый).
    Re[6]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Ziaw Россия  
    Дата: 18.11.10 12:20
    Оценка: +1
    Здравствуйте, Sinix, Вы писали:

    S>Так вы определитесь, какой DDD вам нужен Я про один DDD, Ziaw — про другой, он предлагает смешивать в модели и предметную область, и бизнес-логику. У всех личные тараканы в голове, у каждого приёма — тыщща толкователей.


    Не затруднит ли уважаемого дона привести примеры моих высказываний где я предлагаю смешивать все в модели?
    Re[7]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Sinix  
    Дата: 18.11.10 12:25
    Оценка:
    Здравствуйте, Ziaw, Вы писали:


    S>>Так вы определитесь, какой DDD вам нужен Я про один DDD, Ziaw — про другой, он предлагает смешивать в модели и предметную область, и бизнес-логику. У всех личные тараканы в голове, у каждого приёма — тыщща толкователей.


    Z> Не затруднит ли уважаемого дона привести примеры моих высказываний где я предлагаю смешивать все в модели?

    Затруднит С некоторой натяжкой вот это

    Следуя DDD ваша сущность должна включать в себя или иметь путь ко всем нужным для логики данным.

    можно трактовать как "структура модели данных должна определяться бизнес-логикой", но вы ведь не совсем это имели в виду.

    Ушёл усмирять тараканов
    Re[3]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Aviator  
    Дата: 18.11.10 14:42
    Оценка:
    Здравствуйте, perekrestov, Вы писали:

    P>Здравствуйте, gandjustas, Вы писали:




    G>>Во расскажи для начала какие задачи решают твои entity и репозитарии?


    P>Основная цель, которую я перед собой поставил — определить возможность хранения БЛ совместно с сущностями, за что и агитирует Эванс.

    P>Проблема в том, что эта логика может требовать некоторой обработки данных, которые не всегда можно получить тривиальным способом.
    P>Например, есть сущность Customer

    P>Нам нужно определить является ли этот кастомер GoldCustomer.


    P>(Опустим Specification Pattern, т.к. он проблемы в описываемом случае не решает.)


    P>class Customer

    P>{
    P> public bool IsGoldCustomer(){
    P> // Вот тут нам понадобятся данные за какаой-то период времени или что=-т подобное
    P> // И очень вероятно, нам нужно будет обратиться в базу со сложным запросом
    P> }
    P>}

    P>+ еще хочется реализовать это так, чтобы эту логику можно было тестировать. Другими словами, я хотелбы мочить (от слова mock) репозитории.


    Я бы сделал отдельную службу с методом IsGold(Customer customer). В доменные объекты помещаю только сравнительно простую логику, не требующую взаимодействия с внешним миром (БД, внешние службы...). Хотя в данной конкретной ситуации, почему бы не сделать такое поле в классе Customer (= таблице) и не обновлять при определённых условиях?

    P>Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

    Сурово

    P>Вопрос состоит в том, насколько "красивым"/"правилиным" является такое решение. У меня нет опыта написания приложений с использованием DDD, вот меня и интересует,

    Правильно то, что работает и потребляет допустимое условиями задачи количество ресурсов и время. Ну и поддержка не требует наличия группы из гуру программирования.
    Re[4]: DDD: Как организовать взаимодействие Enity и Reposito
    От: gandjustas Россия http://blog.gandjustas.ru/
    Дата: 18.11.10 14:58
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>Здравствуйте, perekrestov, Вы писали:


    P>>class Customer

    P>>{
    P>> public bool IsGoldCustomer(){
    P>> // Вот тут нам понадобятся данные за какаой-то период времени или что=-т подобное
    P>> // И очень вероятно, нам нужно будет обратиться в базу со сложным запросом
    P>> }
    P>>}

    А>Я понимаю что это не общее, а частное решении для проблемы (а может и не решение вовсе).

    А>Что если сделать такой атрибут в бд (isGoldCustomer) и сделать шедулер который обновляет этот атрибут с заданной периодичностью.

    А>Выигрыш в производительности как бонус (допускаю что не очень ощутимый).


    Обычно статус учитывается в момент покупки. Вот и делай обновление чтобы в момент покупки статус был актуален
    Re[4]: DDD: Как организовать взаимодействие Enity и Reposito
    От: perekrestov Украина  
    Дата: 18.11.10 15:43
    Оценка:
    Здравствуйте, Aviator, Вы писали:


    A>Я бы сделал отдельную службу с методом IsGold(Customer customer). В доменные объекты помещаю только сравнительно простую логику, не требующую взаимодействия с внешним миром (БД, внешние службы...). Хотя в данной конкретной ситуации, почему бы не сделать такое поле в классе Customer (= таблице) и не обновлять при определённых условиях?


    P>>Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

    A>Сурово
    Тут проблема не в самом методе. Если я не ошибаюсь, для таких вещей Эванс рекомендует использовать Specification pattern

    Я хотел показать следущее. Вот если Entity понадобится взаимодействовать с упомянутым вами сервисом.

    Тогда как эта сущность должна получать на него ссылку?

    Например, при покупке товара ГолдКастомером ему начисляется скидка, бонусы или что-то в этом роде.


    Customer customer;
    // тут получили ссылку на него каким-то образом.
    
    Product p;
    // получили ссылку на товар
    
    customer.Buy(p);


    (пример с покупкой я вытянул с головы).

    У меня сложилось такое ощущение, что многие пытаются выносить более-мение сложную логику в бизнес сервисы из сущностей, т.к.
    Но ведь это приводит к анимичной модели... А хочется все-таки понять как добиться на практике того, о чем говорит Эванс.

    Customer customer;
    // тут получили ссылку на него каким-то образом.
    
    Product p;
    // получили ссылку на товар
    
    PaymentService ps = serviceLocator.Resolve<IPaymentService>();
    
    ps.BuyProduct(customer, p);



    P>>Вопрос состоит в том, насколько "красивым"/"правилиным" является такое решение. У меня нет опыта написания приложений с использованием DDD, вот меня и интересует,

    A>Правильно то, что работает и потребляет допустимое условиями задачи количество ресурсов и время. Ну и поддержка не требует наличия группы из гуру программирования.
    Re[4]: DDD: Как организовать взаимодействие Enity и Reposito
    От: perekrestov Украина  
    Дата: 20.11.10 21:23
    Оценка:
    Здравствуйте, Aviator, Вы писали:


    P>>Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

    A>Сурово
    Вроде как нормально

    Domain Driven Design and Development In Practice

    Dependency Injection

    DI is a great way to move the configuration and dependency code out of the domain objects. Also, the design dependency of domain classes on Data Access Object (DAO) classes and service classes on domain classes makes DI a "must have" in DDD implementation. DI facilitates a cleaner and loosely coupled design by injecting the other objects such as Repositories and Services into Domain Objects.

    In the sample application, the service object (FundingServiceImpl) uses DI to inject the Entity objects (Loan, Borrower and FundingRequest). Also, Entities reference Repositories via DI. Similarly, other Java EE resources like DataSource, Hibernate Session Factory and Transaction Manager are injected into Service and Repository objects.

    ddd
    Re[5]: DDD: Как организовать взаимодействие Enity и Reposito
    От: gandjustas Россия http://blog.gandjustas.ru/
    Дата: 20.11.10 22:27
    Оценка:
    Здравствуйте, perekrestov, Вы писали:

    P>>>Я понимаю, что это решается через DI. И, например, если я использую NHibernate я могу инъектить зависомости во время дегидрации используя интерсепторы.

    A>>Сурово
    P>Тут проблема не в самом методе. Если я не ошибаюсь, для таких вещей Эванс рекомендует использовать Specification pattern

    Интереснее всего читать самое начало эванса http://domaindrivendesign.org/sites/default/files/books/chapter01.pdf

    1)Не указаны задачи, решаемые создаваемой программой
    2)Не указано почему сначала создавалась именно структура, а потом функции
    3)Не понятно почему модель предметной области 1-в-1 была отображена на классы с "поведением"

    Все эти фундаментальные для программы решения никак не обоснованы эвансом.
    Re[6]: DDD: Как организовать взаимодействие Enity и Reposito
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 20.11.10 23:46
    Оценка:
    Здравствуйте, gandjustas, Вы писали:

    G>1)Не указаны задачи, решаемые создаваемой программой


    Вообще то ответ на это есть в книге в той самой первой главе.

    G>2)Не указано почему сначала создавалась именно структура, а потом функции


    И структура и функции. Структура важнее, потому что для описания функции нужны уже конкретные термины.

    Функционалисты постоянно про это забывают. Для общеупотребительных случаев функциональный дизайн делается легко и просто. А вот когда область нужно раскапывать, то до функций еще дойти надо.

    G>3)Не понятно почему модель предметной области 1-в-1 была отображена на классы с "поведением"


    Не ясно, что ты имел ввиду.
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.