Re[13]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 13:30
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Mike Chaliy, Вы писали:


MC>>Тебя интересует как работает Add это к ОРМ тулу твоего выбора.

IB>Меня интересует, как это работает у тебя.
MC>>Тебя интересует как работает Mapэто к мапперу твоего выбора.
IB>И это тоже.
Сорри, я наверное туплю. Но я просто вызываю эти методы. Замени слова ЭТО на что-то конкретное.

MC>>И что там не к месту?

IB>Определение твое не к месту.
Ты его просто не понимаеш. Если бы понял, все было бы к месту. но судя по всему я не смогу обьяснить.

MC>> Именно реализация этого языка это и есть респонсибилити.

IB>Тогда ты вообще не о тех объектах.
Или ты не о тех. А ты о каких?

MC>>Нарпимер для респонсибилити обьекта ордер это реализация языка по работе с оредорм.

IB>Так данные-то где?
Поля обьекта. В его внутренней реализации. Хотя я не вижу особой разницы, может быть бег какой-то. Ты к чемуто клониш? Уж не к своему пониманию СРП, про то что хранение данных это уже достаточная респонсибилити?
А тут я живу и пишу...
Re[8]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 13:36
Оценка: +1
Здравствуйте, Mike Chaliy, Вы писали:

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



MC>>>1) ты отпарвил валидацию в конец, должно быть в начале, иначе возможны колизии, принцип фаил фаст знаеш? Обьяснить почему это проблема?

G>>Ну попробуй объясни. У меня нету ни одной тяжелой операции, которая вызывается неявно. А наносекнуды, затраченные на создания объектов роли не играют.

MC>http://en.wikipedia.org/wiki/Fail-fast

MC>В общем случае обозначает что в начале метода должны быть гарантированы рабочие инварианты. Например number == null, а он используеться для генерации текстового представления Айтама. Упс. NullRefrenceException. Это тока иллюстрация. С точки зрения безопасности это хорошо описано в Writing Secure Code, Second Edition
К обсуждаемой теме отношения не имеет.
В реальном случае я бы Code Contracts вопользовался.

MC>И что? Пусть будет без ИД, и хотя у тебя теперь не ПОКО, ну да ладно. Это все равно значительно не облечило чтение.

К чему это?

MC>Ну и ты не боишся что всю БД выгрузиш в память .

нет, я LL принципиально не использую.

MC>А еще ты не боишся что каието рефернсы будут нулл?

Если они могут быть нулл, тогда будут проверки, если нет — то нет.

MC>>>4) ты нарушил СРП в вашем понимании, обьекты теперь хранят не тока данные обьекта, но и ссылки на другие обьекты.

G>>Ничего не нарушил. Объекты не меняются пока не изменилась модель данных.
MC>У вас меняющиеся понятие СРП, в прошлый раз было тока хранение данных.
А это и есть. Ведь есть productId — данные, а ссылка product только слегка упрощает работу.
Определение SRP одно, советую внимательно его изучить. Он является основопологающим принципом хоршего дизайна.

MC>>>Ты про Тотал? Почитай про архитектуры финансовых систем. Там никогда агрегатные результаты не считаються динамически. Если один раз ордер продался по цене 20.00089 денег, то даже когда поменяеються требования к округлению он всеравно должно остаться 20.00089.

G>> Там же вес, причем ту архитектура финансовых систем?
MC>Это стандарный паттерн для любых вычислений, архитектура финансовых систем это там где про это тебе удобней всего будет почитать.
Это ты сам придумал. Денормализацию в твоем слуцчае это никак не оправдывает.

MC>>>Плюс номрализация Тотала не потдаеться юнит тестированию.

G>>Это повод вносить денормализацию?
MC>Да
Надесь ты уже сосознал сколько проблем ты себе таким создал.
Можно пойти дальше, например есть у нас представление Order — Items, показанное выше и SalePeriod — Items, ты предложишь кешировать сумму по периоду тоже (учитывая доводы что ты приводил выше)? А где её кешировать?
А как после кучи таких кешировангий будет выглядеть код CUD для Item?

G>>>>Кстати, что здесь Order.Total? Почему мы total проверяем при сохранении, а не там где действительно надо (при отправке например)?


MC>>>Потому что это бизнес процес который считает тотал. И этот же бизнес процес должен сказать если там что-то не так.

G>>Какой процесс? Там же создание заказа? Почему "создание заказа" считает Total, а не кто либо еще, кому оно надо?
MC>Потому что тотал должен быть сохранен единожды быв посчитан. Никто другой не должен самочинствовать и его считать. Кто-то другой может посчтиать какой-то свой тотал.

Ты расскажи зачем этот тотал нужен. Пока он никому не нужен его и считать не надо.
А то получается что ты придумал фигню, а теперь придумываешь оправдания.

Хочешь честно — давай исходные требования и разберем как их надо реализовывать.

MC>>>Отправка это вообще не контекстаная операция. Нафига мне валидировать тотал если он уже посчитан и дефакто валидный?

G>>Потому что твой вариант таит больше проблем, чем ты можешь представить.
MC>Конкретней, плз.
G>>Нпапример пересчет тотала при добавлении\удалении\редактировании айтема.
MC>Ессно у нас то рич модел, у нас не может получиться что тотал будет посчитан не правильно. И да пересчет тотала происходит при операциях с айтемами.
Уже начинаю плакать от смеха.
Таким образом мы получили пеессимизацию на ровном месте.
Кстати смотри выше SalePeriod — Items, как будешь выкручиваться?

G>>Тебе понадобится поднять в память все айтемы для такой операции.

G>>Очень дорогостоящее редактирование атема выйдет, если учесть что отправка ордера может и не произойти.
MC>Мы подымаем в память весь ордер со всеми айтемами. У нас это не вызвает проблем.
Браво, для редактирования одного айтема поднять в память полбазы — номальное явление для rich, ты это только что доказал.

MC>>>В любом случае твой пример всеравно не читабельный. Попробуй его прочесть плаин текстом. Куча дублирования и мусора.

G>>А ты не привел код AddItem.
MC>Зачем он тебе нужен если речь идет о читабельности этого метода. Я еще раз повторю, AddItem это черный ящик который гарантированно правильно добавит айтем и правильно изменит состояние ордера.
Ну не увиливай, приведи код. А то два куска неэвивалентны.

G>>Я кстати совершенно спокойно могу создать экстеншен метод AddItem и получить туже самую читаемоть что и у тебя.

MC>Добавив экстеншен метод у тебя получиться то о чем говорит ИБ.
о чем он говорит?

MC>Ты не знаеш что делает AddItem.

И ты не знаешь что делает AddItem в твоем случае. Это надо проверять тестами.

MC>В рич моделе это решаеться скрытием состояния, рутагрегатами, боундариес, иммутабле валью обьектами и тому подобным.

От кучи страшных слов гарантий не появится.

MC>В анемик вы вообще никак не защищены от сайдеффектов.

