Pull to refresh

Comments 18

Вы пишете: «если потребуется замена какой-то конкретной СУБД на аналогичную, не придется осуществлять серьезные переделки в приложении.»

Но для аналогичной базы даже городить прям уж такой DAL не нужно, обычно этим занимаются драйвера БД и сврывают конкретную базу, детали зависят от языка и технологий, а вот если вы захотите заменить внезапно SQL на NoSQL, Вы реально перепишете всю логику приложения, ибо то, что делалось простым SQL-запросом, теперь ни за что так запросто не будет. И никакой DAL тут не спасет.

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

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

В том-то и дело, что у разработчиков все равно остаются средства для использования vendor-specific особенностей конкретной СУБД. Никто не мешает, например, при работе через JDBC использовать специфичные конструкции Oracle или MS SQL. Драйвер это пропустит. А вот при работе через DAL такого сделать не получится.

а вот если вы захотите заменить внезапно SQL на NoSQL, Вы реально перепишете всю логику приложения, ибо то, что делалось простым SQL-запросом, теперь ни за что так запросто не будет. И никакой DAL тут не спасет.


Совершенно верно, и в статье об этом говорится: если мы выходим за рамки класса данных (например, переходим от реляционных данных к key-value), то приложение потребует перепроектирования.

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


Не совсем так: мы используем SQL, от него никто не отказывается, но некий общий диалект (м.б. стандарт SQL-92, SQL-99...), который гарантированно поддерживается всеми реляционными СУБД. И этот диалект и считается интерфейсом DAL для доступа к реляционным данным.

данные и их организация настолько сильно влияют на приложение, что их вот так запросто выделить в отдельный слой ну никак не получится.


В статье не предлагается заносить в DAL организацию данных приложения. Структура данных, конечно же, остается частью приложения. DAL предоставляет механизм для доступа к этим данным и, возможно, включает в себя какую-то специфику работы с данными, присутствующими в организации и распространяющуюся на все приложения, работающие в этой организации (например, глобальную политику доступа к данным).
Использование «общего диалекта» приводит к тому, что на каждой СУБД работает неэффективный код. Не все это могут себе позволить.
Ну, начнем с того, что DAL и подходит не всем :) Его сфера применения — это большое предприятие («кровавый enterprise» :))

Использование «общего диалекта» приводит к тому, что на каждой СУБД работает неэффективный код. Не все это могут себе позволить.


На мой взгляд, сформулировано чересчур категорично :) Точнее было бы, как мне кажется, сказать «иногда может привести к тому, что на каких-то СУБД будет работать неэффективный код».

Конечно, такие ситуации будут встречаться, от качелей «универсальность VS эффективность» никуда не деться. Я думаю, что в таких случаях надо будет предусмотреть при организации DAL какие-то закладки, позволяющие выполнить нативный запрос. Но появление таких закладок должно быть исключением из правил и должно строго контролироваться на организационном уровне.
Его сфера применения — это большое предприятие («кровавый enterprise» :))

В кровавом энтерпрайзе вероятность смены БД оочень невысока. Они как посмотрят на стоимость миграции — и заодно проверки совместимости всех связанных систем — так и бросят эту идею. Плавали, ели, спасибо, нет.

А вот как раз DAL нужен почти всем, другое дело, что в современных приложениях его роль в половине случаев будет ORM выполнять.
Плавали, ели, спасибо, нет.

Если не сложно — можно подробнее про «плавали, ели»??
Я работал с более чем одним крупным заказчиком (госучереждения, российский банк), каждый из которых на любые предложения сменить на существующей системе базу данных сразу отвечал «нет».
А исходя из каких соображений крупному заказчику предлагали сменить СУБД для существующих систем?

Я работал в крупном российском банке, который сменил СУБД. На большом кол-ве существующих систем.
А исходя из каких соображений крупному заказчику предлагали сменить СУБД для существующих систем?

Разные варианты. Лицензирование, совместимость, производительность, функциональность.

