Так уж сложилось что сейчас большинство новых серверных приложений, которые приходится видеть, дизайнятся следующим образом.
Model — тупые контейнеры данных реализующие бизнес-сущности
Service — реализация бизнес-логики, которая оперирует Model и работает с другими слоями системы в т.ч. DAL/DAO
И вроде бы все красиво и приятно. Модель часто удается протащить сквозь все уровни приложения (Persistance, Service, RCP и даже View). Service же легким движением руки можно выставить наружу как RPC или использовать другими компонентами. SOA вроде как получается?
Внимание вопрос. Кто-нибудь может внятно объяснить, или ткнуть носом чем второй подход с внедрением бесполезного слоя Repository лучше чем Anemic Model? В приведенных ссылках ни одного понятного мне объяснения не нашел. На счет упрощеного тестирования тоже не согласен, вроде и при первом подходе серьезных проблем с юнит тестами не возникало. Если кто читал книгу DDD, буду благодарен за указание главы, где можно подчерпнуть недостающее знание по интересующему вопросу.
B>Но вновь и вновь появляется материал сеющий зерно сомнения. Первой конечно же была статья Мартина Фаулера B>AnemicDomainModel. Про то что это совсем не правильно когда логика отдельно от данных. А на резонную критику что Model нельзя связывать с внешними сервисами, например DAL. Появилась новая абстракция Repository
Не знаю, как насчет новой... Repository был описан в книжке Фаулера по архитектуре в 2003 г.
"Anemic Domain" Фаулер ругает потому, что логика, природно связанная с бизнес-объектами, выносится куда-то еще, как следствие — повторяется, и получается что-то близкое к процедурному подходу (можете назвать это SOA, легче не станет).
Если вы разделите бизнес-логику на логику домена и логику приложения, то станет видно, что первая — да, должна быть внутри, а вот вторая может быть и выставлена как сервис.
DAL — это не совсем внешний сервис, это скорее "внутренний сервис", он ближе к данным и, в принципе с ним могут работать и сами бизнес-объекты. Впрочем, тут есть разные подходы.
Repository — тот, вроде, вообще ортогонален проблеме Anemic Domain — он может применяться как в anemic domain, так и в rich domain. Он позволяет бизнес-логике формулировать "объектные запросы", запросы на выборку бизнес-объектов определенного типа по структурированно заданным критериям. За счет этого связь между DAL и бизнес-логикой становится не такой жесткой, развязывается через Repository.
Очевидный минус — Repository сложно сделать одинаково эффективным для любых выборок. Ручной SQL все равно будет гибче и мощнее и быстрее.
Здравствуйте, 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
ОК. Спасибо за мнение, но все равно света в конце тунеля пока не видно.
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 может также несколько ИЗМЕНЯТЬ запросы, например, исходя из прав доступа текущего пользователя Добавлять свой аспект.
При этом "клиентская" логика об этом не знает и не заботится.
Здравствуйте, Igor Trofimov, Вы писали: iT>Кайф в том, чтобы когда тебе требуется новый хитрый поиск сотрудников, не нужно было писать еще один Employee[] GetMegaPuperEmployeeList(....) в DAL, у которого внутри зашит конкретный такой SQL, связывая классы AppLogic — DAL еще одной веревочкой. А можно было бы выразить этот запрос на языке объектов и пусть Repository выполнит. Фаулер, кстати, не говорит, а это очень интересно, что Repository может также несколько ИЗМЕНЯТЬ запросы, например, исходя из прав доступа текущего пользователя Добавлять свой аспект. iT>При этом "клиентская" логика об этом не знает и не заботится.
Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени.
Здравствуйте, 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>При этом "клиентская" логика об этом не знает и не заботится.
Не много ли тогда обязанностей станет у репозитория?
Здравствуйте, Aviator, Вы писали:
A>Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени.
В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.
Здравствуйте, Blazkowicz, Вы писали:
B> SOA вроде как получается?
Угу, примерно так.
B> Про то что это совсем не правильно когда логика отдельно от данных.
Это на самом деле правильно, когда логика отдельно от данных. Дело в том, что срок жизни данных намного дольше, чем срок жизни любой логики навернутой на эти данные. Интерпретация данных (логика) может меняться сколь угдно часто и разнообразно, данные же остаются теми же самыми.
И если у нас данные живут вместе с логикой, то любое изменение логики может отразится и на данных — данные ничем не защищены.
Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность. А это гораздо более практичные аргументы, нежели Фаулеровские абстрактные рассуждения об ООП vs "процедурный стиль", если "процедурный стиль" позволяет проще вносить изменения и поддерживать код, то и байт бы с ним, хоть горшком назови, хотя на самом деле это более чем соответствует принципам ООП.
И если в процессе проектирования и разработки приложения, следуя данному принципу, оказалось, что таки наши Model-объекты действительно состоят из одного лишь голого набора данных, значит так тому и быть. Не следует туда класть дополнительную логику, просто потому, что должна же хоть какая-то логика быть в модели.
Хороший, кстати, пример GetFullName() — очевидно, полное имя может выглядеть по разному, в зависимости от контекста использования, и то как оно выглядит, скорее относится к логике представления, нежели к самому объекту. Хотя первое инстинктивное желание — запихнуть этот метод в сам объект.
Вообще говоря, есть разные типы приложений. И существует огромный класс приложений, где логика полностью независит от данных, которыми оперирует, в этих приложениях "анемичный" дизайн — самый правильный выбор. Сущетвуют так же и другие приложения и их тоже не мало, где следуя критерию Меерса, получается вполне себе Фаулеровская Rich Domain Model.
Это я все к тому, что Мартин, конечно, умный дядька, но периодически его заносит.. Ну или народ интерпретирует его высказывания с излишним энтузиазмом.. =)
Здравствуйте, IB, Вы писали:
B>> Про то что это совсем не правильно когда логика отдельно от данных. IB>Это на самом деле правильно, когда логика отдельно от данных...
В том-то и проблема что все вышесказаное тобой я чудесно понимаю и осознаю. Сейчас мне хочется понять противников этого подходя дабы расширить кругозор. Может удастся подчерпнуть что-то полезное для себя.
IB>Это я все к тому, что Мартин, конечно, умный дядька, но периодически его заносит.. Ну или народ интерпретирует его высказывания с излишним энтузиазмом.. =)
Это высказывание в разнах интерпретациях, ты тут уже минимум 3й раз постишь.
Большинство высказываний так же склоняются к тому что Anemic Domain Model и Repository это булшит.
Есть так же интересное замечание, что предлагаемый принцип превращает Anemic Domain Model в Active Record. Тоже, подход, который себя не оправдывает.
Здравствуйте, IB, Вы писали: IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность.
А что за Меерс и где он эти утверждения выдвигает, можно поточнее ссылочку?
Здравствуйте, 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.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, Aviator, Вы писали:
A>>Ну вроде от необходимости писать кучи методов в стиле GetMegaPuperEmployeeList частично спасает применение Query Object. Проблема в том, что для его более-менее полной реализации нужно потратить вероятно достаточно много сил и времени. B>В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object.
Да, он там есть, но тогда вы завязываетесь на NHibernate, да и весь смысл репозитария пропадает.
Здравствуйте, Aviator, Вы писали:
B>>В Hibernate он уже есть, не самый распрекрасный, но достаточно приемлимый Query Object. A>Да, он там есть, но тогда вы завязываетесь на NHibernate,
У нас, в Java, все завязываются на Hibernate и никто от этого особо не страдает.
A>да и весь смысл репозитария пропадает.
Да, как я и говорил выше. При использовании Hibernate (или подобноего инструментария) либо Repository, либо DAO остаются без функциональности.
Здравствуйте, IB, Вы писали:
IB>Здравствуйте, Blazkowicz, Вы писали:
B>> SOA вроде как получается? IB>Угу, примерно так.
IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность. А это гораздо более практичные аргументы, нежели Фаулеровские абстрактные рассуждения об ООП vs "процедурный стиль", если "процедурный стиль" позволяет проще вносить изменения и поддерживать код, то и байт бы с ним, хоть горшком назови, хотя на самом деле это более чем соответствует принципам ООП.
А где конкретно майерс рассматривает этот вопрос?
Здравствуйте, IB, Вы писали:
IB>Фаулер, критикуя плоские объекты не содержащие логики не выдвигает никакого формального критерия, какую же логику считать принадлежащей объекту, а какую внешнему сервису. А вот, например, Меерс — выдвигает, и критерий этот достаточно прост: если логика может быть реализована без доступа к приватным данным объекта, значит эта логика должна содержаться не в объекте, а во внешнем сервисе, потому что в противном случае ослабляется инкапсуляция и увеличивается связность.
Раз уж поднялась тема попробую возразить. На самом деле любую логику можно реализовать без доступа к приватным данным объекта, если эти данные выставленны наружу при помощи get'еров и set'еров. Смысл тогда делать данные приватными? Не проще ли сразу объявлять их паблик?
Здравствуйте, dshe, Вы писали:
D>Раз уж поднялась тема попробую возразить. На самом деле любую логику можно реализовать без доступа к приватным данным объекта, если эти данные выставленны наружу при помощи get'еров и set'еров. Смысл тогда делать данные приватными? Не проще ли сразу объявлять их паблик?
А есть еще принцип минимизации публичного контракта. А есть еще специфика реализации конкретного контракта, отличная от других реализаций этого же самого контракта. Тут главное понять — никакие принципы и теории не спасают от включения верхней головы.
... << RSDN@Home 1.2.0 alpha rev. 725 on Windows Vista 6.0.6000.0>>