В rich вообще говоря тоже. Поэтому пишутся тесты.
Есдинственное отличие, что в anemic эти эффекты получить проще, но это проверяется тестами и программисты не заинектерованы писать неправильный код.

MC>AddItem у вас может полезть в какуюто левую проперти, полезть в БД и тому подобное. Вобщемто экстеншен метод это будет самы главный антиагрумент.

Твой AddItem может сделать тоже самое. Тебе все равно нужен способ доказать что он этого не делает.
Кстати в случае экстеншена у него меньше возможностей полезть во внутренее состояние объекта, поэтому экстеншены предпочтительнее. В Design Guidelines так и написано.

MC>Ты еше можеш и партиал использовать.

Партиал — обратный случай. Слишком много он может сделать с объектом.

MC>Собсно это был тока пример иллюстрирующий проблему, у AddItem может быть логика...

Тогда можно стразу идти стреляться. Потому что по коду программы станет невозможно определить что она делает.
В случае с extension кстати особо навороченную логик не засунешь. Экстеншену не откуда брать ссылку на SqlConnection например.
Re[10]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 13:38
Оценка:
Здравствуйте, meowth, Вы писали:

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


MC>>>
MC>>> (from p in Query() // Query возвращет IQueryable<Product>
MC>>>        where p.Category.Contains("sdfsdf")
MC>>>        select new ProductListItem(){
MC>>>          Name = p.Name; 
MC>>>          ImageUrl = p.Images.First().Url
MC>>>        }).Take(10).ToList();
MC>>>


G>>На входе есть products:IQueryable<Product>, который возвращает все записи. Показать надо первые 10 видимых, из категории X.

G>>Какие будут классы, как распределена логика?

M>Сорри, что лезу, но имхо все написано же:

M> p.Category.Contains("sdfsdf")... // из категории X
M> .. .Take(10) ... // первые 10
Угу, и этот код будет вызыватсья прямо из PL, весь DDD идет лесом.
Re[12]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 13:40
Оценка: 1 (1)
Здравствуйте, meowth, Вы писали:

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



M>>>Весь цимес в том, что он не доказывает и не собирается, что ваша модель -- плоха. Он говорит "ну, пользуйтесь anemic, раз вам в ней нормально. Но только имейте в виду, что Rich -- не такая ужасная, как вы думаете, а ее недостатки можно обойти, а не признавать неисправимыми"

G>>Тут есть некоторое отношение порядка, выражение для которого еще не придумано (и вряд ли будет придумиано когда-нибудь). Назовем его "лучше".
G>>Так вот мы пытаемся показать что anemic лучше rich, а Mike Chaliy говорит что rich лучше anemic, причем неважно каким способом указывая недостатки одно из подходов или достоинства другого.

M>Покажите, где он говорит, что "лучше". Он говорит -- не хуже, потому что описанные вами ужос-нахи, которые неотвратимо настигнут всякого, осмелившегося поюзать rich, зачастую надуманны и оторваны от практики, а вы с эти спорите

M>причем где _вы_ говорите, что anemic лучше, я вижу -- например, в строчке выше; вы и не скрываете

Еще раз "лучше" — название отношения порядка. Какие аргументы приводить для доказательства этого — разницы нету.
Все равно те кто пользуются rich не откажутся от него, как и пользователи anemic, а вот те кто еще не в курсе смогут для себя выводы сделать.
А то после прочтения фаулера у некоторых мозг отказывается самостоятельно работать.
Re[11]: Anemic Domain Model vs Rich Domain Model
От: meowth  
Дата: 29.05.09 13:42
Оценка:
Здравствуйте, gandjustas, Вы писали:

M>>Сорри, что лезу, но имхо все написано же:

M>> p.Category.Contains("sdfsdf")... // из категории X
M>> .. .Take(10) ... // первые 10
G>Угу, и этот код будет вызыватсья прямо из PL, весь DDD идет лесом.

Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся. Я сильно не прав?
Re[9]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 13:52
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Mike Chaliy, Вы писали:


MC>>Нам надо менять тока в том месте где надо.

IB>Ну вот, а мы как раз про сценарий, когда везде надо. Как самый геморройный и самый часто встречающийся.
У нас практически не встречаеться. У нас публикуеться минимум, у нас это один из принципов. Поэтому если что-то надо добавить для УИ, то никто не будет этого менять, в сервисах и наоборот.
И вообще это очень зависит от приложения... Хз, мож у вас правило паблишить всю модель. У меня когда-то такое было. Клиент захотел что-бы базаданных была публичным АПИ.

MC>>Ну и кто дурак? У нас такого не быват. У нас публичный АПИ тестируеться.

IB>А, то есть, твоя претензия к стройной модели сводится к тому, что там ничего не тестируется?

Та не, ты привел какойто левый пример, я вообще ни слова притензий не сказал.
Про то что мы тестируем публичное АПИ, так это вобщемто вполне нормально, мы например вылавливали проблемы с сериализацией. Логично что зафиксировав АПИ мы заботимся о подписчиках.

IB>Вообщем, кончай заливать, что у вас все зашибись как изолировано.

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

MC>>Для меня это вообще не новость, у нас репортинг это инфраструктура к которой модель вообще не имеет отношения.

IB>А к чему же у вас тогда модель имеет отношение?
К бизнес модели. Репортинг это не более чем еще одно ридонли представление данных. А данные у нас меняються тока в модели.

MC>>Если тебе хочеться сказать что типа ваша модель покрывает 5% кода приложения, а вот наша анемичная 95%(мне кажеться 40%), я с тобой вполне согласен. Для нас это не являеться камнем претконовения. Все ДТО у нас анемичны по определению.

IB>Отлично, так зачем вам тогда не DTO? Чтобы оставшиеся 5% выглядели красиво и правильно, по книжке?

1) У нас модель самая дорагая часть. От этих процесов зависят деньги.
2) Мы выбираем самый подходящий инструмент. Если для нашей модели лучше рич, то почему не рич? Мы же не враги себе. Если для справочников/реопортов/контрактов нужно анемик, тю, знач анемик.

Книги тут вообще не причем. Я же не давлю что вот типа Еванс так сказал... Мы просто это используем. Нам нравиться. И я это рассказываю.

IB>Какую проблемы вы решаете, городя true domain model — чтобы ORM работал?

?? Еще раз, мы не городим, у нас код получаеться значительно лаконичней, лучше документирован, лучше для изменения бизнес логики. true domain model это набор практик, а не фреймворк. Его не надо городить. Ты просто его используеш и все.

MC>>LINQ никто не отменял, с чего ты взял что мы не используем LINQ? У нас куча траверсинга на LINQ, репорты тож на LINQ...

IB>Ну правильно, у вас же там плоский DTO.
У нас там такая же БД как и у тебя, соотвевенно ручные средства такие же точно как у вас.
А тут я живу и пишу...
Re[10]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 13:54
Оценка: :)
Здравствуйте, Mike Chaliy, Вы писали:

