Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 23.12.07 11:11
Оценка: 1 (1)
Изучаю Java/Spring/Hibernate и возник следующий архитектурный вопрос.

Часто, при просмотре примеров как из комплекта Hibernate, так и из комплекта Spring, можно обнаружить агрегатную реализацию классов в Domain Layer — как в следующем простейшем примере:

public class Entry {
  int id;
  String text;  
  ...
  // Иногда тут еще ставят и родительскую ссылку типа  
  // User user;
}

public class User {
  int id;
  String name;
  ...
  Set<Entry> entries;
}


И вводят соответствующий контракт для DAO слоя:

public interface AbstractUserDao {
  ...
  List<User> getSomeUsers(String criteria);
  ...
}


При реализации DAO на основе Hibernate при подгрузке объектов класса User мы можем выбрать: будем ли мы подгружать внутреннюю коллекцию entries сразу, или же она будет подгружаться при непосредственном обращении к элементам коллекции (Hibernate заменяет класс коллекции на свой) — по одной записи или пачками.

Если мы отбросим теоретизирование и решаемся полностью завязаться на Hibernate — то вопросов нет.

Но! Что же делать, если все таки мы хотим спроектировать систему с возможностью легкой замены реализации DAO — например на iBatis или JDBC? Эти системы не так изощренны как Hibernate и у нас остается только два выбора (?) — не грузить внутреннюю коллекцию entries вообще, и тогда все сервисы будут натыкаться на полное отсутствие элементов; либо, наоборот — грузить все полностью, но тут возникает проблема с быстродействием, пожиранием памяти, а что еще хуже, у внутренних объектов могут быть другие внутренние объекты или даже циклические связи, что вообще никак не решается.

Получается, что, в общем стратегическо-архитектурном подходе агрегаты лучше не делать? То есть, убрать коллекцию entries из класса User, а для ее получения сервисы пусть принудительно дергают специальный метод?

public interface AbstractUserDao {
  ...
  List<User> getSomeUsers(String criteria);
  List<Entry> getUserEntries(int userId);
  ...
}


И не является ли лишним подтверждением правоты такого подхода — то, что в книжке Domain Driven Design не рекомендуют агрегировать одни глобальные Entity в другие глобальные Entity (в нашем случае и User и Entry — являются глобальными с уникальными ID)?

Просветите насчет агрегатов в Domain Layer — стоит ли следовать примерам из Spring/Hibernate или нет?




23.12.07 17:50: Перенесено модератором из 'Java' — Blazkowicz
Re: Аггрегаты в Domain Layer и универсальное DAO
От: Trean Беларусь http://axamit.com/
Дата: 23.12.07 16:35
Оценка:
Здравствуйте, mazurkin, Вы писали:

M>При реализации DAO на основе Hibernate при подгрузке объектов класса User мы можем выбрать: будем ли мы подгружать внутреннюю коллекцию entries сразу, или же она будет подгружаться при непосредственном обращении к элементам коллекции (Hibernate заменяет класс коллекции на свой) — по одной записи или пачками.


M>Если мы отбросим теоретизирование и решаемся полностью завязаться на Hibernate — то вопросов нет.


M>Но! Что же делать, если все таки мы хотим спроектировать систему с возможностью легкой замены реализации DAO — например на iBatis или JDBC? Эти системы не так изощренны как Hibernate и у нас остается только два выбора (?) — не грузить внутреннюю коллекцию entries вообще, и тогда все сервисы будут натыкаться на полное отсутствие элементов; либо, наоборот — грузить все полностью, но тут возникает проблема с быстродействием, пожиранием памяти, а что еще хуже, у внутренних объектов могут быть другие внутренние объекты или даже циклические связи, что вообще никак не решается.


M>И не является ли лишним подтверждением правоты такого подхода — то, что в книжке Domain Driven Design не рекомендуют агрегировать одни глобальные Entity в другие глобальные Entity (в нашем случае и User и Entry — являются глобальными с уникальными ID)?


M>Просветите насчет агрегатов в Domain Layer — стоит ли следовать примерам из Spring/Hibernate или нет?


