Здравствуйте, TG, Вы писали:
TG>А в каких случаях надо абстрагироваться от способа получения данных? И зачем?
Когда работаешь с несколькими источниками однотипных данных, которые могут отличаться как по протоколу, так и по схеме данных. Интерфейс у репозитория описывается в терминах домена, реализация для каждого источника своя.
Здравствуйте, Miroff, Вы писали:
M>Дизайн строится не от данных, а от от операций.
Это интересно. Давайте построим дизайн от операций. M>Если у тебя не получается логично присунуть метод, значит ты что-то сделал не так.
M>Давай разберем что. В ДДД принято идти от предметной области, а в предметной области нет никаких ER, а есть единица товара, у которой есть SKU, физическая локация (на главном склад, у перевозчика, у покупателя и т.п.) и обязательства (вернуть постащику, сжечь, поставить покупателю и т.п.) И когда ты такую модель строишь у тебя логичным образом возникает поединичный учет и резервирование товара логично превращается в метод sku_item.createObligation(Supplybbligation(Order))
M>ER модель при этом будет выглядеть так
M>СКУ, Единица товара, Склад, обязательство, заказ
M>Связи: M>СКУ — единица товара (один-ко-многим) M>обязательство — единица товара (один-ко-многим) M>заказ — обязательство (один-ко-многим) M>СКУ — склад (многие-к-одному)
Непонятно. Какие атрибуты будут у этих сущностей? Как устроен метод sku_item.createObligation(Supplybbligation(Order))?
Почему метод вы написали так, а не SupplyObligation.create(sku_item, Order), и не Order.createSupplyObligation(sku_item)?
Как мне гарантировать атомарность резервирования товаров в заказе — либо весь заказ, либо ничего?
M>При этом логичным образом решаются и другие задачи, вроде "посчитать себестоимость хранения товара на складе" или "посчитать ущерб от уничтоженного товара находившегося на сгоревшем складе"
Давайте пока с простым разберемся. А потом попробуем придумать, к какому из классов приделать упомянутые вами методы.
S>>Что такое "проекции друг на друга"? Расскажите подробнее.
M>Это из функционального программирование пришло. В данном случае это обратимое преобразование F(Товар, Склад, Заказ) -> (Товар, Остаток, Резерв)
По-прежнему ничего не понятно. Кто тут на кого проецируется? Я в функциональном программировании термина "проекция" не встречал. Если он общепринятый — киньте ссылку на первоисточник, если ваш — распишите подробнее. M>Ты можешь рассматривать проекции как DB view только не с точки зрения БД, а с точки зрения классов.
Непонятно. В DB View не ограничены проекциями (в терминах реляционной алгебры).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
M>>Давай разберем что. В ДДД принято идти от предметной области, а в предметной области нет никаких ER, а есть единица товара, у которой есть SKU, физическая локация (на главном склад, у перевозчика, у покупателя и т.п.) и обязательства (вернуть постащику, сжечь, поставить покупателю и т.п.) И когда ты такую модель строишь у тебя логичным образом возникает поединичный учет и резервирование товара логично превращается в метод sku_item.createObligation(Supplybbligation(Order))
M>>ER модель при этом будет выглядеть так
M>>СКУ, Единица товара, Склад, обязательство, заказ
M>>Связи: M>>СКУ — единица товара (один-ко-многим) M>>обязательство — единица товара (один-ко-многим) M>>заказ — обязательство (один-ко-многим) M>>СКУ — склад (многие-к-одному)
S>Непонятно. Какие атрибуты будут у этих сущностей?
Релевантных для задачи никаких.
S>Как устроен метод sku_item.createObligation(Supplybbligation(Order))?
Как реализуешь, так и будет устроен. Может он записи в БД создает, может API вызывает, может в файл складывает.
S>Почему метод вы написали так, а не SupplyObligation.create(sku_item, Order), и не Order.createSupplyObligation(sku_item)?
Потому что логика предметной области требует писать именно так. Обязательство это свойство единицы товара, а не самостоятельная сущность и тем более не свойство заказа. Вся идея ДДД состоит в том, что архитектура должна проистекать из домена, а не из представления архитектора о прекрасном.
S>Как мне гарантировать атомарность резервирования товаров в заказе — либо весь заказ, либо ничего?
Как тебе угодно: транзакциями, блокировами, многофазными коммитами, вручную, автоматически или через аспекты. Физическая реализация ортогональна дизайну.
Что важно, это задуматься действительно ли атомарность нужна по предметной области или это очередная выдуманная хотелка потому что все так делают? В предметной области такого требования может вообще не существовать. Допустим, ты покупаешь пакетный тур и туроператор бронирует для тебя перелет, отель и дайвинг курс. В реальности, на любом этапе ЖЦ заказа может произойти факап: рейс отменят, отель сгорит, дайв-центр потеряет аккредитацию PADI и в заказ придется вносить изменения. В том числе и порождающие финансовые транзакции в произвольном направлении.
S>По-прежнему ничего не понятно. Кто тут на кого проецируется? Я в функциональном программировании термина "проекция" не встречал. Если он общепринятый — киньте ссылку на первоисточник, если ваш — распишите подробнее.
Представь, что у тебя есть вьюха из нескольких таблиц. В классических СУБД она доступна только для чтения. А теперь представь, что ты можешь делать в нее INSERT или UPDATE и эта команда автоматически приведет к изменению исходных таблиц. Дальше представь, что это вьюха маппится на какую-то entity в коде и эта entity ведет себя неотличима от всех остальных маппингов. Вот это и есть проекция. Детали реализации могут быть совершенно любыми, от вьюх и хранимых процедур на уровне БД, до полной иммутабельности на эффектах и соответствующих монадах.
Здравствуйте, Miroff, Вы писали:
M>Релевантных для задачи никаких.
Это понятно, просто их описание лучше помогло бы мне понять, какая у них семантика.
S>>Как устроен метод sku_item.createObligation(Supplybbligation(Order))? M>Как реализуешь, так и будет устроен. Может он записи в БД создает, может API вызывает, может в файл складывает.
Это не ответ, а уход от ответа. Очень многие "архитектуры" спотыкаются ровно на том, что при реализации получается чушь, хотя картинка исходно была красивая.
S>>Почему метод вы написали так, а не SupplyObligation.create(sku_item, Order), и не Order.createSupplyObligation(sku_item)? M>Потому что логика предметной области требует писать именно так. Обязательство это свойство единицы товара, а не самостоятельная сущность и тем более не свойство заказа.
Вот это нужно как-то обосновывать. Потому, что связи не являются "свойствами" в каком-то объективном смысле — они не "принадлежат" сущности.
Вот у нас есть отдел, есть его начальник. "Руководить" — это связь между отделом и сотрудником; она является "свойством" сотрудника в той же степени, что и отдела.
Поэтому и непонятно, отчего вы решили, что обязательство — это "свойство" единицы товара, что бы понятие "единица товара" ни означало.
M>Вся идея ДДД состоит в том, что архитектура должна проистекать из домена, а не из представления архитектора о прекрасном.
Это понятно. Непонятно, почему вы "поведение" приписываете каким-то конкретным концептам из вашего "домена".
В домене "торговля товаром" обязательство является свойством контрагента, а не какого-то конкретного товара. Это не товар "перемещается" от поставщика к получателю, это кто-то, обладающий свободой воли, перемещает товар.
S>>Как мне гарантировать атомарность резервирования товаров в заказе — либо весь заказ, либо ничего? M>Как тебе угодно: транзакциями, блокировами, многофазными коммитами, вручную, автоматически или через аспекты. Физическая реализация ортогональна дизайну.
Так не бывает. Дизайн очень сильно влияет на реализацию, ни о какой ортогональности речь идти не может.
M>Что важно, это задуматься действительно ли атомарность нужна по предметной области или это очередная выдуманная хотелка потому что все так делают?
Можно и задуматься, хотя в контексте этого разговора это оффтоп. Оффтоп потому, что предметная область существует объективно. Да, на этапе анализа иКмеет смысл уточнять требования — совершенно необязательно автоматизировать неэффективный процесс, можно сначала его перепроектировать, а уже потом воплощать в коде.
Но рано или поздно мы приходим к тому, что есть некоторые требования. Реализация не должна диктовать требования архитектуре, а архитектура — бизнесу.
Нам нужна такая методология, которая позволяет проектировать архитектуру так, чтобы она одновременно удовлетворяла бизнес-требованиям и позволяла эффективную реализацию.
А не так, что мы делаем архитектуру для "а давайте мы изменим постановку задачи", и потом "наша ортогональная реализация работает за O(N^3), хотя у конкурентов O(logN)".
M>Представь, что у тебя есть вьюха из нескольких таблиц. В классических СУБД она доступна только для чтения. А теперь представь, что ты можешь делать в нее INSERT или UPDATE и эта команда автоматически приведет к изменению исходных таблиц. Дальше представь, что это вьюха маппится на какую-то entity в коде и эта entity ведет себя неотличима от всех остальных маппингов. Вот это и есть проекция. Детали реализации могут быть совершенно любыми, от вьюх и хранимых процедур на уровне БД, до полной иммутабельности на эффектах и соответствующих монадах.
Нет, это не проекция. То, что вы описываете — это REST-идеология, когда все сценарии выражаются в терминах CRUD-операций. Но она сама по себе работает только тогда, когда у нас нет никакого "поведения" за пределами этих модификаций. Вот я взял и добавил связь между сотрудником и департаментом — и это привело к определённому результату, независимо от того, оформил ли я это через department.Employees += e или через e.Deparment = department. А может, так вообще нельзя, и нужно создать экземпляр EmployeeContractAddendum, который после подписания обеими сторонами автоматически отразит изменения штатного расписания департамента и должности у сотрудника.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, amironov79, Вы писали:
TG>>А в каких случаях надо абстрагироваться от способа получения данных? И зачем? A>Когда работаешь с несколькими источниками однотипных данных, которые могут отличаться как по протоколу, так и по схеме данных. Интерфейс у репозитория описывается в терминах домена, реализация для каждого источника своя.
Так полного абстрагирования не получится.
Детали реализации доступа к источнику все равно понадобятся для реагирования на ошибки, например.
И невозможно будет делать транзакционно некоторые группы операций.