MC>Ну у меня тож есть приложения в которых уи на веб формах, логика-доступ к данным в одном слое, сотни класов менеджеров. И это все работает и потдерижвается. И что?

Медаль тебе.



MC>Ты же не можеш сравнить скорости добовления фитчеров. То что ты называеш рич моделью таковой не являеться.

ну так ты может свое определение Rich придумаешь? А то мы тут все пользуемся тем что фаулер нам рассказывает.

MC>Соотвевенно у тебя просто нет опыта сравнить эти два подхода.

У меня то как раз есть.
А вот у тебя в стройной модели опыта и нету.

G>>Странно, я anemic использую, ни разу не доходило до создания отдельной инфраструктуры репортинга (отображения).

G>>Что тогда DDDшными методами делается?
MC>Тока бизнес модели. Все построенно вокруг бизнес моделей. Если доменная область не позволяет построить рич модель, то естесвенный фалбек в анемичные модели. Соотвевенно иммутабилити обьектов, и соотвевенно возможность периспользовать сущьности в других слоях.
Приведи список фич, и покажи где задействовано DDD, а где anemic.

MC>Рич модель идеальна когда стоимость реализации бизнес модели это самая большая часть бюджета. В ентрерпрайз приложениях это очень часто. Хотя уровень писателей ентерпрайз приложений обычно очень низок. А это приводит что люди думают в терминах хранилища данных. Что естевенно приводит к анемичным моделям, так как у таблиц нема поведения.

Перефразирую: используя rich модель получите стоимость реализации модели в самую большую часть бюджета.

G>>Где же Ubiquitous Language и читаемый Domain Expretом код?

MC>В доменной модели.
А 95% — то самое отображение информации, забыл?
То есть самое DDD приложение только на 5% DDD? Остальное больше похоже на anemic или вообще без объектной модели?
Тогда и говорить не о чем.

G>>Кстати, а кто вызывает показанный выше код?

MC>Именно этот УИ. Метод MVC контроллера.

MC>
MC>var query = new ListAllProductsQuery{};
MC>var page = Get<IReportingService>().QueryPage(query);
MC>return page.Results.Map(p => ProductListItemMapInstance.Map(p)) //Однако в этом месте будет загрузка целого объекта p, а потом его маппинг
MC>

Прекрасно, см коммент.

MC>>>Чето типа того, писал прямо тут, могут быть ошибки.

MC>>>В реальной реализации пейджинг, сортинг, фильтры находятсья в инфраструктуре.
G>>В какой инфраструктуре. Давай полный пример.
G>>На входе есть products:IQueryable<Product>, который возвращает все записи. Показать надо первые 10 видимых, из категории X.
G>>Какие будут классы, как распределена логика?
MC>Логики нет. Она тока в модели. Это по этому и денормализщация с тоталом.
Как это логики нет? Фильтры, группировки — самая логика, которой реально 95% в любой программе.
Или по твоему логика, это только изменения данных, которые производятся не человеком?
Re[16]: Anemic Domain Model vs Rich Domain Model
От: GlebZ Россия  
Дата: 29.05.09 13:55
Оценка:
Здравствуйте, IB, Вы писали:

GZ>>Ну наконец — то.

IB>То есть, метрика таки есть. уже хорошо.
Неправильно. Метрики правильности его применения. Это несколько другое.

GZ>>Это аггрегируемая информация.

IB>Да ну нет же.
Ну надо же. Я же писал условия задачи, и тут оказывается что нет. Что ты в неагрегате собираешься хранить?

GZ>> Ибо на физическом уровне, доступ управляется набором идентификаторов связанных с объектом.

IB>Так родительский идентификатор в объекте и так есть, тогда вообще ничего дополнительно делать не надо.
Повторяю то что писал до этого. Если нам не хватает идентификатора, а нужно поднимать весь объект, то по ресурсоемкости задача равняется Rich. А вот по сопровождению — проигрывает.

IB>Не проще, потому что когда понадобится щелкнуть этими тумблерами в обратном порядке, с одним ты ничего не сделаешь.

Если тебе нужно закрутить солнце в другую сторону, найди другую кнопку на солнце. Иначе не факт, что при обратной последовательности действий солнце не упадет на землю, и вконец не придавит слонов которые ее держат.

IB>Ты серьезно считаешь, что если я изменю сигнатуру метода с CanEdit(id), на CanEdit(id, id), мне компилятор ничего не скажет?!!

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

GZ>>А вот зачем? Весь смысл Rich, это то что ты абстрагируешься от БД.

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

GZ>>Нет. В Rich — все места связаны с методом объекта.

IB>В Anemic тоже, только другого объекта. Вопрос не как, а по какому принципу.
IB>В Rich — object cohesion, в Anemic — functional cohesion, и последнее — существенно лучше, с точки зрения поддрежки и изменения кода.
Что такое object cohesion?
Если тебе интересны подобные аналогии, то в Rich — распространен Data coupling, в Anemic — Control Coupling. Угадай, что лучше?

GZ>> Объект и контекст пользователя, все что нужно для пользы дела. Все остальные проблемы, как зависимость от типа, можно решить в одном конкретном месте.

IB>Нельзя, если типов больше одного, а вот в anemic как раз можно, вне зависимости от их количества.
Gang of Four — можешь подобрать любой способ. А для независимости от типа — нужно иметь слабоструктурированность. И это совершенно другая песня.

GZ>>То, что можно изменить полиморфно поведение в одном месте существенно увеличивает поддержку?

IB>Во-первых не полиморфно, а во-вторых, существенно ухудшает, как только появляется дополнительный сценарий.
Все, мило молчу. Тебе виднее.

GZ>>В Rich — строго наоборот. Объект решает как ему проверяться. Это большая разница.

IB>Конечно, это один из основных косяков Rich, так как проверка зависит от контекста, значит объект должен знать обо всех контекстах.
Опять. Если ты о контексте использования, то Gang of Four/
Re[9]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 13:56
Оценка:
Здравствуйте, IB, Вы писали:

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


M>>Человек (Mike Chaliy) показывает вам на примере своего проекта, как оно работает

IB>В том, то и дело, что не показывает.
Ну и ладно... В конце-то концов от меня не убудет. Разве что время потратил...

M>>-- что оно а)элегантно б)реально РАБОТАЕТ (это тоже важно) б)легко сопровождаемо в)не содержит тех проблем, которые вы пытаетесь отыскать в решении.

IB>Оно нифига не "элегантно", как выясняется, работать может вообще все, как я уже говорил, а про проблемы отдельный разговор. Тут вот походу выясняется, что свою красивую модель он вообще не использует, а использует повсюду DTO, а модель как раз для красоты и элегантности — понятно что проблем нет.

Хм, мы используем ее там где это оправдано. Ты же не используеш ТекстБокс как поле класса модели? Так и мы не используем анемик для реализации бизнес модели.

