Здравствуйте, another_coder, Вы писали:
_>Здравствуйте, Baudolino.
_>В настоящее время, такое определение, на мой взгляд, вводит в заблуждение людей, т.к. является слишком общим. За этим определением может скрываться любой функционал, абсолютно любой.
Любой, удовлетворяющий определению паттерна. Это нормальная ситуация.
_>И приведенный пример, действительно, удовлетворяет. Но это не репозиторий.
Это репозиторий
по определению. Причем по достаточно общепринятому определению. Если вы хотите дать другое определение, давайте, но вам нужно будет объяснить, чем оно лучше.
B>>Т.е. любой репозиторий — DAO, но не любой DAO — репозиторий.
_>Из-за такого представления и возникает путаница в общении.
Путаница в общении обычно возникает из-за того, что кто-то что-то не знает или не понимает. Обычно решается фразой "давай для начала определим, что такое..." и глоссарием в архитектурной документации.
_>Думаю, следует разделять мух от котлет: DAO — абстракция над хранилищем данным, без логики связанной с бизнесом, Repository — аналогично, как aggregate root в DDD.
Вы предлагаете отделять мух от котлет, но используете слова "аналогично" и "как". Хорошее определение не должно использовать аналогии, потому что определение по аналогии нечетко: оно полагается на ментальную модель читателя, которая у разных людей может быть разной. Дайте четкое определение на русском языке и мы его обсудим.
_>Ничего не смешано. Смотрите сами и попробуйте подумать, где вы будете все это сводить в единую систему?
B>>Логика реализации "запросов"
_>Это чистый DAO, или ORM framework.
Что такое "чистый DAO"? Что значит в данном случае "или": если это ORM, то это не DAO? Или DAO=ORM? Как от этого меняется определение репозитория?
B>>кэширование и логирование — особенности внутренней реализации, о которых клиент не знает.
_>Это сервисная логика, которая может меняться не зависимо от хранилища по не зависящим от проектирования и ПО хотелкам либо клиента, либо самих разрабов. На каком уровне она будет использоваться?
Что такое "сервисная логика"? Вспомогательная? Логика сервисного слоя? Кэширование — это алгоритмический, а не архитектурный паттерн. Как реализован ваш компонент доступа к БД — это скрытая деталь реализации. Репозиторий может кэшировать, шлюз БД — может, клиент слоя доступа к данным — может. Суть определений от этого не меняется.
B>>Фильтрация по служебным полям — часть интерфейса DAO (и, как сказано выше, может быть, репозитория)
_>Служебные поля служебным полям рознь. Есть те, что являются частью бизнес логики, есть те, частью целостности хранения данных, а есть те, что нужны в рамках обслуживания системы. Куда относится, например, IsDeleted (имеется ввиду, что ничего не удаляется), а куда фильтрация по CreatedDate (имеется ввиду, не показывать слишком старые)?
Это специфика функциональных требований к конкретной системе, которые нужно как следует анализировать. Давайте разберем на примере IsDeleted. Само по себе такое поле никогда не появляется — оно является частью требований к инфраструктуре приложения, к тому как обрабатываются данные вообще, а не конкретные сущности. Как правило, его задача — сохранить данные для аудита, планового или в чрезвычайной ситуации (для бэкапа такой способ подходит плохо). Для того, чтобы понять, на каком уровне этот флаг появляется, необходимо найти конечного пользователя и используемый им интерфейс. Если это то же самое приложение, то без вариантов — это часть доменной модели и интерфейс DAO знает о его существовании (например, в виде специальных методов типа findDeleted). Если для чтения этого флага используется другое приложение (например, штатный клиент БД) — у вас имеет место быть интеграция через БД, этот флаг является частью протокола интеграции, т.е. особенностью внутренней реализации DAO. При этом все вышесказанное никак не влияет на выбор конкретного вида DAO: это может относиться в равной степени к репозиторию, шлюзу таблицы БД (table data gateway) и т.п.
_>И в дополнение при наличии всего-всего вы начнете думать, как же все это протестировать. Начнете выделять функциональности, чтобы от них изолироваться. Вы обнаружите, что, например, IsDeleted должен быть на уровне DAO, CreatedDate — в Repository, при этом вам 2L кеширование нужно и вы думаете о том, чтобы прицепить 3rd party библиотеку и это тоже нужно в Repsoitory. А вот аудитлог вам скорее всего понадобиться в DAO. Хотя, какую-то умную служебную (алерты для саппорта, например, или для сбора спец информации) нотификацию вы опять же засунете в репозиторй.
Как я уже говорил, в моем представлении репозиторий — это разновидность DAO, и вы пока не предложили альтернативной трактовки. Проблем с тестированием не вижу вообще никаких. Даже со всем, что вы упомянули, тесты (и юнит, и интеграционные) тут будут очень простые. Что меняется от того, что у вас появляется зависимость одного компонента от другого с четко определенным интерфейсом, позволяющим при необходимости в тесте инжектировать заглушку для верификации взаимодействия?
_>Конечно, условий слишком много, чтобы проводить четкую линию между между тем что куда относится. Но то, что хочется видеть, это понимание того, что Data Layer — это не один класс, в который сначала все сваливается, а потом превращается в то, что трудно тестировать и поддерживать.
_>Это должно быть просто и сердито: DAO — объект доступа к данным, Repository — объект подготовки данных к BO. Без всяких обобщений и "перевоплощений" ропозитория в DAO, как вы писали.
Кому должно?

