Здравствуйте, Miroff, Вы писали:
M>Здесь нет связей, здесь есть именно свойства сущностей.
Непонятно. Сущность не может быть свойством другой сущности.
M>Это не связь, а совершенно отдельный доменный объект — "роль". У сотрудника может быть много ролей в одном отделе, эти роли могут пересекаться или активироваться по каким-то особым критериям. Вплоть до того, что роль может быть вакантной.
Этот объект совершенно точно не может быть отдельным. Потому что без сотрудника он невозможен, как и без отдела. Можно усложнять доменную модель, которую я предложил — например, так, как предложили вы.
Просто тогда в модели вместо бинарной связи "быть начальником" между сотрудником и отделом появляется тернарная связь "исполнять роль", в которой участвуют отдел, сотрудник, и роль.
M>Единица товара это атомарный субъект транзакции учета: пачка молока, красная шляпа, автомобиль. Ведь в реальности ты продаешь покупателю не -1 из строчки количество красных шляп, а конкретный предмет со собственными свойствами и историй. И при наступлении опредленного этапа жизненного цикла заказа у тебя появляется обязательство этот предмет выделить из кучи однотипных и передать его в пользование покупателю.
Это не означает, что я обязан держать где-то столько строчек, сколько есть экземпляров однотипных товаров у меня на складе.
Вот например, я продаю кому-то 0.435 кг изюма. Что такое "обязательство"? Что тут будет "предметом, выделяемым из кучи однотипных"? 1380 изюминок?
M>Потому что поведение выражается через свойства доменных сущностей. Поведения в отрыве от сущностей не существует. Т.е. первичный сущности и только относительно сущностей мы можем определять поведение.
По-прежнему непонятно, откуда у вас возникла такая фантазия. У красной шляпы нет никакого поведения. И через свойства красной шляпы поведение домена не выражается.
Поведение есть у того, кто эту шляпу продаёт — будь то живой продавец или программа.
M>В домене торговля никого "обладающего свободой" нет и быть не может. В торговле царствуют алгоритмы имеющие силу закона. Ты не можешь взять товар и переместить его вместо покупателя на свалку просто потому что тебе так захотелось.
Чего это вдруг? Запросто перемещу. Для этого мне достаточно оформить накладную на списание. И какое там "поведение" у этого товара мне наплевать — процесс списания регламентируется приказом по компании, и сегодня он один, завтра другой, а послезавтра он зависит от цвета шляпы. Бежать внедрять код логики списания внутрь класса, объектом которого является "красная шляпа" — это последнее, что стоит делать. Именно по этой причине.
M>Реализация МОЖЕТ влиять на дизайн, но задача DDD это как раз избежать этого влияния моделируя предметную область в отрыве от искуственных ограничений. Ты можешь сделать дизайн чтобы самые частые операции выполнялись быстрее всего. Например сложить товары и заказы в одну базу. Но такой дизайн всегда получается очень хрупким, непригодным к расширению домена и при изменении требований такой дизайн быстро разваливающийся под собственной тяжестью.
M>К тому же, в современных системах не принято при выполнении доменной операции сразу бежать и что-то менять в хранилищах. Вместо этого операции накапливаются, а потом материализуются пачкой. Это могут транзакции в БД, CQRS,
M>функциональные эффекты или старый добрый паттерн Команда из GoF. Тебе никто не мешает в момент материализации переопределить порядок операций и применить любые мыслимые оптимизации, на которые у тебя хватит фантазии. Например, заменять пару SELECT/UPDATE на in place update или вообще на вызов хранимой процедуры которая генерируется из того же DSL
M>Атомарность заказа это на самом деле плохое требование. Оно сложное в реализации, плохо влияет на производительноть и, главное, не приносит прибыли маскируя проблему. Если мы не продали что-то потому что оно закончилось у нас на складе, это прямой УБЫТОК, потому что мы упустили прибыль. И современные системы строятся так, чтобы такое происходило как можно реже. Поэтому в приоритете динамической ценообразование, предсказание продаж, автоматическое пополнение и другие продвинутые процессы. В тех редких случаях когда такая ситуация произошла, дешевле вернуть покупателю деньги за недоставленный товар чем закладываться на этот сценарий.
Всё верно. Это означает, что подход, в котором "цена" является свойством "товара", непригоден. Даже если мы это свойство делаем вычисляемым. Сам товар не может знать, почём его продают — потому что ценообразование динамическое, и оно зависит и от товара, и от наличия этого товара на складе сейчас, и от покупателя и его предыстории, и от соседних товаров в том же заказе.
Никакая из этих "доменных сущностей" не подходит для размещения логики определения цены. Только какой-то внешний по отношению к этому домену "динамический ценообразователь", который, как правило, стейтлесс.
Вот он скорее всего будет построен по принципам ООП — там тебе и наследование, и полиморфизм, и агрегация, и паттерны Policy, и Factory Method и все лучшие наработки. А вот в "доменных сущностях" (в терминологии ER-модели) никакой логики не будет.
S>>Нет, это не проекция. То, что вы описываете — это REST-идеология, когда все сценарии выражаются в терминах CRUD-операций. Но она сама по себе работает только тогда, когда у нас нет никакого "поведения" за пределами этих модификаций.
M>Ну да, REST широко использует проекции данных. Это неудивительно, ведь все что мы делаем, в конечном итоге сводится к машине Тюринга на конечной ленте, а в ней ничего кроме данных не существует.
S>>Вот я взял и добавил связь между сотрудником и департаментом — и это привело к определённому результату, независимо от того, оформил ли я это через department.Employees += e или через e.Deparment = department. А может, так вообще нельзя, и нужно создать экземпляр EmployeeContractAddendum, который после подписания обеими сторонами автоматически отразит изменения штатного расписания департамента и должности у сотрудника.
M>Не всегда проекция возможна, это верно. Но ты и сам разрешил это противоречие добавив новую сущность.
То, что вы используете общепринятые термины в необщепринятом смысле, только затрудняет коммуникацию.