Здравствуйте, dimgel, Вы писали:
D>М-да, хоть и не собирался отвечать, но мимо этого бреда пройти невозможно. Не будет счётчика ссылок, не будет соответствующего кода в entity.
А какой будет? Напоминаю:
server_mouse: Отделение BL от данных и выделение отдельной группы объектов-data-контейнеров. Где же тогда инкапсуляция? Правильно — в Ж.
IB: А в данном случае, с инкапсуляцией все в порядке.
dimgel: Бояре сумлеваются. Редуцировать entities до структур... я лучше уж DTO добавлю (в качестве базовых классов entities).
Внимание, вопрос: какими критериями лично ты руководствуешься при определении, какой метод стоит поместить в бизнес-объект, а какой туда помещать не стоит?
D>Даже если это остальное не делает ничего, кроме как делегирует к методам обсновного объекта?
Зависит от. Я уже говорил, что откровенный примитив лучше оставить по месту до лучших времен. В остальных случаях -- выношу.
D>При отсутствии дополнительных выгод, упоминания которых я жду с открытым ртом, этот принцип называется "заставь дурака богу молиться".
Примитивные случаи не рассматриваем. Во всех остальных: каждый объект обладает строго ограниченной зоной ответственности (его изменение не порождает каскад изменений в остальных частях системы; упрощается разработка и поддержка, поскольку в каждый момент времени программиск концентриуется на строго определенном куске функциональности, не захламленном поддерживающим кодом), повторное использование (обратно из-за того, что модуль обеспечивает строго определенную функциональность), упрощается модульное тестирование.
Достаточно?
HgLab: Mercurial Server and Repository Management for Windows
Здравствуйте, Нахлобуч, Вы писали:
Н>Внимание, вопрос: какими критериями лично ты руководствуешься при определении, какой метод стоит поместить в бизнес-объект, а какой туда помещать не стоит?
Вот же ж чёрт... В десятый раз повторяю: я позволяю себе из entity работать с другими entities. И больше ни с чем — ни с email-оповещалками, ни с UI, ни со слоем BL, который за всё это отвечает. То есть, если взять все entities и обозвать их отдельным слоем, то содержащийся в нём код не обращается ни к чему за его слоя. Но внутри этого слоя я действую по принципу минимизации количества вспомогательных объектов и делегирования, поскольку BL в любом случае имеет доступ к entities, так что ему всё равно, а выше BL я entities не пускаю, интерфейс BL сформулирован в терминах DTO.
D>>Даже если это остальное не делает ничего, кроме как делегирует к методам обсновного объекта?
Н>Зависит от. Я уже говорил, что откровенный примитив лучше оставить по месту до лучших времен. В остальных случаях -- выношу.
Ок.
D>>При отсутствии дополнительных выгод, упоминания которых я жду с открытым ртом, этот принцип называется "заставь дурака богу молиться".
Н>Примитивные случаи не рассматриваем. Во всех остальных: каждый объект обладает строго ограниченной зоной ответственности (его изменение не порождает каскад изменений в остальных частях системы; упрощается разработка и поддержка, поскольку в каждый момент времени программиск концентриуется на строго определенном куске функциональности, не захламленном поддерживающим кодом), повторное использование (обратно из-за того, что модуль обеспечивает строго определенную функциональность), упрощается модульное тестирование.
Н>Достаточно?
Да, наверное... Похоже, мы спорим ни о чём. Щас можно было бы увязнуть в пустозвонстве на тему "что такое зона ответственности", но думаю, все эти вопросы не имеют смысла вне конкретики. Насчёт системы документооборота ты конечно погорячился — даже элементарное ТЗ в виде списка допустимых операций составлять — не одну минуту, а прикидывать, как этот список операций раскидать — и того дольше. Но я уже приводил совершенно конкретный пример достаточно сложной и реалистичной операции:
parentNode.addChild(TreeNode childNode) — у меня модификация счётчиков детей и потомков для всех предков childNode выполняется внутри TreeNode. Чем это плохо? Ну я только одно могу придумать: при политике lazy load, будет много атомарных обращений к базе — столько, сколько предков у parentNode. Но если уж на то пошло, я запрос на предзагрузку вынесу в контроллер/хелпер, а логику модификации счётчиков всё равно оставлю в классе TreeNode — ну блин нечего ей делать вовне, вообще нечего.
Повторюсь ещё раз на всякий случай: всё это предполагает использование DTO. Ну и что? Я распух на DTO, зато похудел на всяких хелперах. По суммарному объёму кода ещё неизвестно, в проигрыше я или нет, а по удобству использования мне мой вариант больше нравится: DTO — они для внешнего использования, и код, их обслуживающий, в целом изолирован; а "ядровая логика BLL" в итоге стала существенно компактнее и проще.
Здравствуйте, dimgel, Вы писали:
IT>>Ты бы лучше попробовал понять почему несколько человек в этой теме пели тебе про одно и тоже — про сложность. Ты всё как-то отмахиваешься от этого момента,
D>Я отмахиваюсь от конкретных рецептов борьбы с этой сложностью, которыми меня кормят без конкретной аргументации. "За маму, бл#$%, за папу." Нахлобуч, чей абстрактно-высокоумный пост ты плюсанул, чуть ниже выдал совершенно дикую ересь по конкретике. Спрашивается: чего стоят песни о сложности в его исполнении?
Дай ссылочку на ересь, а то я что-то выдимо пропустил.
IT>>а тем не менее он как раз является в этом споре ключевым для определения наилучшего решения.
D>Вот тут ниже mrozov красиво спел про наилучшие решения.
mrozov спел не тебе, а топик стартеру.
D>А я у тебя попросил всего лишь навсего уточнение термина "внешние связи" применительно к entity.
А я тебе и ответил. Всё зависит. Точно так же как и правильность твоего решения зависит от конктретной ситуации. В одной ситуации оно может быть вполне оправдано, а в другой повлечёт кучу проблем. Приводить тебе конкретные примеры никто не будет, просто по той причине, что чтобы продемонстрировать несостоятельность твоего подхода нужны не 10 и не 20, а тысячи строк кода. Хочешь я тебе приведу пример? Давай.
using System;
interface IOutputer
{
void Write(string str);
}
class ConsoleOutputer : IOutputer
{
public void Write(string str)
{
Console.Write(str);
}
}
interface IFormatter
{
void Write(string format, params object[] args);
}
class Formatter : IFormatter
{
public Formatter(IOutputer outputer)
{
_outputer = outputer;
}
readonly IOutputer _outputer;
public void Write(string format, params object[] args)
{
_outputer.Write(string.Format(format, args));
}
}
class Programm
{
static void Main()
{
var outputer = new ConsoleOutputer();
var formatter = new Formatter(outputer);
formatter.Write("Hello, {0}!\n", "World");
}
}
Знаешь что делает этот бред и почему это бред? Делает он вот что:
using System;
class Programm
{
static void Main()
{
Console.WriteLine("Hello, World!");
}
}
А бред это потому, что используемые средства не адекватны решаемой задаче. Но, чтобы продемонстрировать тебе, когда это перестанет быть бредом и станет весьма полезным паттерном мне нужно набить несколько сот может быть тысяч строк кода, которые ты всё равно читать не будешь. Как ты там сказал? ТЗ, сроки, 50%? (кстати, ты забыл об оставшихся 50%)
И если Нахлобуч написал ересь, то, я подозреваю, это только потому, что он попытался впихнуть невпихуемое в две строчки, которые ты здесь от всех требуешь. Так не бывает. Придётся обходиться без примеров.
В принципе, задачу можно облегчить методом от противного
Представь, что твоя задача находится на шкале сложности в определённой точке. Предположим, что твоё решение вполне адекватно твоей задаче. Теперь давай двинемся в сторону соответствующей более простым задачам, двинемся как можно дальше, туда, где твоё решение перестанет быть адекватным и станет похожим на то, что я привёл выше. Представил? Представь ещё, что ты доказываешь правильность своего подхода людям, решающим более простые задачи и которые в той точке сложности в которой был ты никогда не были и о ней не подозревают. Как ты им будешь что-то доказывать, какие приводить примеры? А они станут тебя слушать или обзовут твои неудавшиеся попытки ересью?
Если ты понял о чём речь, то можно возвращаться в исходную точку и начинать разбираться с тем, что и почему здесь говорят о сложности и почему плюсуются абстрактно-высокоуровневые посты.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Если ты понял о чём речь, то можно возвращаться в исходную точку и начинать разбираться с тем, что и почему здесь говорят о сложности и почему плюсуются абстрактно-высокоуровневые посты.
Тем не менее, GlebZ ухитрился написать нечто не только абстрактно-высокоуровневое, но и содержащее достаточно конкретики, чтобы я смог извлечь из этого что-то полезное (несмотря на то, что это полезное неприменимо к моим нынешним масштабам). А пустое бла-бла-бла вокруг прописных истин с элементами самовосхваления не прибавляет ни пользы для слушателя, ни доверия к квалификации бла-бла-блатора. За сим откланиваюсь.
Здравствуйте, dimgel, Вы писали:
D>Впрочем, если ты соблаговолишь пройтись развёрнуто по моим примерам (в духе "пойдёшь налево — коня съедят, пойдёшь направо — тебя съедят, про прямо и говорить стыдно"), я был бы признателен.
Я бы соблаговолил, только перечитывать всю ветку лень. Давай ты сформулируешь свои вопросы ещё раз, а я попробую на них ответить в терминах коней.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
D>>Впрочем, если ты соблаговолишь пройтись развёрнуто по моим примерам (в духе "пойдёшь налево — коня съедят, пойдёшь направо — тебя съедят, про прямо и говорить стыдно"), я был бы признателен.
IT>Я бы соблаговолил, только перечитывать всю ветку лень. Давай ты сформулируешь свои вопросы ещё раз, а я попробую на них ответить в терминах коней.
1) Есть сайт/веб-сервис и GUI-клиент к нему, не сохраняющий состояния. Клиент поддерживает режимы обычного юзера и администратора. Обобщённый use case: человек запускает клиент, логинится юзером или админом, выполняет несколько запросов к серверу, завершает клиента (тем самым выполняя logout). Админы и юзеры могут работать с одними и теми же объектами, но юзеры не должны видеть некоторых полей. Я решил через DTO. DTO-объекты для админов наследуются из DTO-объектов для юзверей, добавляя к ним "админские" данные. Решение без DTO? Я вижу собственно только одну альтернативу копированию структуры — редактирование на месте, с предварительным detach от ORM. Но вот не лежит душа: к примеру, вдруг захочется закешировать что-нибудь, а оно уже "подчищенное"...
2) Есть класс TreeNode, являющийся mixin-ом (вспомогательным базовым классом) для некоторых entities. Он добавляет к entity поля parent, numChildren, numDescendants и методы манипуляции деревом, например TreeNode::addChild(TreeNode). Данный метод выполняет инкремент счётчика numChildren у себя, а также счётчика numDescendants у себя и у всех своих предков, плюс помечает нового дитятю как подлежащего сохранению в базе. Хотелось бы услышать пример use case ("налево пойдёшь"), когда такое решение несостоятельно и необходимо выносить эту логику во внешний контроллер. При дополнительном условии, что мы не планируем отказ от использования DTO (поскольку такой отказ — ещё более жёсткое условие, чем "прибивание архитектуры гвоздями к Hibernate" (c) твой же).
D>плюс помечает нового дитятю как подлежащего сохранению в базе
Вот это лишнее, Hibernate сам сбросит дерево, насколько я помню. Так что метод addChild() содержит только инкременты счётчиков, т.е. выглядит так, словно никакого ORM вообще не существует.
Здравствуйте, dimgel, Вы писали:
D>Тем не менее, GlebZ ухитрился написать нечто не только абстрактно-высокоуровневое, но и содержащее достаточно конкретики
GlebZ — маладец! Почёт ему и уважуха.
D>За сим откланиваюсь.
В который раз?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
D>>За сим откланиваюсь.
IT>В который раз?
Перед тобой-то? Посмотрим, как на сформулированные специально для тебя вопросы ответишь, может и в последний. Если я уже начал чувствовать замедление собственных мозгов, то к тем, кто на 10 лет меня старше, надо относиться ещё более критически.
Здравствуйте, dimgel, Вы писали:
D>1) Есть сайт/веб-сервис и GUI-клиент к нему, не сохраняющий состояния. Клиент поддерживает режимы обычного юзера и администратора. Обобщённый use case: человек запускает клиент, логинится юзером или админом, выполняет несколько запросов к серверу, завершает клиента (тем самым выполняя logout). Админы и юзеры могут работать с одними и теми же объектами, но юзеры не должны видеть некоторых полей. Я решил через DTO. DTO-объекты для админов наследуются из DTO-объектов для юзверей, добавляя к ним "админские" данные. Решение без DTO? Я вижу собственно только одну альтернативу копированию структуры — редактирование на месте, с предварительным detach от ORM. Но вот не лежит душа: к примеру, вдруг захочется закешировать что-нибудь, а оно уже "подчищенное"...
Собственно говоря, твоё решение определяется как раз тем, к чему у тебя не лежит душа. Я принципиально не кеширую объекты, в том числе по причинам, о которых ты говоришь. Я кеширую результаты вызовов методов. Поэтому у меня нет проблем с detach (как и нет самого detach) и нет проблем с использованием одного и того же типа объекта, экземпляр которого может иметь некоторые поля незаполненными, если они не нужны.
На самом деле, ты продемонстрировал хороший пример того, как выбираемые инструменты, диктующие архитектуру приложения, влияют на решения программиста. Ты используешь ORM, который кроме всего прочего занимается кешированием объектов. Ты хорошо понимаешь, какую западлянку можно получить, если использовать один и тот же объект и пытаешься решить проблему с помощью добавления новой сущности. Это решает проблему, но её могло бы и не быть вовсе, если бы архитектуру приложения тебе диктовал не твой ORM, а ты сам. А так это похоже на выпрямление кривизны с помощью другого компенсирующего выкривления.
Мой подход. Используем один тип объекта из модели данных для двух разных запросов, объекты никогда повторно не используются, если нужно кеширование, то кешируются результаты вызовов методов. Просто, эффективно, надёжно.
D>2) Есть класс TreeNode, являющийся mixin-ом (вспомогательным базовым классом) для некоторых entities. Он добавляет к entity поля parent, numChildren, numDescendants и методы манипуляции деревом, например TreeNode::addChild(TreeNode). Данный метод выполняет инкремент счётчика numChildren у себя, а также счётчика numDescendants у себя и у всех своих предков, плюс помечает нового дитятю как подлежащего сохранению в базе. Хотелось бы услышать пример use case ("налево пойдёшь"), когда такое решение несостоятельно и необходимо выносить эту логику во внешний контроллер. При дополнительном условии, что мы не планируем отказ от использования DTO (поскольку такой отказ — ещё более жёсткое условие, чем "прибивание архитектуры гвоздями к Hibernate" (c) твой же).
В данном случае речь идёт о логике работы с конкретной структурой данных и у меня нет никаких притензий, т.к. это всё ортогонально BLL, DAL и прочей лэйерщине. В большинстве случаев я бы поступил так же. Единственное, скорее всего я бы постарался выделить подобную работу с деревьями в common и сделать её generic
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Мой подход. Используем один тип объекта из модели данных для двух разных запросов, объекты никогда повторно не используются, если нужно кеширование, то кешируются результаты вызовов методов. Просто, эффективно, надёжно.
Во! Теперь припоминаю, что про кеширование результатов вызовов методов ты уже неоднократно когда-то высказывался. Спасиб.
IT>Единственное, скорее всего я бы постарался выделить подобную работу с деревьями в common и сделать её generic
Это я тоже уже догадался, там иначе привинчивать к основному классу неудобно.
Здравствуйте, dimgel, Вы писали:
D>>>За сим откланиваюсь. IT>>В который раз? D>Перед тобой-то?
Я понял, я понял, ты откланиваешься перед каждым отдельно
D>Посмотрим, как на сформулированные специально для тебя вопросы ответишь, может и в последний. Если я уже начал чувствовать замедление собственных мозгов, то к тем, кто на 10 лет меня старше, надо относиться ещё более критически.
Я свои мозги берегу с юности и не распыляю их ресурсы понапрасну. Один раз нашёл приемлемое в 95% случаях решение и теперь решаю подобные задачи в режиме idle.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Представь, что твоя задача находится на шкале сложности в определённой точке. Предположим, что твоё решение вполне адекватно твоей задаче. Теперь давай двинемся в сторону соответствующей более простым задачам, двинемся как можно дальше, туда, где твоё решение перестанет быть адекватным и станет похожим на то, что я привёл выше. Представил? Представь ещё, что ты доказываешь правильность своего подхода людям, решающим более простые задачи и которые в той точке сложности в которой был ты никогда не были и о ней не подозревают. Как ты им будешь что-то доказывать, какие приводить примеры? А они станут тебя слушать или обзовут твои неудавшиеся попытки ересью?
IT>Если ты понял о чём речь, то можно возвращаться в исходную точку и начинать разбираться с тем, что и почему здесь говорят о сложности и почему плюсуются абстрактно-высокоуровневые посты.
(начиная отсюда и до конца)
?
Я допускаю, что я тоже в силу меньшего опыта могу чего-то не понимать, но, повторюсь, я к примеру часто использую в BLL & DAL статические классы и за несколько лет это мне никаких проблем не принесло. Мне же говорят что нужно использовать интерфейсы с DI, и для меня это выглядит как твой пример с IOutputer и IFormatter — я не вижу необходимости в этом, абсолютно.
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Нахлобуч, Вы писали:
Н>>Внимание, вопрос: какими критериями лично ты руководствуешься при определении, какой метод стоит поместить в бизнес-объект, а какой туда помещать не стоит?
D>Вот же ж чёрт... В десятый раз повторяю: я позволяю себе из entity работать с другими entities. И больше ни с чем — ни с email-оповещалками, ни с UI, ни со слоем BL, который за всё это отвечает. То есть, если взять все entities и обозвать их отдельным слоем, то содержащийся в нём код не обращается ни к чему за его слоя. Но внутри этого слоя я действую по принципу минимизации количества вспомогательных объектов и делегирования, поскольку BL в любом случае имеет доступ к entities, так что ему всё равно, а выше BL я entities не пускаю, интерфейс BL сформулирован в терминах DTO.
А где они берут эти ентити с которыми работают? tracking + lazy-load? Или они умеют лазить в базу, доставать то, что нужно, сохранять то, что нужно?
D>Повторюсь ещё раз на всякий случай: всё это предполагает использование DTO. Ну и что? Я распух на DTO, зато похудел на всяких хелперах. По суммарному объёму кода ещё неизвестно, в проигрыше я или нет, а по удобству использования мне мой вариант больше нравится: DTO — они для внешнего использования, и код, их обслуживающий, в целом изолирован; а "ядровая логика BLL" в итоге стала существенно компактнее и проще.
Я сильно сомневаюсь, что возможны клиент-серверы с более менее сложной логикой без DTO вообще, так что вопрос не в DTO а их количестве. Хотя я много слышал от сторонников тонкой модели, что они легко обходятся без DTO.
Здравствуйте, dimgel, Вы писали:
D>По-моему, вы двое говорите о разной инкапсуляции.
Она одна.
D>Я повторю свой пример: есть метод A->setB(B) и поле B::countAs. Корректировка второго из первого — это ИМХО оправданная инкапсуляция логики (в данном случае тривиальной), поскольку в противном случае об этом счётчике придётся помнить всюду, где используется первый метод.
Этот пример не имеет отношения к исходному вопросу.
D>Бояре сумлеваются.
Проблемы бояр...
D>Редуцировать entities до структур... я лучше уж DTO добавлю (в качестве базовых классов entities).
Да хоть горшком назови.
Здравствуйте, Ziaw, Вы писали:
Z>А где они берут эти ентити с которыми работают? tracking + lazy-load? Или они умеют лазить в базу, доставать то, что нужно, сохранять то, что нужно?
Умеют. Добавления/модификации объектов hiberate сбрасывает в базу сам, а вот для запроса объекта по (class, id), а также для удаления объекта требуется доступ из вызывающего entitу к hibernate session (уже не помню, инжектил я её в каждый объект или обращался к current thread session).
Скажем так: я рассматривал DAL = все entities + hibernate + соответствующие helpers (preloads и т.п.). Мне хотелось, чтобы интерфейс этого DAL, используемый BLL, был компактным и объектным, с минимумом вспомогательных классов и без торчащих наружу потрохов ORM. То есть, чтобы BLL мог вызывать человеческое parentNode.addChild(childNode) вместо treeController.addChild(parentNode, childNode). Сам DAL благодаря хиберу выходил простым, так что вводить дополнительные расслоения/ограничения внутри него было нецелесообразно; работа с session из entities в итоге давала более компактный результат (я не погнушался и сделал базовый класс для всех entities с методом getSession()).
Lazy load вообще говоря ортогонален логике. Когда мне требовалось делать preload вручную, я вызывал соответствующий DAL хелпер из BLL перед вызовом основного метода, что дико (где ж изоляция BLL от потрохов ORM?). Сейчас я сделал бы этот метод (TreeNodeHelper::preloadAncestors(node)) доступным только внутри DAL и воткнул бы его вызов прямо в TreeNode.addChild(). Как-то так.
В общем, на Дао программирования этот подход конечно не тянет, но в качестве варианта решения для системы средней сложности, прибитой гвоздями к Hibernate, ИМХО вполне жизнеспособен.
Единственный неоднозначный вопрос — где кончается логика отслеживания логической целостности базы и начинается бизнес-логика. Я не позволял себе вызывать из DAL что-либо за пределами DAL, но с другой стороны, многие вещи, находящиеся в BLL и работающие только с базой, можно перетащить из BLL в DAL один в один. В таких случаях я обычно консультировался со своей левой пяткой.
Z>Я сильно сомневаюсь, что возможны клиент-серверы с более менее сложной логикой без DTO вообще, так что вопрос не в DTO а их количестве. Хотя я много слышал от сторонников тонкой модели, что они легко обходятся без DTO.
IT ниже написал свой вариант решения одной конкретной задачи. Напоминание про "кеширование результатов вызовов методов" для меня было недостающим куском мозаики для понимания его минималистского stateless + DTOless подхода. Весьма красивого, надо сказать, хотя и требующего некоторых дополнительных усилий при первом использовании, т.к. "типовыми средствами" подобная парадигма не поддерживается.
Здравствуйте, dimgel, Вы писали:
D>Умеют. Добавления/модификации объектов hiberate сбрасывает в базу сам, а вот для запроса объекта по (class, id), а также для удаления объекта требуется доступ из вызывающего entitу к hibernate session (уже не помню, инжектил я её в каждый объект или обращался к current thread session).
ага, new Entity() и гибернейт сам почуял, что ее хотят заперсистить. Почти вся логика происходит по сценарию —
1. вытаскиваем объекты
2. изменяем их и/или создаем новые и/или удаляем
3. сохраняем результаты
Логика как не крути завазяна на БД, пусть неявно, излишне абстрагироваться от тоже БД вредно.
D>Lazy load вообще говоря ортогонален логике. Когда мне требовалось делать preload вручную, я вызывал соответствующий DAL хелпер из BLL перед вызовом основного метода, что дико (где ж изоляция BLL от потрохов ORM?). Сейчас я сделал бы этот метод (TreeNodeHelper::preloadAncestors(node)) доступным только внутри DAL и воткнул бы его вызов прямо в TreeNode.addChild(). Как-то так.
Ортогонален BL, но мы тут не о BL, а об архитектуре. Если твой BL завязан на LL — это может привести к серьезным проблемам производительности в будущем. Ты можешь возразить, что BL ничего не знает про LL и он происходит абсолютно прозрачно. Но это ничего не меняет, избавиться от LL без серьезного переписывания BL у тебя не выйдет.
D>IT ниже написал свой вариант решения одной конкретной задачи. Напоминание про "кеширование результатов вызовов методов" для меня было недостающим куском мозаики для понимания его минималистского stateless + DTOless подхода. Весьма красивого, надо сказать, хотя и требующего некоторых дополнительных усилий при первом использовании, т.к. "типовыми средствами" подобная парадигма не поддерживается.
Это ты свою узкую проблему решил. Кеширование результатов вызовов stateless server'а вполне стандартный паттерн, поддерживается даже фреймворками.
DTO решает другую серьезную задачу — отдай мне то, и только то, что нужно одним вызовом. При использовании тонкой модели встречаются случаи когда "то, и только то, что нужно" является Entity или IList<Entity>, тогда спец. DTO не требуется. Но это лишь частный случай.
Здравствуйте, IB, Вы писали:
D>>По-моему, вы двое говорите о разной инкапсуляции. IB>Она одна.
"Данные отдельно, логика отдельно" — это инкапсуляция? Может быть, напомнить определение из ООП, про чёрные ящики там и т.п.? Помнится, IT честно говорил, что в его архитектуре ООП с инкапсуляцией идут лесом. Но не придумывал новых трактовок общеизвестным терминам.
Если же речь идёт об инкапсуляции бизнес-логики (как я догадываюсь), то это далеко не "одна", а совсем даже "другая".
Здравствуйте, Ziaw, Вы писали:
Z>ага, new Entity() и гибернейт сам почуял, что ее хотят заперсистить.
В большинстве случаев — да, т.к. новый объект добавляется в дерево уже persistent-объектов. Но не всегда, разумеется, это я несколько неряшливо написал.
Z>Ортогонален BL, но мы тут не о BL, а об архитектуре.
В таком случае, что такое архитектура, если не декомпозиция на слои и их взаимодействие?
Z>Если твой BL завязан на LL — это может привести к серьезным проблемам производительности в будущем.
Не сталкивался. Разумеется, поскольку BL оперитрует бизнес объектами, он в любом случае завязан на их структуру, т.е. на структуру базы. При изменении структуры базы BL придётся рефакторить, это очевидно. Что касается проблем производительности в рамках заданной структуры базы, то в хибере полно винтиков, и я описал, где и как я склонен эти винтики дёргать: внутри DAL, прозрачным для BL образом.
Z>Это ты свою узкую проблему решил. Кеширование результатов вызовов stateless server'а вполне стандартный паттерн, поддерживается даже фреймворками.
Ок, буду иметь в виду. В любом случае я собирался этот вопрос исследовать поподробнее после освоения lift.
Z>DTO решает другую серьезную задачу — отдай мне то, и только то, что нужно одним вызовом. При использовании тонкой модели встречаются случаи когда "то, и только то, что нужно" является Entity или IList<Entity>, тогда спец. DTO не требуется. Но это лишь частный случай.
Именно с этим аргументом я защищал DTO. Мой конкретный пример, однако, IT решил без DTO. Вполне вероятно, что можно сочинить пример, который он без DTO не решит. Однако я склонен доверять его оценке, что для 95% случаев его подход работает (хотя бы потому, что не могу с ходу вспомнить вообще ни одной задачи, где бы он не сработал).
Здравствуйте, dimgel, Вы писали:
D>"Данные отдельно, логика отдельно" — это инкапсуляция?
Именно.
D> Может быть, напомнить определение из ООП, про чёрные ящики там и т.п.?
Я другое напомню — не надо телегу впереди лошади ставить. Не инкапсуляция, потому что ООП, а ООП потому что инкапсуляция.
Инкапсуляция — это средство уменьшения связности кода, путем сокрытия конкретной реализации за публичным контрактом. Так какую реализацию ты скрываешь, навешивая на данные, к которым один фиг есть публичный доступ, левую логику?
D> Помнится, IT честно говорил, что в его архитектуре ООП с инкапсуляцией идут лесом.
IT умница, и к ООП относится с нежностью и трепетом, так что пальцами ООП не трожь.. =)
IT, если что, сам за себя скажет.
D>Но не придумывал новых трактовок общеизвестным терминам.
Это не новая трактовка, это оригинальная. Почитай классиков, Меерса, например, или Саттера.
D>Если же речь идёт об инкапсуляции бизнес-логики (как я догадываюсь), то это далеко не "одна", а совсем даже "другая".
Чем она другая? Не мог бы ты привести определение обеих?