True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 24.10.07 14:57
Оценка: 9 (4)
Так уж сложилось что сейчас большинство новых серверных приложений, которые приходится видеть, дизайнятся следующим образом.
Model — тупые контейнеры данных реализующие бизнес-сущности
Service — реализация бизнес-логики, которая оперирует Model и работает с другими слоями системы в т.ч. DAL/DAO
И вроде бы все красиво и приятно. Модель часто удается протащить сквозь все уровни приложения (Persistance, Service, RCP и даже View). Service же легким движением руки можно выставить наружу как RPC или использовать другими компонентами. SOA вроде как получается?

Но вновь и вновь появляется материал сеющий зерно сомнения. Первой конечно же была статья Мартина Фаулера
AnemicDomainModel. Про то что это совсем не правильно когда логика отдельно от данных. А на резонную критику что Model нельзя связывать с внешними сервисами, например DAL. Появилась новая абстракция Repository:
http://debasishg.blogspot.com/2007/02/domain-driven-design-inject.html
http://martinfowler.com/eaaCatalog/repository.html
http://domaindrivendesign.org/books/index.html

Внимание вопрос. Кто-нибудь может внятно объяснить, или ткнуть носом чем второй подход с внедрением бесполезного слоя Repository лучше чем Anemic Model? В приведенных ссылках ни одного понятного мне объяснения не нашел. На счет упрощеного тестирования тоже не согласен, вроде и при первом подходе серьезных проблем с юнит тестами не возникало. Если кто читал книгу DDD, буду благодарен за указание главы, где можно подчерпнуть недостающее знание по интересующему вопросу.

Спасибо!
Re: True OOP&Repository vs Service&AnemicModel
От: Igor Trofimov  
Дата: 24.10.07 18:21
Оценка:
B>Но вновь и вновь появляется материал сеющий зерно сомнения. Первой конечно же была статья Мартина Фаулера
B>AnemicDomainModel. Про то что это совсем не правильно когда логика отдельно от данных. А на резонную критику что Model нельзя связывать с внешними сервисами, например DAL. Появилась новая абстракция Repository

Не знаю, как насчет новой... Repository был описан в книжке Фаулера по архитектуре в 2003 г.
"Anemic Domain" Фаулер ругает потому, что логика, природно связанная с бизнес-объектами, выносится куда-то еще, как следствие — повторяется, и получается что-то близкое к процедурному подходу (можете назвать это SOA, легче не станет).

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

DAL — это не совсем внешний сервис, это скорее "внутренний сервис", он ближе к данным и, в принципе с ним могут работать и сами бизнес-объекты. Впрочем, тут есть разные подходы.

Repository — тот, вроде, вообще ортогонален проблеме Anemic Domain — он может применяться как в anemic domain, так и в rich domain. Он позволяет бизнес-логике формулировать "объектные запросы", запросы на выборку бизнес-объектов определенного типа по структурированно заданным критериям. За счет этого связь между DAL и бизнес-логикой становится не такой жесткой, развязывается через Repository.
Очевидный минус — Repository сложно сделать одинаково эффективным для любых выборок. Ручной SQL все равно будет гибче и мощнее и быстрее.

Все вышесказанное — довольно IMHO
Re[2]: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 24.10.07 18:44
Оценка:
Здравствуйте, Igor Trofimov, Вы писали:

iT>Не знаю, как насчет новой... Repository был описан в книжке Фаулера по архитектуре в 2003 г.

Разве? Не припомню. И с сайта Фаулера этот паттерн ссылается на книгу Domain Driven Design, а не Enterprise Patterns.

iT>"Anemic Domain" Фаулер ругает потому, что логика, природно связанная с бизнес-объектами, выносится куда-то еще, как следствие — повторяется, и получается что-то близкое к процедурному подходу (можете назвать это SOA, легче не станет).

В случае Anemic Domain, в модель пихается только та логика которая модет быть ограничена строго этой моделью. Такой логики, обычно, в проектах не так много.

iT>Если вы разделите бизнес-логику на логику домена и логику приложения, то станет видно, что первая — да, должна быть внутри, а вот вторая может быть и выставлена как сервис.

Не очень понял. Логика которая обращается к DAL, она какая из двух?

iT>DAL — это не совсем внешний сервис, это скорее "внутренний сервис", он ближе к данным и, в принципе с ним могут работать и сами бизнес-объекты. Впрочем, тут есть разные подходы.

Да, могут, для этого делается абстракция "репозиторий". Только я хочу понять в чем кайф от такого подхода?