Вот тут я, кстати, начал примерно понимать, куда вы клоните. Давайте отбросим на минутку все наши представления о паттернах-фигаттернах, и рассмотрим задачу в общем виде, чтобы определить их заново.
Итак, у нас есть бизнес-логика, реализованная в рамках ООП. Есть хранилище данных, чаще всего реляционное (РСУБД). Нам нужно обеспечить передачу данных из хранилища в бизнес-логику. Поскольку хранилище тяжелое, реализованное посторонними людьми, мы хотим в целях простоты поддержки и тестирования изолировать доступ к нему в отдельном архитектурном слое. Назовем его Data Access Layer (DAL). В этом слое у нас будет некоторое количество компонентов, которые будет использовать бизнес-логика. Следующим шагом мы определим вид этих компонентов, выбрав уровень связности бизнес-логики и хранилища. Если мы готовы пожертвовать гибкостью в пользу большей производительности, мы выбираем интерфейс компонентов, в котором каждый метод представляет собой некий запрос к БД и возвращает временный объект (DTO). Мы называем тип таких компонентов Table Data Gateway. Если мы хотим наоборот, чтобы бизнес-логика воспринимала хранилище просто как некую коллекцию, мы в интерфейсе компонентов DAL будем использовать методы вида добавить/заменить/удалить и назовем такие компоненты Repository. Каждый такой компонент будет соответствовать одной сущности модели (или одной иерархии). Определившись с интерфейсами, приступаем к выбору реализации. Мы будем использовать какое-либо стандартное API для доступа к БД, которое позволит нам выполнять SQL-запросы и получать в ответ табличные данные.
Поскольку нам нужно преобразовать реляционную модель в объектную, нам требуется объектно-реляционное отображение (ORM). Его можно реализовать самостоятельно, строя запросы и преобразуя полученные данные (в таком случае стоит вынести логику построения запросов и чтения результатов в отдельный класс — Object-Relational Mapper), а можно выбрать готовое ORM-решение, которое используя декларативную модель описания отображения, сведет код вашего репозитория к одной строчке в каждом методе.
Далее, хранилище далеко от узла развертывания, поэтому мы хотим ускорить его работу за счет алгоритма кэширования. Мы можем использовать готовый кэш, поэтому добавим в нужные методы компонента DAL попытку чтения из кэша перед чтением из БД. Кэш будет представлен у нас простым интерфейсом с методами вида get/putIfAbsent/invalidate и т.п. За инжектирование конкретной реализации кэша в наш компонент DAL ,будет отвечать контейнер DI. Но лучше всего будет в таком случае настроить кэш в ORM/f и вообще не заморачиваться на собственную реализацию логики. Что касается журналирования и обработки ошибок, замусоривать код такой вспомогательной логикой не обязательно, если у вас есть возможность завернуть ваши компоненты в прокси, которые будут журналировать вызовы методов. Это обычно делается с помощью AOP. А теперь внимание, вопрос: а где здесь собственно должно появиться ваше разделение на "объект доступа к данным" и "объект подготовки данных к ВО"? (и что такое ВО?)
_>И сразу отвечу на возможный вопрос о кеше и доп логике в ропозитории.
А кто бы ставил этот вопрос?

Вроде все нормальные люди давно уже используют DI.