M>> Но при этом почему-то сами ставите ему вопрос, сами отвечаете, и в своем ответе находите недочеты, которые приписываете решению.

IB>Ну так он-то не отвечает, вот и приходится гадать.. =)

Пля, ну и где я не ответил? Дава конкретный вопрос где я не ответил.
А тут я живу и пишу...
Re[12]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 13:59
Оценка:
Здравствуйте, meowth, Вы писали:

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


M>>>Сорри, что лезу, но имхо все написано же:

M>>> p.Category.Contains("sdfsdf")... // из категории X
M>>> .. .Take(10) ... // первые 10
G>>Угу, и этот код будет вызыватсья прямо из PL, весь DDD идет лесом.

M>Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся.

Ага, теперь нам надо разный код писать для работы с товарами категории X в domain и в reporting.
Ну что, господа архитекторы, где тут повторное использование кода?

M>Я сильно не прав?

Не, ты очень сильно прав. Даже неверное сильнее, чем хотелось бы.
Re[13]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 14:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

M>>Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся.

G>Ага, теперь нам надо разный код писать для работы с товарами категории X в domain и в reporting.
G>Ну что, господа архитекторы, где тут повторное использование кода?

А что именно не переиспользуеться?
Еще раз, в репортах ретрив информации. Ни клочка логики.
В модели изменение состояния.
А тут я живу и пишу...
Re[13]: Anemic Domain Model vs Rich Domain Model
От: meowth  
Дата: 29.05.09 14:16
Оценка:
Здравствуйте, gandjustas, Вы писали:

M>>Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся.

G>Ага, теперь нам надо разный код писать для работы с товарами категории X в domain и в reporting.

Хм, ты странно ведешь беседу.
По-твоему, для domain этот код плох, потому что он с слишком DTO-ориентирован, для репортинга плох, потому что не такой же, как для domain, хотя и лезет в domain, а для presentation layer я так и не понял почему плох, но у тебя он вызвал сильное отторжение.

G>разный код писать для работы с товарами категории X в domain и в reporting.

В основном -- нет, потому что AutoMapper отлично умеет мапить rich model на presentation DTO (или reporting items). Тот же самый код используется и для reporting'а, только потом из domain легким движением o2o mapper получается reporting DTO.

Однако может быть такое, что и надо. Но это -- редкая и ожидаемая фигня, потому что в репортинге все равно используются свои presentation envelopes aka DTO, и даже anеmic от них не спасет. (Блин, и мы опять обсуждаем тот + anemic, что там можно поднять domain model в UI. Тьфу!)

G>Ну что, господа архитекторы, где тут повторное использование кода?

Повторное использование будет там, где есть повторная парадигма. Был показан пример domain query, чего тебя не устраивает?

M>>Я сильно не прав?

G>Не, ты очень сильно прав. Даже неверное сильнее, чем хотелось бы.
Ну да же не знаю, что сказать. Неверное, я обратное доказывать не буду, потому что не собираюсь занимать позицию защищиющегося.
Re[11]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 14:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

MC>>Ты же не можеш сравнить скорости добовления фитчеров. То что ты называеш рич моделью таковой не являеться.

G>ну так ты может свое определение Rich придумаешь? А то мы тут все пользуемся тем что фаулер нам рассказывает.
Ну и чего у тебя тогда вопросы возникают? Файлер же не говорит что надо в домен засовывать фильры, кнопки сейв, сериализации или все то что вы тут описываете.


G>Приведи список фич, и покажи где задействовано DDD, а где anemic.


Рич
ДобавитьОрдер
ЗапаблишитьОрдер

Анемик
Показать Оредеры за такойто период (УИ, или репортты, или ДТО промапленые из модели)
Сделать доступным информацию про ордеры (ВебСервис, почти все операции ходтя в рич модель, а результат мапят в ДТО)

MC>>Рич модель идеальна когда стоимость реализации бизнес модели это самая большая часть бюджета. В ентрерпрайз приложениях это очень часто. Хотя уровень писателей ентерпрайз приложений обычно очень низок. А это приводит что люди думают в терминах хранилища данных. Что естевенно приводит к анемичным моделям, так как у таблиц нема поведения.

G>Перефразирую: используя rich модель получите стоимость реализации модели в самую большую часть бюджета.
смешно. Если у тебя бизнес логика это самое дешевое, то врядли тебе стоит нервничать.

G>>>Где же Ubiquitous Language и читаемый Domain Expretом код?

MC>>В доменной модели.
G> А 95% — то самое отображение информации, забыл?
95% это слова ИБ, я какнибуть погляжу статистику но что-то мне подсказывает что самая большая часть это УИ, потом домен, потом дто, потом инфраструктура.

G>То есть самое DDD приложение только на 5% DDD? Остальное больше похоже на anemic или вообще без объектной модели?

G>Тогда и говорить не о чем.
ОК, хотя я ответил ИБ на такой же точно вопрос.

G>>>Кстати, а кто вызывает показанный выше код?

ХЗ, я не знаю про какой ты код.

MC>>Именно этот УИ. Метод MVC контроллера.


MC>>
MC>>var query = new ListAllProductsQuery{};
MC>>var page = Get<IReportingService>().QueryPage(query);
MC>>return page.Results.Map(p => ProductListItemMapInstance.Map(p)) //Однако в этом месте будет загрузка целого объекта p, а потом его маппинг
MC>>

G>Прекрасно, см коммент.
И что? Это проблема?


MC>>Логики нет. Она тока в модели. Это по этому и денормализщация с тоталом.

G>Как это логики нет? Фильтры, группировки — самая логика, которой реально 95% в любой программе.
У нас это единожды написаный код. Мы просто периспользуем обьекты Query. Ессно что одинотипное фильтрование мы строим по метаданным.

G>Или по твоему логика, это только изменения данных, которые производятся не человеком?

Я про логику изменения состояния в модели данных. Обычно эти изменения инциализируються какараз человеком.
А тут я живу и пишу...
Re[14]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 14:23
Оценка:
Здравствуйте, Mike Chaliy, Вы писали:

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


M>>>Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся.

G>>Ага, теперь нам надо разный код писать для работы с товарами категории X в domain и в reporting.
G>>Ну что, господа архитекторы, где тут повторное использование кода?

MC>А что именно не переиспользуеться?

MC>Еще раз, в репортах ретрив информации. Ни клочка логики.
MC>В модели изменение состояния.

Юзкейс из моего проекта. Только админ может видеть\редактировать\еще_что_то_делать с сущностями X, которые невидимы (Visible = false).
Короче для каждой операции надо накладывать условие выборки. У меня всо всех случаях (хоть репортиг, хоть что-то еще) делает это один и тот же код.
(На самом деле это делается для всех сущностей, у которых есть видимость, одним и тем же кодом)

В твоем случае придется два раза писать для reporting и domain.
Re[14]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 14:37
Оценка:
Здравствуйте, meowth, Вы писали:

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