Зерно правды есть, хотя я думаю небходимости переводить целиком DAO переводить с Hibernate-реализации на JDBC нет. Кроме того у Hibernate точнее у любого ORM с lazy-loading есть концептуальная проблема с отдачей объектов с lazy-объектами или коллекциями во view или при сериализации. Приходится использовать или session in view (что не есть гуд), принудительную инициализацию коллекции через initialize, что может также, привести к печальным последствиям для производительности, заменять lazy коллекции на пустые (ломает ОО-дизайн). В принципе, та же фигня — вид сбоку.
Re[2]: Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 23.12.07 19:45
Оценка:
T>Зерно правды есть, хотя я думаю небходимости переводить целиком DAO переводить с Hibernate-реализации на JDBC нет. Кроме того у Hibernate точнее у любого ORM с lazy-loading есть концептуальная проблема с отдачей объектов с lazy-объектами или коллекциями во view или при сериализации. Приходится использовать или session in view (что не есть гуд), принудительную инициализацию коллекции через initialize, что может также, привести к печальным последствиям для производительности, заменять lazy коллекции на пустые (ломает ОО-дизайн). В принципе, та же фигня — вид сбоку.

Про перевод я имел в виду не какую-то практическую необходимость, а то, каким образом лучше проектировать, чтобы максимально отвязаться от особенностей DAO слоя — чтобы потом можно было выбирать и реализовывать.

А, кстати, что не так с "session in view"? В книжке "Hibernate In Action" он вроде приведен как вполне рабочий вариант?
Re: Аггрегаты в Domain Layer и универсальное DAO
От: Blazkowicz Россия  
Дата: 24.12.07 13:25
Оценка:
Здравствуйте, mazurkin, Вы писали:

M>Но! Что же делать, если все таки мы хотим спроектировать систему с возможностью легкой замены реализации DAO — например на iBatis или JDBC? Эти системы не так изощренны как Hibernate и у нас остается только два выбора (?)

ИМХО, написать соответствующую проксю для JDBС не так сложно. Только зачем это нужно если Hibernate умеет работать даже с низкоуровневыми запросами? Вообще такая радикальная смена уровня приложения встречается крайне редко.

M>- не грузить внутреннюю коллекцию entries вообще, и тогда все сервисы будут натыкаться на полное отсутствие элементов;

Это вообще не выход. Полностью убивается весь готовый код.

M>либо, наоборот — грузить все полностью, но тут возникает проблема с быстродействием, пожиранием памяти, а что еще хуже, у внутренних объектов могут быть другие внутренние объекты или даже циклические связи, что вообще никак не решается.

Ну, когда вы пишете на JDBC, то и сами разруливаете что грузить, и как делать циклические связи. В принципе не так сложно и написать методы подргужающее нужного размера дерево для каждого случая. Но это стремительно усложнти весь слой работы с базой.

M>Получается, что, в общем стратегическо-архитектурном подходе агрегаты лучше не делать? То есть, убрать коллекцию entries из класса User, а для ее получения сервисы пусть принудительно дергают специальный метод?

Почему ты исключаешь написание собственного прокси? Это не так сложно.

M>И не является ли лишним подтверждением правоты такого подхода — то, что в книжке Domain Driven Design не рекомендуют агрегировать одни глобальные Entity в другие глобальные Entity (в нашем случае и User и Entry — являются глобальными с уникальными ID)?

А есть цитата из книги? Или ссылка на главу? Что такое глобальная сущность? Которая пересекает несколько слоев?

M>Просветите насчет агрегатов в Domain Layer — стоит ли следовать примерам из Spring/Hibernate или нет?

Вы можете придумать хоть одну причину отказатся от Hibernate в пользу какого-нибудь другого решения?
Re[3]: Аггрегаты в Domain Layer и универсальное DAO
От: Trean Беларусь http://axamit.com/
Дата: 24.12.07 13:25
Оценка:
Здравствуйте, mazurkin, Вы писали:

T>>Зерно правды есть, хотя я думаю небходимости переводить целиком DAO переводить с Hibernate-реализации на JDBC нет. Кроме того у Hibernate точнее у любого ORM с lazy-loading есть концептуальная проблема с отдачей объектов с lazy-объектами или коллекциями во view или при сериализации. Приходится использовать или session in view (что не есть гуд), принудительную инициализацию коллекции через initialize, что может также, привести к печальным последствиям для производительности, заменять lazy коллекции на пустые (ломает ОО-дизайн). В принципе, та же фигня — вид сбоку.


M>Про перевод я имел в виду не какую-то практическую необходимость, а то, каким образом лучше проектировать, чтобы максимально отвязаться от особенностей DAO слоя — чтобы потом можно было выбирать и реализовывать.


Если отказаться от коллекций, то определенно будет проще.

M>А, кстати, что не так с "session in view"? В книжке "Hibernate In Action" он вроде приведен как вполне рабочий вариант?


Open Session in View работает только, когда при рендеринге используется локальная сессия, если рендеринг делается на другом контейнере, то автоматом лишаемся транзакций. Вторая проблема, это то что увеличивается длительность транзакции, которая открыта все время, пока рендерится страница. Короче надо пользоваться осторожно иначе можно отгрести проблемы с масштабированием.
Re[2]: Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 24.12.07 16:56
Оценка:
B>ИМХО, написать соответствующую проксю для JDBС не так сложно. Только зачем это нужно если Hibernate умеет работать даже с низкоуровневыми запросами? Вообще такая радикальная смена уровня приложения встречается крайне редко.
B>Вы можете придумать хоть одну причину отказатся от Hibernate в пользу какого-нибудь другого решения?

Я спрашиваю больше про теоретическое проектирование (можете вспомнить про сферический вакуум ). У меня нет никаких проблем с освоением Hibernate — я хочу понять как правильно проектировать гибкие системы.

Хотя наверное причиной можно привести, например, уже существующую БД, которая спроектирована не лучшим образом — насколько я понимаю iBatis сдесь более уместен? А вдруг после того как приложение уже сделано, БД решили перепроектировать и переключиться на Hibernate как более простой?

M>>- не грузить внутреннюю коллекцию entries вообще, и тогда все сервисы будут натыкаться на полное отсутствие элементов;

B>Это вообще не выход. Полностью убивается весь готовый код.
M>>либо, наоборот — грузить все полностью, но тут возникает проблема с быстродействием, пожиранием памяти, а что еще хуже, у внутренних объектов могут быть другие внутренние объекты или даже циклические связи, что вообще никак не решается.
B>Ну, когда вы пишете на JDBC, то и сами разруливаете что грузить, и как делать циклические связи. В принципе не так сложно и написать методы подргужающее нужного размера дерево для каждого случая. Но это стремительно усложнти весь слой работы с базой.

Так вот и я про это же самое говорю...

M>>Получается, что, в общем стратегическо-архитектурном подходе агрегаты лучше не делать? То есть, убрать коллекцию entries из класса User, а для ее получения сервисы пусть принудительно дергают специальный метод?

B>Почему ты исключаешь написание собственного прокси? Это не так сложно.

Вы имеете в виду прокси для класса в Domain Layer? В принципе, тоже наверное подход, только сложновато.

M>>И не является ли лишним подтверждением правоты такого подхода — то, что в книжке Domain Driven Design не рекомендуют агрегировать одни глобальные Entity в другие глобальные Entity (в нашем случае и User и Entry — являются глобальными с уникальными ID)?

B>А есть цитата из книги? Или ссылка на главу? Что такое глобальная сущность? Которая пересекает несколько слоев?

Глава 6. Aggregates — Насколько я ее понимаю. Вот, например, абзац, хотя лучше конечно прочитать все.

First we need an abstraction for encapsulating references within the model. An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE. The root is the only member of the AGGREGATE that outside objects are allowed to hold references to, although objects within the boundary may hold references to each other. ENTITIES other than the root have local identity, but that identity needs to be distinguishable only within the AGGREGATE, because no outside object can ever see it out of the context of the root ENTITY.