iT>Repository — тот, вроде, вообще ортогонален проблеме Anemic Domain — он может применяться как в anemic domain, так и в rich domain. Он позволяет бизнес-логике формулировать "объектные запросы", запросы на выборку бизнес-объектов определенного типа по структурированно заданным критериям. За счет этого связь между DAL и бизнес-логикой становится не такой жесткой, развязывается через Repository.

Попробую переосознать завтра утром, сейчас все равно не пойму в чем прелесть. И что такое "объектные запросы" и как они связаны с Repository.

iT>Очевидный минус — Repository сложно сделать одинаково эффективным для любых выборок. Ручной SQL все равно будет гибче и мощнее и быстрее.

Брр, про SQL речь вообще не идет. Понятно что бизнес запросы транслируются в SQL через несколько слоев, точто так же понятно что бизнес логика не формирует запросы. Этим занимается DAL, вот только в чем глубинный смысл репозитория в этом процессе, кроме ослабления связи?

iT>Все вышесказанное — довольно IMHO

ОК. Спасибо за мнение, но все равно света в конце тунеля пока не видно.
Re[3]: True OOP&Repository vs Service&AnemicModel
От: Igor Trofimov  
Дата: 24.10.07 19:30
Оценка: 7 (1)
iT>>Не знаю, как насчет новой... Repository был описан в книжке Фаулера по архитектуре в 2003 г.
B>Разве? Не припомню. И с сайта Фаулера этот паттерн ссылается на книгу Domain Driven Design, а не Enterprise Patterns.

с. 341 в русском издании.

B>В случае Anemic Domain, в модель пихается только та логика которая модет быть ограничена строго этой моделью. Такой логики, обычно, в проектах не так много.


В "настоящем" Anemic Domain в модели логики вообще нет. Я не очень понимаю, что значит "логика которая модет быть ограничена строго этой моделью".

Я мыслю так:
При увольнении (Fire()) сотрудника должны быть заблокированы (IsActive=false) все его учетные записи в почте, например. Это логика домена. Она там есть всегда. Независимо от того, какое приложение работает — "главбух" или "директор". Если зацепили увольнение — логика отработает.

А если по кнопке в интерфейсе директора надо "найти всех сотрудников, проработавших меньше полугода и больше одного раза сменивших за время работы руководителя и всех таких — уволить после предварительного отображения списка, и разослать соответствующие письма" — это логика приложения

В Anemic Domain логика блокировки учетных записей будет внутри логики поиска и увольнения "скакунцов" или, может, будет явно включена каки-то вызовом вспомогательного shared метода.
А сами сотрудники будут не сильно умнее DataRow.

iT>>Если вы разделите бизнес-логику на логику домена и логику приложения, то станет видно, что первая — да, должна быть внутри, а вот вторая может быть и выставлена как сервис.

B>Не очень понял. Логика которая обращается к DAL, она какая из двух?

Ну, и та, и та может быть, по идее.

iT>>DAL — это не совсем внешний сервис, это скорее "внутренний сервис", он ближе к данным и, в принципе с ним могут работать и сами бизнес-объекты. Впрочем, тут есть разные подходы.

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

Кайф в том, чтобы когда тебе требуется новый хитрый поиск сотрудников, не нужно было писать еще один Employee[] GetMegaPuperEmployeeList(....) в DAL, у которого внутри зашит конкретный такой SQL, связывая классы AppLogic — DAL еще одной веревочкой. А можно было бы выразить этот запрос на языке объектов и пусть Repository выполнит. Фаулер, кстати, не говорит, а это очень интересно, что Repository может также несколько ИЗМЕНЯТЬ запросы, например, исходя из прав доступа текущего пользователя Добавлять свой аспект.
При этом "клиентская" логика об этом не знает и не заботится.
Re[4]: True OOP&Repository vs Service&AnemicModel
От: Aviator  
Дата: 25.10.07 06:24
Оценка:
Здравствуйте, Igor Trofimov, Вы писали:
iT>Кайф в том, чтобы когда тебе требуется новый хитрый поиск сотрудников, не нужно было писать еще один Employee[] GetMegaPuperEmployeeList(....) в DAL, у которого внутри зашит конкретный такой SQL, связывая классы AppLogic — DAL еще одной веревочкой. А можно было бы выразить этот запрос на языке объектов и пусть Repository выполнит. Фаулер, кстати, не говорит, а это очень интересно, что Repository может также несколько ИЗМЕНЯТЬ запросы, например, исходя из прав доступа текущего пользователя Добавлять свой аспект.
iT>При этом "клиентская" логика об этом не знает и не заботится.

Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени.
Re[4]: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 25.10.07 09:17
Оценка:
Здравствуйте, Igor Trofimov, Вы писали:

iT>с. 341 в русском издании.