M>>>Mike же сказал, что это -- reporting, а там на DDD никто и не надеялся.

G>>Ага, теперь нам надо разный код писать для работы с товарами категории X в domain и в reporting.

M>Хм, ты странно ведешь беседу.

M>По-твоему, для domain этот код плох, потому что он с слишком DTO-ориентирован, для репортинга плох, потому что не такой же, как для domain, хотя и лезет в domain, а для presentation layer я так и не понял почему плох, но у тебя он вызвал сильное отторжение.
Это ты что-то придумал.

G>>разный код писать для работы с товарами категории X в domain и в reporting.

M>В основном -- нет, потому что AutoMapper отлично умеет мапить rich model на presentation DTO (или reporting items). Тот же самый код используется и для reporting'а, только потом из domain легким движением o2o mapper получается reporting DTO.
Только для этого надо поднять в память сначала весь объект. А это может быть непозволительно долго.
Кроме того, если нужны запросы с аггрегатными операциями, что придумаете?
Re[9]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 14:50
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Mike Chaliy, Вы писали:


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



MC>>>>1) ты отпарвил валидацию в конец, должно быть в начале, иначе возможны колизии, принцип фаил фаст знаеш? Обьяснить почему это проблема?

G>>>Ну попробуй объясни. У меня нету ни одной тяжелой операции, которая вызывается неявно. А наносекнуды, затраченные на создания объектов роли не играют.

MC>>http://en.wikipedia.org/wiki/Fail-fast

MC>>В общем случае обозначает что в начале метода должны быть гарантированы рабочие инварианты. Например number == null, а он используеться для генерации текстового представления Айтама. Упс. NullRefrenceException. Это тока иллюстрация. С точки зрения безопасности это хорошо описано в Writing Secure Code, Second Edition
G>К обсуждаемой теме отношения не имеет.
Имеет, попробуй сделать свой метод читабельным с учетом этого правила.
G>В реальном случае я бы Code Contracts вопользовался.
Гениально , особенно если учесть что мы пишем бизнес логику. Тогда уже Debug.Assert... Если не иронизировать, то в случае если number это может быть юзерский инпут(или пользование публичного АПИ) твои Code Contracts будут просто жестоко выглядеть , ты путаеш тулинг . Пустой number это не контракт метода, это инвалидная бизнес операция.

MC>>И что? Пусть будет без ИД, и хотя у тебя теперь не ПОКО, ну да ладно. Это все равно значительно не облечило чтение.

G>К чему это?
К тому что даже сделав референсы, читабельность метода значительно не улучшилась..

MC>>Ну и ты не боишся что всю БД выгрузиш в память .

G>нет, я LL принципиально не использую.
У Ордера свзяь с Айтемом, у Айтема с Периодом, У Айтема с Периодом. Пои идее у тебя должно выгрузить Ордер, Айтмы и Периодом, ну или хачить с зинтами. Но тогда хз когда и где полезут нуллы.

MC>>А еще ты не боишся что каието рефернсы будут нулл?

G>Если они могут быть нулл, тогда будут проверки, если нет — то нет.
А у нас не может быть нулов, в все твой нелюбимый агрегат рут.

MC>>>>4) ты нарушил СРП в вашем понимании, обьекты теперь хранят не тока данные обьекта, но и ссылки на другие обьекты.

G>>>Ничего не нарушил. Объекты не меняются пока не изменилась модель данных.
MC>>У вас меняющиеся понятие СРП, в прошлый раз было тока хранение данных.
G>А это и есть. Ведь есть productId — данные, а ссылка product только слегка упрощает работу.
G>Определение SRP одно, советую внимательно его изучить. Он является основопологающим принципом хоршего дизайна.
, Поржал, вы тут с ИБ практикуете уникальное понимание СРП и при этом ты говориш мне его изучать .

MC>>>>Ты про Тотал? Почитай про архитектуры финансовых систем. Там никогда агрегатные результаты не считаються динамически. Если один раз ордер продался по цене 20.00089 денег, то даже когда поменяеються требования к округлению он всеравно должно остаться 20.00089.

G>>> Там же вес, причем ту архитектура финансовых систем?
MC>>Это стандарный паттерн для любых вычислений, архитектура финансовых систем это там где про это тебе удобней всего будет почитать.
G>Это ты сам придумал. Денормализацию в твоем слуцчае это никак не оправдывает.
Ты дорастеш до этого... Правда потерянные нолики могут оказаться критическими, ну да ладно. Ты же сам себе на уме.

MC>>>>Плюс номрализация Тотала не потдаеться юнит тестированию.

G>>>Это повод вносить денормализацию?
MC>>Да
G>Надесь ты уже сосознал сколько проблем ты себе таким создал.
Это осознаное решение, основанное на своем и чужем опыте.

G>Можно пойти дальше, например есть у нас представление Order — Items, показанное выше и SalePeriod — Items, ты предложишь кешировать сумму по периоду тоже (учитывая доводы что ты приводил выше)? А где её кешировать?

Смотря чего ты добиваешся. В закрытом периоде SalePeriod вполне можно и кешировать, в открытом оно не имеет смысл.

G>А как после кучи таких кешировангий будет выглядеть код CUD для Item?

Хз, у нас такого кода нет.

G>>>>>Кстати, что здесь Order.Total? Почему мы total проверяем при сохранении, а не там где действительно надо (при отправке например)?

MC>>>>Потому что это бизнес процес который считает тотал. И этот же бизнес процес должен сказать если там что-то не так.
G>>>Какой процесс? Там же создание заказа? Почему "создание заказа" считает Total, а не кто либо еще, кому оно надо?
MC>>Потому что тотал должен быть сохранен единожды быв посчитан. Никто другой не должен самочинствовать и его считать. Кто-то другой может посчтиать какой-то свой тотал.
G>
G>Ты расскажи зачем этот тотал нужен. Пока он никому не нужен его и считать не надо.
При изменении непроданного ордера должен пересчитаться тотал.

G>А то получается что ты придумал фигню, а теперь придумываешь оправдания.

Писец, что значит оправдания? Где оправдания? Это конкретная реаолизация с конкретными требованиями.
G>Хочешь честно — давай исходные требования и разберем как их надо реализовывать.
Выше. Я не представляю как ты будеш разбирать если у тебя нема представленя постороения таких систем...

MC>>>>Отправка это вообще не контекстаная операция. Нафига мне валидировать тотал если он уже посчитан и дефакто валидный?

G>>>Потому что твой вариант таит больше проблем, чем ты можешь представить.
MC>>Конкретней, плз.
G>>>Нпапример пересчет тотала при добавлении\удалении\редактировании айтема.
MC>>Ессно у нас то рич модел, у нас не может получиться что тотал будет посчитан не правильно. И да пересчет тотала происходит при операциях с айтемами.
G>Уже начинаю плакать от смеха.
G>Таким образом мы получили пеессимизацию на ровном месте.
G>Кстати смотри выше SalePeriod — Items, как будешь выкручиваться?
Выше.