Вы наверное, меня не совсем правильно поняли. Я пока ничего не программирую и не проектирую Я изучаю Spring и иже с ним, и пока нахожусь в полном восторге Хочу понять общие принципы и закономерности, а не частные практические решения — потому как последние способен освоить и без посторонней помощи По затронутому мной вопросу меня интересуют multi-DAO примеры, в частности пример из замечательно книжки Pro Spring, где мирно параллельно уживаются hibernate, ibatis и jdbc. В этом простом примере реализован компромиссный принцип: cущности агрегируются и подгружаются все внутренние коллекции целиком (во всех упомянутых реализациях DAO) — но агрегируются только те и так, чтобы при полной подгрузке не создавать особых проблем (предполагается, что объектов во внутренних коллекциях будет не много). Это контрастирует с чисто Hibernate примерами, где в Domain Layer почти все ссылается на все, в том числе и обоюдными связи — потому как Hibernate делает всю работу в фоне.

Вот я и пытаюсь понять все особенности — а чтобы понять особенности — в первую очередь пытаюсь вывести некий "общий делитель".
Re[4]: Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 24.12.07 16:57
Оценка:
M>>А, кстати, что не так с "session in view"? В книжке "Hibernate In Action" он вроде приведен как вполне рабочий вариант?
T>Open Session in View работает только, когда при рендеринге используется локальная сессия, если рендеринг делается на другом контейнере, то автоматом лишаемся транзакций. Вторая проблема, это то что увеличивается длительность транзакции, которая открыта все время, пока рендерится страница. Короче надо пользоваться осторожно иначе можно отгрести проблемы с масштабированием.

Ага, спасибо, буду иметь в виду, если будет крупный проект. В книжках, почему-то про это не пишут
Re[2]: Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 24.12.07 17:06
Оценка:
B>Вы можете придумать хоть одну причину отказатся от Hibernate в пользу какого-нибудь другого решения?

Во, придумал! Спрошу у практиков так: влияет ли (или должно ли влиять) наличие (или отсутствие) ORM-технологии с lazy-loading на способ реализации Domain Layer, а конкретно — на количество и интенсивность внутренних связей в его классах?
Re[3]: Аггрегаты в Domain Layer и универсальное DAO
От: Blazkowicz Россия  
Дата: 24.12.07 18:19
Оценка:
Здравствуйте, mazurkin, Вы писали:

B>>Вы можете придумать хоть одну причину отказатся от Hibernate в пользу какого-нибудь другого решения?


M>Во, придумал! Спрошу у практиков так: влияет ли (или должно ли влиять) наличие (или отсутствие) ORM-технологии с lazy-loading на способ реализации Domain Layer, а конкретно — на количество и интенсивность внутренних связей в его классах?


Хороший тул не должен влиять на вашу бизнес модель. Хороший тул он по тому и хороший что натягшивается на максимальное количество моделей. Конечно абсолютно хороших инструментов мало. Даже хибер с его маппингом частенько диктуют как сделать класс или таблицу. Но это очень минимальное влияние.
Re[3]: Аггрегаты в Domain Layer и универсальное DAO
От: Blazkowicz Россия  
Дата: 24.12.07 18:39
Оценка:
Здравствуйте, mazurkin, Вы писали:


M>Хотя наверное причиной можно привести, например, уже существующую БД, которая спроектирована не лучшим образом — насколько я понимаю iBatis сдесь более уместен?

Не верно. Hibernate 3 был разработан специально для того чтобы натягивать ненатягиваемое (маппить криво спроектированые таблицы)

M>Вы имеете в виду прокси для класса в Domain Layer? В принципе, тоже наверное подход, только сложновато.

Что сложного? Пишешь прокси для бинов. Перехватываешь соответствующие геттеры. Нет зависимости, проверил класс, спросил DAO. Есть зависимость — отдал. Ничуть не сложнее чем отказыватся от методов getEntity().getAnotherEntity в пользу
dao.loadEntity()
dao.loadAnotherEntity(Entity)