Единственный аргумент, который на моей памяти работал — это сертификация.
То есть, не то чтобы «спасибо, нет», но все-таки «иногда да» ;)
Это по разряду «спасибо, нет… какая проверка?!»

Ну и я, в общем-то не зря написал «вероятность невысока», а не «смена невозможна».
В Java описанное довольно актуально — в качестве DAL выступает Hibernate. Его Criteria API и HQL еле-еле покрывают SQL-92, а вызовы хранимок в разных базах с точки зрения кода выглядят почти одинаково. Поэтому переход на другую РСУБД может оказаться не таким сложным делом. Особенно когда цена вопроса — отказ от лицензий Oracle.

Причем вокруг Hibernate довольно легко построить свои обертки, которые не сильно снижают эффективность, поэтому во всех программах на Java ест ярко выраженный DAL.

В случае .NET\C# картина совершенно иная. Там есть Linq, который сам по себе слой абстракции над запросами базы. Вот только уровень поддержки Linq разных провайдеров разный, поэтому используя Linq легко написать код, который будет работать только с MS SQL. С другой стороны Linq настолько мощен, что его нельзя абстрагировать в своем DAL без потери функциональности. Поэтому обычно все забивают на DAL, затачивают программу под конкретный движок СУБД, выжимая максимум.
Получается быстрее в разработке и более эффективный код, но при этом сменить БД — проблема.

На практике в любом серьезном проекте программа все равно неявно затачивается под конкретную СУБД и смена СУБД это далеко не только смена строки подключения. У меня есть прекрасный пример, когда смена MS SQL на Mongo увеличила объем кода приложения почти в 2 раза. Это при том, что архитектор утверждал, что Mongo идеально подходит для этого приложения. А в случае «кровавого ынтерпрайза», где много данных и в каждый запрос добавляется нетривиальный предикат проверки прав, подобный переход сделать еще сложнее.
Linq настолько мощен, что его нельзя абстрагировать в своем DAL без потери функциональности.

Вопрос может быть наивный (с .NET знаком весьма поверхностно, живу в Java мире):
А разве нельзя накрыть эту мощную функциональность какими-нибудь репозиториями и, тем самым, последовать дао верного пути DAL? :)

смена MS SQL на Mongo увеличила объем кода приложения почти в 2 раза

Это как раз переход от одного класса данных к другому. Естественно, без переписывания никак.

На практике в любом серьезном проекте программа все равно неявно затачивается под конкретную СУБД и смена СУБД это далеко не только смена строки подключения

Здесь вопрос в том, что еще помимо строки подключения нужно исправить. При отсутствии DAL — это разбросанные по всему коду специфические SQL конструкции, при наличии DAL — все эти конструкции могут быть заключены в ограниченном наборе классов с выставленным API. Цена перехода для второго случая, как я думаю, существенно ниже.

А в случае «кровавого ынтерпрайза», где много данных и в каждый запрос добавляется нетривиальный предикат проверки прав

Ну, не во всех энтерпрайзах такое есть. А если и понадобится такой функционал, то, на мой взгляд, он должен быть инкапсулирован в отдельный компонент, который при переходе и дорабатывается.

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

Во-первых, любой LINQ-провайдер — это уже DAL, так что формально задача выполнена. А во-вторых, если вы поверх этого будете строить еще один слой абстракции… ну да, можно. Но зачем?
еще один слой абстракции… ну да, можно. Но зачем?

Во-первых, для экранирования использования LINQ конструкций, специфичных для провайдеров.
Во-вторых, для улучшения структуры и читаемости кода. Мне кажется, что любой запрос (неважно, SQL, HQL, LINQ) сложнее select с 1-2 условиями должен быть перенесен в метод репозитория с четким и ясным названием. Не 10 строк WHERE… AND… NOT EXISTS… BETWEEN и т.п., а что-то типа findAllUncompleteOrders. (Отец Эванс шлет нам горячий DDD привет! :))
Уже неоднократно обсуждено, причем здесь же на хабре — при работе с LINQ запросы можно компоновать без применения репозитория. Например:

for (var order = source.Orders.Uncomplete().ForPriorityCustomers())
{
...
}
А разве нельзя накрыть эту мощную функциональность какими-нибудь репозиториями и, тем самым, последовать дао верного пути DAL? :)

Проблема в том, что любой самописный DAL значительно уменьшит мощность Linq. МС оценивает разработку Linq-провайдера в 2 человеко-года. Ни один ынтерпрайзный проект такие затраты нести не будет ради DAL. С другой стороны любой ORM с Linq делает ровно тоже самое, что описанный вами DAL.

Это как раз переход от одного класса данных к другому. Естественно, без переписывания никак

А изначально утверждалось обратное. Причем именно автором DAL.

При отсутствии DAL — это разбросанные по всему коду специфические SQL конструкции, при наличии DAL — все эти конструкции могут быть заключены в ограниченном наборе классов с выставленным API.

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

Суть любой абстракции для доступа к данным — генерация запросов. Для РСУБД запрос тем лучше (быстрее, тратит меньше ресурсов), чем он точнее — по максимуму определены все предикаты, написаны все джоины, указаны только нужные поля в проекции, указана сортировка и выборка по страницам.
Часть сведений для построения запроса есть только в верхних слоях приложения (presentation layer), например проекция, сортировка и постраничное разбиение. Можно все передавать параметрами, но набор параметров пухнет с нереальной скоростью.

В итоге идеальный DAL это не просто наборы методов с 1-2 параметрами, которые возвращают коллекции объектов. Идеальный DAL это метод Fetch, который принимает некоторый объект, содержащий все параметры — проекции, сортировки, джоины итд (query object). То есть ровно то, что делает ORM. При этом query object собирается не в одном месте, а постепенно в него добавляются параметры на всех слоях.

Но тут всегда возникают database specific вещи: типы не совпадают, в одной базе можно написать x is null, а в другой нет, в одной базе есть функции, а в другой нет итд. То есть мелкие особенности попадают в логику приложения.

И DAL тут не поможет, потому что если попытаться отказаться от query objeсt и все параметры передавать в методы как обычные параметры, то очень быстро наступает ад для поддержки.

А вот в простых случаях, когда можно все свести к DAL из десятка методов, теория о том, что можно все особенности изолировать в DAL — верна. Но это не «кровавый ынтерпрайз», а скорее наоборот, простенькие наколеночные системы, с небольшим количеством пользователей, данных и примитивной логикой.

Ну, не во всех энтерпрайзах такое есть. А если и понадобится такой функционал, то, на мой взгляд, он должен быть инкапсулирован в отдельный компонент, который при переходе и дорабатывается.

Тогда я не знаю что вы называете энтерпрайзом.
Если вы просто называете так «ит-зоопарк», то никакого отношения к DAL он не имеет. Разработчик всегда работает с одной базой, которая заложена в архитектуру и под нее покупаются лицензии.
Если энтерпразом вы называете большое количество существующей инфраструктуры, то тоже к DAL не имеет отношения. Все равно у вас основная база одна и ваше приложение нужно чтобы эту базу наполнять.
Я бы называл энтерпрайзом задачи, где требуется учитывать структуру организации в логике приложения. Это неизменно ведет нас к запросам, которые как-то обрабатывают разрешения.

Инкапсулировать такую логику нельзя. Потому что проверка разрешений не в самом запросе — адские тормоза и не работает уже при 5000 строк. Поэтому разработчики энтерпрайз систем вынуждены включать разграничения доступа в логику работы с базой. А это, с учетом проблем описанных выше, приводит к бесполезности DAL.

ЗЫ. Тем не менее, когда средства генерации запросов очень слабые, как Hibernate в Java, то сделать DAL вокруг него не представляет проблем.
Sign up to leave a comment.