G>>>Тебе понадобится поднять в память все айтемы для такой операции.

G>>>Очень дорогостоящее редактирование атема выйдет, если учесть что отправка ордера может и не произойти.
MC>>Мы подымаем в память весь ордер со всеми айтемами. У нас это не вызвает проблем.
G>Браво, для редактирования одного айтема поднять в память полбазы — номальное явление для rich, ты это только что доказал.
Да. Откуда ты взял пол базы? У нас есть понятие рут агрегата. Это обьект с четкими границами. У нас не бывает ситуаций когда неконтролированно подгружаеться что-то извне агрегата. И недозаполненый обьектов как у вас не бывает. У нас обьект всегда актуален.

MC>>>>В любом случае твой пример всеравно не читабельный. Попробуй его прочесть плаин текстом. Куча дублирования и мусора.

G>>>А ты не привел код AddItem.
MC>>Зачем он тебе нужен если речь идет о читабельности этого метода. Я еще раз повторю, AddItem это черный ящик который гарантированно правильно добавит айтем и правильно изменит состояние ордера.
G>Ну не увиливай, приведи код. А то два куска неэвивалентны.
Эквиваленты, полностью решают одну и туже задачу. И имеют идентичный результаты. Я не буду ничего приводить. Мне что скушно?

G>>>Я кстати совершенно спокойно могу создать экстеншен метод AddItem и получить туже самую читаемоть что и у тебя.

MC>>Добавив экстеншен метод у тебя получиться то о чем говорит ИБ.
G>о чем он говорит?
Что код говоно.

MC>>Ты не знаеш что делает AddItem.

G>И ты не знаешь что делает AddItem в твоем случае. Это надо проверять тестами.
Уже проверено. И гарантированно работает во всех инвариантах ордера. А твоя версия просто не может гарантировать инварианты.

MC>>В рич моделе это решаеться скрытием состояния, рутагрегатами, боундариес, иммутабле валью обьектами и тому подобным.

G>От кучи страшных слов гарантий не появится.
Появляеться. Как бы ты не сопротивлялся.

MC>>В анемик вы вообще никак не защищены от сайдеффектов.

G>В rich вообще говоря тоже. Поэтому пишутся тесты.
У нас запрещено выходить за приделы рут агрегатов, у нас запрещено выходить за приделы сервисов. На кажном уровне свои запреты. Причем для рут агрегатов это гарантируеться на компил тайме.
G>Есдинственное отличие, что в anemic эти эффекты получить проще, но это проверяется тестами и программисты не заинектерованы писать неправильный код.
Дава по пунктам.
Как ты получиш сокрытие данных в анемик? Иммутабле? Ты не можеш их пользовать у тебя Linq2Sql.
Как ты получиш рутагрегатамы? Вспомни про разные вью.
Как ты получиш боундариес? Тут проще в теории ничего сложного, но реально в рич моделях это на уровне практик, а в анемик про это даже не задумываються.

MC>>AddItem у вас может полезть в какуюто левую проперти, полезть в БД и тому подобное. Вобщемто экстеншен метод это будет самы главный антиагрумент.

G>Твой AddItem может сделать тоже самое. Тебе все равно нужен способ доказать что он этого не делает.
Выше
G>Кстати в случае экстеншена у него меньше возможностей полезть во внутренее состояние объекта, поэтому экстеншены предпочтительнее. В Design Guidelines так и написано.
Ссылку. Ты забыл у тебя анемик у тебя все состояние наружу.

MC>>Ты еше можеш и партиал использовать.

G>Партиал — обратный случай. Слишком много он может сделать с объектом.
Что можно больше сделать с обьектом у которого все открыто?

MC>>Собсно это был тока пример иллюстрирующий проблему, у AddItem может быть логика...

G>Тогда можно стразу идти стреляться. Потому что по коду программы станет невозможно определить что она делает.
Он добовляет айтем. Все просто.
G>В случае с extension кстати особо навороченную логик не засунешь. Экстеншену не откуда брать ссылку на SqlConnection например.
, супер агрумент.
А тут я живу и пишу...
Re[12]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 14:55
Оценка:
Здравствуйте, Mike Chaliy, Вы писали:

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


MC>>>Ты же не можеш сравнить скорости добовления фитчеров. То что ты называеш рич моделью таковой не являеться.

G>>ну так ты может свое определение Rich придумаешь? А то мы тут все пользуемся тем что фаулер нам рассказывает.
MC>Ну и чего у тебя тогда вопросы возникают? Файлер же не говорит что надо в домен засовывать фильры, кнопки сейв, сериализации или все то что вы тут описываете.


G>>Приведи список фич, и покажи где задействовано DDD, а где anemic.


MC>Рич

MC>ДобавитьОрдер
MC>ЗапаблишитьОрдер


MC>Анемик

MC>Показать Оредеры за такойто период (УИ, или репортты, или ДТО промапленые из модели)
А также:
Показать ордеры такого-то клиента.
Показать самые популярные товары
...

Короче ДобавитьОрдер, как уже выяснили в rich и anemic случае почти одинаково выглядят, наверное как и ЗапаблишитьОрдер.
Поэтому тему можно не продолжать. действительно при самом rich 95% получается вовсе даже anemic.

MC>>>Рич модель идеальна когда стоимость реализации бизнес модели это самая большая часть бюджета. В ентрерпрайз приложениях это очень часто. Хотя уровень писателей ентерпрайз приложений обычно очень низок. А это приводит что люди думают в терминах хранилища данных. Что естевенно приводит к анемичным моделям, так как у таблиц нема поведения.

G>>Перефразирую: используя rich модель получите стоимость реализации модели в самую большую часть бюджета.
MC> смешно. Если у тебя бизнес логика это самое дешевое, то врядли тебе стоит нервничать.
У меня на самом деле БЛ — всегда самая большая часть. Для меня логика — это то что лежит между разметкой UI и базой данных.
Ифраструктурная часть логики одинаковая для всех проектов, поэтому её писать не надо.

MC>>>Именно этот УИ. Метод MVC контроллера.


MC>>>
MC>>>var query = new ListAllProductsQuery{};
MC>>>var page = Get<IReportingService>().QueryPage(query);
MC>>>return page.Results.Map(p => ProductListItemMapInstance.Map(p)) //Однако в этом месте будет загрузка целого объекта p, а потом его маппинг
MC>>>

G>>Прекрасно, см коммент.
MC>И что? Это проблема?
Вообще то да.
Чтобы сформировать ProductListItem (три поля) тебе понадобится поднять в память весь product, весь список связанных Image, а только потом маппер сделает 3 поля.

MC>>>Логики нет. Она тока в модели. Это по этому и денормализщация с тоталом.