К тому же такой подход полностью исключает fetching, когда ты можешь одним запросом загрузить обе сущности через join.


M>Глава 6. Aggregates — Насколько я ее понимаю. Вот, например, абзац, хотя лучше конечно прочитать все.


Спасибо. Найдем, будем посмотреть.

M>В этом простом примере реализован компромиссный принцип: cущности агрегируются и подгружаются все внутренние коллекции целиком (во всех упомянутых реализациях DAO) — но агрегируются только те и так, чтобы при полной подгрузке не создавать особых проблем (предполагается, что объектов во внутренних коллекциях будет не много). Это контрастирует с чисто Hibernate примерами, где в Domain Layer почти все ссылается на все, в том числе и обоюдными связи — потому как Hibernate делает всю работу в фоне.


Теперь ты ещё больше меня запутал. Объясняю оптимальный вариант на примере хибера. В случае других решений подобные походы реализовать не так уже и сложно.
Агрегируется все что только можно. Таким образом бизнес логика может достать все нужные зависимости без проблем. Все зависимости подгружаются лениво, чтобы уменьшить memory footprint. Такой подход вырождается в большее количество запросов. Тогда для каждого конкретного случая dao методы оптимизируются чтобы подгружать зависимости за раз, там где это действительно нужно. Так улучшается производительность, не увеличивая затраты памяти.
Подобный подход не сложно применить даже если все реализовано на JDBC.
Re: Аггрегаты в Domain Layer и универсальное DAO
От: malkolinge Украина  
Дата: 25.12.07 15:33
Оценка:
А это не всегда агрегация. в т.ч коллекция может представлять "ассоциированые" или слабоагрегированные поля. Чистая агрегация — это когда время жизни у агрегата и агрегируемых объектов одинаковое.
Re[2]: Аггрегаты в Domain Layer и универсальное DAO
От: mazurkin http://mazurkin.info
Дата: 07.01.08 13:37
Оценка:
M>А это не всегда агрегация. в т.ч коллекция может представлять "ассоциированые" или слабоагрегированные поля. Чистая агрегация — это когда время жизни у агрегата и агрегируемых объектов одинаковое.

Да, вы правы. Но в данной ситуации, во-первых сути дела не меняет, а во-вторых если внутренние коллекции и ссылки существуют только в одном экземпляре — то зачастую (но далеко не всегда) так и происходит.

B>Теперь ты ещё больше меня запутал. Объясняю оптимальный вариант на примере хибера. В случае других решений подобные походы реализовать не так уже и сложно. Агрегируется все что только можно. Таким образом бизнес логика может достать все нужные зависимости без проблем. Все зависимости подгружаются лениво, чтобы уменьшить memory footprint. Такой подход вырождается в большее количество запросов. Тогда для каждого конкретного случая dao методы оптимизируются чтобы подгружать зависимости за раз, там где это действительно нужно. Так улучшается производительность, не увеличивая затраты памяти.

Подобный подход не сложно применить даже если все реализовано на JDBC.

Все верно! Я бы тоже так сделал!

Но, теперь представим, что "сверху" приходит решение об отказе от Hibernate и переходе на чистый JDBC с использованием инфраструктуры Spring. Почему? — не знаю, придумайте сами причину — JDBC и "никаких гвоздей"! Ваши действия в данном случае?

Уменьшить плотность связей и делать модель "разряженной"? То есть мы приходим к выводу, что построение domain-layer зависит от того, есть ли у нас lazy-loading или нет?

Или, как вы говорите, самому наделать прокси-оберток вокруг классов из domain-layer — тогда каким образом и с помощью какой технологии?
Re[3]: Аггрегаты в Domain Layer и универсальное DAO
От: Blazkowicz Россия  
Дата: 09.01.08 14:26
Оценка:
Здравствуйте, mazurkin, Вы писали:

M>Или, как вы говорите, самому наделать прокси-оберток вокруг классов из domain-layer — тогда каким образом и с помощью какой технологии?

Собсвенно так же как и у всех:
java.lang.reflect.Proxy
CGLIB
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.