Спасибо. Перечитал. Появился вопрос, с учетом современных ORM средств либо DAL, либо Repository становятся бесполезны для работы с БД.

B>>В случае Anemic Domain, в модель пихается только та логика которая модет быть ограничена строго этой моделью. Такой логики, обычно, в проектах не так много.

iT>В "настоящем" Anemic Domain в модели логики вообще нет. Я не очень понимаю, что значит "логика которая модет быть ограничена строго этой моделью".
Ну, к примеру, класс Person. Метод getFullName() ограничивается только использованием свойств и методов класса Person.

iT>При увольнении (Fire()) сотрудника должны быть заблокированы (IsActive=false) все его учетные записи в почте, например. Это логика домена. Она там есть всегда. Независимо от того, какое приложение работает — "главбух" или "директор". Если зацепили увольнение — логика отработает.

Вооот. А если метод StuffService.fire(Employee), то это уже Anemic Domain.

iT>Кайф в том, чтобы когда тебе требуется новый хитрый поиск сотрудников, не нужно было писать еще один Employee[] GetMegaPuperEmployeeList(....) в DAL, у которого внутри зашит конкретный такой SQL, связывая классы AppLogic — DAL еще одной веревочкой. А можно было бы выразить этот запрос на языке объектов и пусть Repository выполнит.

Спасибо, вот это интересно.

iT>Фаулер, кстати, не говорит, а это очень интересно, что Repository может также несколько ИЗМЕНЯТЬ запросы, например, исходя из прав доступа текущего пользователя Добавлять свой аспект.

iT>При этом "клиентская" логика об этом не знает и не заботится.
Не много ли тогда обязанностей станет у репозитория?
Re[5]: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 25.10.07 09:18
Оценка:
Здравствуйте, Aviator, Вы писали:

A>Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени.

В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.
Re: True OOP&Repository vs Service&AnemicModel
От: IB Австрия http://rsdn.ru
Дата: 25.10.07 10:45
Оценка: 56 (8) +3
Здравствуйте, Blazkowicz, Вы писали:

B> SOA вроде как получается?

Угу, примерно так.

B> Про то что это совсем не правильно когда логика отдельно от данных.

Это на самом деле правильно, когда логика отдельно от данных. Дело в том, что срок жизни данных намного дольше, чем срок жизни любой логики навернутой на эти данные. Интерпретация данных (логика) может меняться сколь угдно часто и разнообразно, данные же остаются теми же самыми.
И если у нас данные живут вместе с логикой, то любое изменение логики может отразится и на данных — данные ничем не защищены.
Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность. А это гораздо более практичные аргументы, нежели Фаулеровские абстрактные рассуждения об ООП vs "процедурный стиль", если "процедурный стиль" позволяет проще вносить изменения и поддерживать код, то и байт бы с ним, хоть горшком назови, хотя на самом деле это более чем соответствует принципам ООП.
И если в процессе проектирования и разработки приложения, следуя данному принципу, оказалось, что таки наши Model-объекты действительно состоят из одного лишь голого набора данных, значит так тому и быть. Не следует туда класть дополнительную логику, просто потому, что должна же хоть какая-то логика быть в модели.
Хороший, кстати, пример GetFullName() — очевидно, полное имя может выглядеть по разному, в зависимости от контекста использования, и то как оно выглядит, скорее относится к логике представления, нежели к самому объекту. Хотя первое инстинктивное желание — запихнуть этот метод в сам объект.

Вообще говоря, есть разные типы приложений. И существует огромный класс приложений, где логика полностью независит от данных, которыми оперирует, в этих приложениях "анемичный" дизайн — самый правильный выбор. Сущетвуют так же и другие приложения и их тоже не мало, где следуя критерию Меерса, получается вполне себе Фаулеровская Rich Domain Model.

Это я все к тому, что Мартин, конечно, умный дядька, но периодически его заносит.. Ну или народ интерпретирует его высказывания с излишним энтузиазмом.. =)
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[2]: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 25.10.07 10:51
Оценка:
Здравствуйте, IB, Вы писали:

B>> Про то что это совсем не правильно когда логика отдельно от данных.

IB>Это на самом деле правильно, когда логика отдельно от данных...
В том-то и проблема что все вышесказаное тобой я чудесно понимаю и осознаю. Сейчас мне хочется понять противников этого подходя дабы расширить кругозор. Может удастся подчерпнуть что-то полезное для себя.

IB>Это я все к тому, что Мартин, конечно, умный дядька, но периодически его заносит.. Ну или народ интерпретирует его высказывания с излишним энтузиазмом.. =)