G>>Как это логики нет? Фильтры, группировки — самая логика, которой реально 95% в любой программе.
MC>У нас это единожды написаный код. Мы просто периспользуем обьекты Query. Ессно что одинотипное фильтрование мы строим по метаданным.
Это просто нету сложных выборок. Например как получить список заказов с суммой , если сумма не кешируется в самом заказе?
Метаданные отдыхают.
Re[15]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 14:58
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Юзкейс из моего проекта. Только админ может видеть\редактировать\еще_что_то_делать с сущностями X, которые невидимы (Visible = false).

G>Короче для каждой операции надо накладывать условие выборки. У меня всо всех случаях (хоть репортиг, хоть что-то еще) делает это один и тот же код.
G>(На самом деле это делается для всех сущностей, у которых есть видимость, одним и тем же кодом)

G>В твоем случае придется два раза писать для reporting и domain.


Я не вижу дублирования.

1) Первое у нас в продукте есть Multitenancy. Это когда в одной БД можут находиться несколько разных приложений (это мы економим на хосете моде). Реализвано приблизительно как в http://java.dzone.com/articles/introduction-hibernate-filters У нас аналогичное тока програмно. Мы не используем ХМЛ.
Фактически с фильтром приложение не видит ничего из того что ей не позволено.

2) Ну а второе, секурити тримминг это не респонсибилити модели. Этим может заниматься тока ендинтерфейс, ну или аппликейшен фасады. В домене вообще нема понятия Админа.
А тут я живу и пишу...
Re[13]: Anemic Domain Model vs Rich Domain Model
От: Mike Chaliy Украина http://chaliy.name
Дата: 29.05.09 15:08
Оценка:
Здравствуйте, gandjustas, Вы писали:


MC>>И что? Это проблема?

G>Вообще то да.
G>Чтобы сформировать ProductListItem (три поля) тебе понадобится поднять в память весь product, весь список связанных Image, а только потом маппер сделает 3 поля.
Если это станет проблемой, а оно не станет, как я говорил у нас кеши. Мы прикрутим кастомный репорт.

G>Это просто нету сложных выборок. Например как получить список заказов с суммой , если сумма не кешируется в самом заказе?

Незнаю, ты придумал себе проблему ты и решай. У нас суммы не кешируються. У нас они сохраняються.
А тут я живу и пишу...
Re[10]: Anemic Domain Model vs Rich Domain Model
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.05.09 15:32
Оценка:
Здравствуйте, Mike Chaliy, Вы писали:

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


G>>Здравствуйте, Mike Chaliy, Вы писали:


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



MC>>>>>1) ты отпарвил валидацию в конец, должно быть в начале, иначе возможны колизии, принцип фаил фаст знаеш? Обьяснить почему это проблема?

G>>>>Ну попробуй объясни. У меня нету ни одной тяжелой операции, которая вызывается неявно. А наносекнуды, затраченные на создания объектов роли не играют.

MC>>>http://en.wikipedia.org/wiki/Fail-fast

MC>>>В общем случае обозначает что в начале метода должны быть гарантированы рабочие инварианты. Например number == null, а он используеться для генерации текстового представления Айтама. Упс. NullRefrenceException. Это тока иллюстрация. С точки зрения безопасности это хорошо описано в Writing Secure Code, Second Edition
G>>К обсуждаемой теме отношения не имеет.
MC>Имеет, попробуй сделать свой метод читабельным с учетом этого правила.
тебе больше придраться не к чему?

G>>В реальном случае я бы Code Contracts вопользовался.

MC>Гениально , особенно если учесть что мы пишем бизнес логику. Тогда уже Debug.Assert... Если не иронизировать, то в случае если number это может быть юзерский инпут(или пользование публичного АПИ) твои Code Contracts будут просто жестоко выглядеть , ты путаеш тулинг . Пустой number это не контракт метода, это инвалидная бизнес операция.
Ты ни разу не пользовался контрактами чтоли?
Я поставлю контракт в createOrder, проверятель начнет ругаться в вызвающем методе, что может быть передан неправльный number, я вставлю контракт там, итд.
Так дойдет до PL, где я просто обязан буду вставить проверку на пустой намбер.

А перед сохранением вставлю код валидации объекта, чтобы гарантировано в базу неверная инфа не попала.

MC>>>И что? Пусть будет без ИД, и хотя у тебя теперь не ПОКО, ну да ладно. Это все равно значительно не облечило чтение.

G>>К чему это?
MC>К тому что даже сделав референсы, читабельность метода значительно не улучшилась..
Ну ты достал уже

public void CreateOrder(number)
{
  Contract.Requires(number != null);

  var order = new Order(){Number = number, Total = calcualteTotal(weight1, weight2)};
  order.AddItem(product1, weight1);
  order.AddItem(product2, weight2);

  _validationService.Validate(order);
  _orderRepository.Add(order);
}

AddItem — экстеншен метод, код которого я тебе не покажу.
Теперь гораздо интереснее.
Явный контракт позволяет статически проверки делать — очень гут.
Нету скрытой логики с calculateTotal внутри ордера — тоже прекрасно.

MC>>>Ну и ты не боишся что всю БД выгрузиш в память .

G>>нет, я LL принципиально не использую.
MC>У Ордера свзяь с Айтемом, у Айтема с Периодом, У Айтема с Периодом. Пои идее у тебя должно выгрузить Ордер, Айтмы и Периодом, ну или хачить с зинтами. Но тогда хз когда и где полезут нуллы.
Эта фраза похожа на заклинание вызова духов...

MC>>>А еще ты не боишся что каието рефернсы будут нулл?

G>>Если они могут быть нулл, тогда будут проверки, если нет — то нет.
MC>А у нас не может быть нулов, в все твой нелюбимый агрегат рут.
Это вам кто обеспечивает? Святой дух? Все равно ведь для этого код написан.

MC>>>>>4) ты нарушил СРП в вашем понимании, обьекты теперь хранят не тока данные обьекта, но и ссылки на другие обьекты.

G>>>>Ничего не нарушил. Объекты не меняются пока не изменилась модель данных.
MC>>>У вас меняющиеся понятие СРП, в прошлый раз было тока хранение данных.
G>>А это и есть. Ведь есть productId — данные, а ссылка product только слегка упрощает работу.
G>>Определение SRP одно, советую внимательно его изучить. Он является основопологающим принципом хоршего дизайна.
MC>), Поржал, вы тут с ИБ практикуете уникальное понимание СРП и при этом ты говориш мне его изучать .
http://en.wikipedia.org/wiki/Single_responsibility_principle
изучай.

G>>Это ты сам придумал. Денормализацию в твоем слуцчае это никак не оправдывает.

MC>Ты дорастеш до этого... Правда потерянные нолики могут оказаться критическими, ну да ладно. Ты же сам себе на уме.
Ну не отмазывайся. Там же вес, а не бабло.

G>>Можно пойти дальше, например есть у нас представление Order — Items, показанное выше и SalePeriod — Items, ты предложишь кешировать сумму по периоду тоже (учитывая доводы что ты приводил выше)? А где её кешировать?

MC>Смотря чего ты добиваешся. В закрытом периоде SalePeriod вполне можно и кешировать, в открытом оно не имеет смысл.
Все, не могу больше. Код в студию.
Давай с кешированием сумм по ордерам и закрытым периодам.
Банально CRUD для Itemов.

G>>А как после кучи таких кешировангий будет выглядеть код CUD для Item?

MC>Хз, у нас такого кода нет.
Что? позиции в заказы не добавляются?
Не верю (С) Станиславский.

G>>>>>>Кстати, что здесь Order.Total? Почему мы total проверяем при сохранении, а не там где действительно надо (при отправке например)?

MC>>>>>Потому что это бизнес процес который считает тотал. И этот же бизнес процес должен сказать если там что-то не так.
G>>>>Какой процесс? Там же создание заказа? Почему "создание заказа" считает Total, а не кто либо еще, кому оно надо?
MC>>>Потому что тотал должен быть сохранен единожды быв посчитан. Никто другой не должен самочинствовать и его считать. Кто-то другой может посчтиать какой-то свой тотал.
G>>
G>>Ты расскажи зачем этот тотал нужен. Пока он никому не нужен его и считать не надо.
MC>При изменении непроданного ордера должен пересчитаться тотал.
Да не надо мне эту чушь говорить. Скажи кому этот тотал нужен.
Ты же там вес указал.

G>>А то получается что ты придумал фигню, а теперь придумываешь оправдания.

MC>Писец, что значит оправдания? Где оправдания? Это конкретная реаолизация с конкретными требованиями.
G>>Хочешь честно — давай исходные требования и разберем как их надо реализовывать.
MC>Выше. Я не представляю как ты будеш разбирать если у тебя нема представленя постороения таких систем...
Да ты полные требования (только не результат их интерпретации тобой) покажи.
Или хотябы замкнутое подмножество.

MC>>>>>Отправка это вообще не контекстаная операция. Нафига мне валидировать тотал если он уже посчитан и дефакто валидный?

G>>>>Потому что твой вариант таит больше проблем, чем ты можешь представить.
MC>>>Конкретней, плз.
G>>>>Нпапример пересчет тотала при добавлении\удалении\редактировании айтема.
MC>>>Ессно у нас то рич модел, у нас не может получиться что тотал будет посчитан не правильно. И да пересчет тотала происходит при операциях с айтемами.
G>>Уже начинаю плакать от смеха.
G>>Таким образом мы получили пеессимизацию на ровном месте.
G>>Кстати смотри выше SalePeriod — Items, как будешь выкручиваться?
MC>Выше.
Ну давай же код.

G>>>>Тебе понадобится поднять в память все айтемы для такой операции.

G>>>>Очень дорогостоящее редактирование атема выйдет, если учесть что отправка ордера может и не произойти.
MC>>>Мы подымаем в память весь ордер со всеми айтемами. У нас это не вызвает проблем.
G>>Браво, для редактирования одного айтема поднять в память полбазы — номальное явление для rich, ты это только что доказал.
MC>Да. Откуда ты взял пол базы? У нас есть понятие рут агрегата. Это обьект с четкими границами. У нас не бывает ситуаций когда неконтролированно подгружаеться что-то извне агрегата.
Это не отменяет того факта что для редактирования айтема надо поднимать много данных.

MC>И недозаполненый обьектов как у вас не бывает. У нас обьект всегда актуален.

И что вам это дает?

G>>>>Я кстати совершенно спокойно могу создать экстеншен метод AddItem и получить туже самую читаемоть что и у тебя.

MC>>>Добавив экстеншен метод у тебя получиться то о чем говорит ИБ.
G>>о чем он говорит?
MC>Что код говоно.
Доказательства?

MC>>>Ты не знаеш что делает AddItem.

G>>И ты не знаешь что делает AddItem в твоем случае. Это надо проверять тестами.
MC>Уже проверено. И гарантированно работает во всех инвариантах ордера. А твоя версия просто не может гарантировать инварианты.
Угу, у меня нету инвариантов ордера.
У меня тестами проверяется что нельзя сделать с ордером того, чего с ним делать нельзя.
У меня вообще ордер имеет состояние только потому что EF не поддерживает работу с Immutable данными.

MC>>>В рич моделе это решаеться скрытием состояния, рутагрегатами, боундариес, иммутабле валью обьектами и тому подобным.

G>>От кучи страшных слов гарантий не появится.
MC>Появляеться. Как бы ты не сопротивлялся.
Да никак не появляется. Кто тебе гарнтирует что под страшными словом не сидит баг?

MC>>>В анемик вы вообще никак не защищены от сайдеффектов.

G>>В rich вообще говоря тоже. Поэтому пишутся тесты.
MC>У нас запрещено выходить за приделы рут агрегатов, у нас запрещено выходить за приделы сервисов. На кажном уровне свои запреты. Причем для рут агрегатов это гарантируеться на компил тайме.
Каким образом?
ты запретишь кому-либо в compile time внутри рут агрегата создать SqlConnection?
Если да, то скажи как. Тоже юзать буду. А то пока по-старинке: тесты, да code review.

G>>Есдинственное отличие, что в anemic эти эффекты получить проще, но это проверяется тестами и программисты не заинектерованы писать неправильный код.

MC>Дава по пунктам.
MC>Как ты получиш сокрытие данных в анемик? Иммутабле? Ты не можеш их пользовать у тебя Linq2Sql.
Сначала скажи зачем мне скрывать данные? Обынчо наоборот — их показывать надо.

MC>Как ты получиш рутагрегатамы? Вспомни про разные вью.

Мне они не нужны. Я просто Linq запросы пишу и все. Рутагрегаты, это такой же костыль rich, как DTO.

MC>Как ты получиш боундариес? Тут проще в теории ничего сложного, но реально в рич моделях это на уровне практик, а в анемик про это даже не задумываються.

Да все тоже самое, только названий модных нету.

MC>>>AddItem у вас может полезть в какуюто левую проперти, полезть в БД и тому подобное. Вобщемто экстеншен метод это будет самы главный антиагрумент.

G>>Твой AddItem может сделать тоже самое. Тебе все равно нужен способ доказать что он этого не делает.
MC>Выше
G>>Кстати в случае экстеншена у него меньше возможностей полезть во внутренее состояние объекта, поэтому экстеншены предпочтительнее. В Design Guidelines так и написано.
MC>Ссылку. Ты забыл у тебя анемик у тебя все состояние наружу.
Это не касаемо anemic, это Framework Design Guidelines последней редакции.

MC>>>Ты еше можеш и партиал использовать.

G>>Партиал — обратный случай. Слишком много он может сделать с объектом.
MC>Что можно больше сделать с обьектом у которого все открыто?
Это тоже не касаемо anemic.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.