Это высказывание в разнах интерпретациях, ты тут уже минимум 3й раз постишь.
Re: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 25.10.07 11:15
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

Ещё ссылки если кому интересно.
Spring 2.0 vs. the Anemic Domain Model
Обсуждение

Большинство высказываний так же склоняются к тому что Anemic Domain Model и Repository это булшит.
Есть так же интересное замечание, что предлагаемый принцип превращает Anemic Domain Model в Active Record. Тоже, подход, который себя не оправдывает.
Re[2]: True OOP&Repository vs Service&AnemicModel
От: b_manvelyan Украина  
Дата: 25.10.07 11:22
Оценка:
Здравствуйте, IB, Вы писали:
IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность.

А что за Меерс и где он эти утверждения выдвигает, можно поточнее ссылочку?
Re[3]: True OOP&Repository vs Service&AnemicModel
От: IB Австрия http://rsdn.ru
Дата: 25.10.07 12:18
Оценка:
Здравствуйте, b_manvelyan, Вы писали:

_>А что за Меерс и где он эти утверждения выдвигает, можно поточнее ссылочку?

Scott Meyers, автор Effective C++, More Effective C++ и других замечательных и полезных книг и статей.

I've been battling programmers who've taken to heart the lesson that being object-oriented means putting functions inside the classes containing the data on which the functions operate. After all, they tell me, that's what encapsulation is all about.

They are mistaken.

(c) S. Meyers
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[6]: True OOP&Repository vs Service&AnemicModel
От: Aviator  
Дата: 25.10.07 19:15
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

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


A>>Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени.

B>В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.
Да, он там есть, но тогда вы завязываетесь на NHibernate, да и весь смысл репозитария пропадает.
Re[2]: True OOP&Repository vs Service&AnemicModel
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.10.07 05:08
Оценка: :))) :))) :)
Здравствуйте, IB, Вы писали:
Короче, можно уже смело оперировать термином "пост-Фаулеровские подходы к архитектуре".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: True OOP&Repository vs Service&AnemicModel
От: Blazkowicz Россия  
Дата: 26.10.07 09:25
Оценка:
Здравствуйте, Aviator, Вы писали:

B>>В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.

A>Да, он там есть, но тогда вы завязываетесь на NHibernate,
У нас, в Java, все завязываются на Hibernate и никто от этого особо не страдает.

A>да и весь смысл репозитария пропадает.

Да, как я и говорил выше. При использовании Hibernate (или подобноего инструментария) либо Repository, либо DAO остаются без функциональности.
Re[2]: True OOP&Repository vs Service&AnemicModel
От: Aviator  
Дата: 26.10.07 14:13
Оценка:
Здравствуйте, IB, Вы писали:

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


B>> SOA вроде как получается?

IB>Угу, примерно так.


IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность. А это гораздо более практичные аргументы, нежели Фаулеровские абстрактные рассуждения об ООП vs "процедурный стиль", если "процедурный стиль" позволяет проще вносить изменения и поддерживать код, то и байт бы с ним, хоть горшком назови, хотя на самом деле это более чем соответствует принципам ООП.

А где конкретно майерс рассматривает этот вопрос?
Re[6]: True OOP&Repository vs Service&AnemicModel
От: Igor Trofimov  
Дата: 26.10.07 17:37
Оценка:
B>В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.

Ага. И, по сути, Hibernate реализует паттерны Query и Repository
Собственно, они обычно тесно связаны.
Re[2]: True OOP&Repository vs Service&AnemicModel
От: dshe  
Дата: 30.11.07 15:33
Оценка:
Здравствуйте, IB, Вы писали:

IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность.


Раз уж поднялась тема попробую возразить. На самом деле любую логику можно реализовать без доступа к приватным данным объекта, если эти данные выставленны наружу при помощи get'еров и set'еров. Смысл тогда делать данные приватными? Не проще ли сразу объявлять их паблик?
--
Дмитро
Re[3]: True OOP&Repository vs Service&AnemicModel
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.11.07 20:34
Оценка: +2
Здравствуйте, dshe, Вы писали:

D>Раз уж поднялась тема попробую возразить. На самом деле любую логику можно реализовать без доступа к приватным данным объекта, если эти данные выставленны наружу при помощи get'еров и set'еров. Смысл тогда делать данные приватными? Не проще ли сразу объявлять их паблик?


А есть еще принцип минимизации публичного контракта. А есть еще специфика реализации конкретного контракта, отличная от других реализаций этого же самого контракта. Тут главное понять — никакие принципы и теории не спасают от включения верхней головы.
... << RSDN@Home 1.2.0 alpha rev. 725 on Windows Vista 6.0.6000.0>>
AVK Blog
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.