Бизнес логика в хранимках — это хорошо или плохо?

Контекст

Существует расхожее мнение, что бизнес-логика в хранимках — это зло. Однако от опытных разработчиков нередко можно услышать, что это не так. Давайте разбираться.

Есть две хороших статьи, описывающих проблематику: раз (оригинал) и два.
Первая описывает проблематику и хорошо показывает отличия систем с одним, двумя, тремя и N звеньями. В ней автор убедительно доказывает, что вся бизнес-логика должна быть в бизнес слое. Вместе с тем, автор также сообщает, что:

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

По сути этим же утверждением автор приходит к мысли, что:

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

В комментариях к статье можно встретить и такое утверждение, вполне созвучное с утверждениями автора статьи:

Вообще SQL как язык удобен только для консоли, в программировании он не нужен.

На каком-то форуме встречал и такое эмоциональное высказывание (к сожалению не могу найти, чтобы добавить ссылку):

Только полный дурак будет хранить бизнес-логику в хранимках

Есть другое мнение. Автор второй статьи сообщает:

Я видел много разных ORM, но не видел ни одного хорошего. То есть такого, который за пределами простых примеров не превращается в обузу и прокрустово ложе

Я искренне извиняюсь перед теми братьями по профессии, кто вложил массу времени и усилий в создание многочисленных универсальных лучших в мире ORM. Мне правда очень жаль.

В его статье перечислены приёмы, позволяющие успешно применять первый подход.

Мы видим, что продолжают выходить инструменты, для систем с бизнес-логикой в хранимках. Например: Бизнес-логика в базе данных при помощи SchemaKeeper. Примечательна оговорка в начале статьи:

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

Другой автор в своей статье вполне обоснованно выступает в защиту данного подхода, описывая на примере развития сервиса платежей, из которого выпала работа пользователя:

Встает вопрос — зачем всю эту информацию откачивать из базы данных, обрабатывать и записывать обратно? Такой необходимости вообще нет, т.к. пользователь полностью исключен из автоматической обработки платежей. Соответственно, все это может решиться на уровне обработки данных, которым и занимается в полной мере сервер базы данных.
А ведь, то что мы раньше выделили бизнес-логику в объектной методологии нам совсем не пригодилось, т.к. нам стало нужно иметь просто одну хранимую процедуру, которая просто проведет платежное поручение из очереди. Да в этом случае бизнес-логика попадает в хранимые процедуры.

И задаёт резонный вопрос:

3-х звенная архитектура, предполагает, что бизнес-логика находится на сервере (среднее звено) и для данной задачи минует клиента. Но во-первых, мы ввели лишние звено, а во-вторых, оно снова же выполняет в данной задаче роль клиента — откачивает данные из базы данных, их обрабатывает и записывает назад. И все это только для того, чтобы было удобно на объектном языке обрабатывать бизнес-логику. Не велика ли цена?

Автор повторяет опыт с системой коммунальных платежей, когда бизнес-логика в хранимках снова выигрывает. От себя могу сразу также добавить пару примеров:

  1. Запуск/останов/отмена/перенос акций с вытеснением по приоритетам и/или смешиванием.
  2. Расчёт зарплаты с премиями, отпусками, штрафами и т.п.

Здесь, когда бизнес-логика в среднем звене, придётся вытянуть кучу данных, обработать, и, минуя пользователя, записать обратно. Для какой-нибудь чёрной пятницы, это будет довольно большая куча данных. Как следствие это будет работать гораздо дольше, чем могло бы. И с привлечением бОльших ресурсов.

Можно привести ещё массу примеров попроще, которые успешно решаются пакетными запросами и/или агрегированием на стороне БД. И нередко всё это с транзакциями. Вынос этого куда-либо является избыточным. Никто не спорит с тем, что первичная валидация и форматирование — должно происходить на клиенте.

Можно услышать такое возражение, в стиле — выкачивает много даннных? Делает работу, для которой создавалась БД? Не беда:

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

Взять пример с акциями выше. Когда-то у нас расчёт акций происходил на сайте (CMS Bitrix24). После того, как этот механизм перенесли в БД, сайт удалось существенно разгрузить и сэкономить на хостинге — вполне значимую сумму денег.

Список возражений

Ниже собраны различные возражения к подходу "бизнес-логика в хранимках".

Повторяемость кода

Эта проблема проявляется при любом подходе. Решается переиспользованием кода. Результат одной хранимки может быть использован в другой хранимке.

Нельзя вести командную разработку

Это не так. Командная разработка строится абсолютно также, через контроль версий, slack и прочее.

Их сложно тестировать и следить за их изменением

Тут не совсем понятно — никто не запрещает писать тестовые скрипты. Изменения отслеживаются через Git.

Хранимые процедуры должны документироваться

Бесспорно, нужно просто это делать.

Сложность навигации в хранимках

Слабое возражение, так как в приложениях, использующих ORM подход, существует такое же большое количество классов. Кроме того хранимки структурируются схемами.

Трудности при переходе на другие СУБД

Да, это сравнимо с переписыванием клиентского приложения на другой язык (например было на PHP, стало на C#). Разные СУБД дают разные возможности. С другой стороны, за весь жизненный цикл проекта, это может и не потребоваться. Все случаи, которые изместны мне — это перевод серверов с ОС Windows на ОС Linux и следующие за этим перенос баз с MS SQL на PostreSQL. Однако даже Microsoft уже научили свою СУБД работать на Linux.
Другая возможная причина — это сэкономить на базе данных, используя одну из бесплатных. Это веский довод. Здесь всё зависит от необходимых возможностей. Решение потребуется принимать на старте проекта. Ровно так же, как это происходит с выбором языка для клиентского приложения.

СУБД требуют создавать пул подключений

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

SQL сложный

СУБД — это специализированный софт, максимально заточенный на работу с данными.
SQL — язык декларативный, а не императивный, алгоритмы какие-то редко бывают, отлаживать по шагам практически нечего. Требуется совсем другой подход к разработке. Для разработчика на императивных языках — это игра "на чужом поле". Если запрос чуть сложнее, чем тривиальный, то для грамотного его написания требуются специфические знания. Что можно делать в транзакциях, а чего нельзя? Когда индекс полезен, а когда — вреден? Что лучше, "IN" или "JOIN"? Почему происходит эскалация блокировок и на что это влияет? И так далее. Для этого потребуется кадровый разработчик именно по языкам SQL. Особой разницы в зарплате, по сравнению с другими разработчиками не замечено. Для работы с данными нужны соответствующие специалисты.

Зачем SQL-хранимки, когда есть Hibernate и его HQL?

  • Хранимки изолируют данные и работу с ними от клиентского приложения. Для приложения остаются "действия" и оно ничего не знает о схемах и внутренней структуре базы данных. Через это обеспечивается уровень абстракции.
  • Упрощается управление безопасностью. Это достигается путём отключения доступа ко всему, кроме хранимых процедур. Дальнейшая детализированная защита обеспечивается уже внутри хранимых процедур средствами языка и платформы.
  • Хранимые процедуры компилируются и выполняются сервером БД сразу после вызова. Это ускоряет время работы содержащегося внутри кода.
  • Замечено, что написание отличных от простой логики занимает меньше времени.
  • Hibernate — это вариант адаптации инструмента обработки данных под свою область знаний.
  • Можно не противопоставлять SQL-хранимки и Hibernate — хранимки нормально вписываются в Hibernate.

Итого

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

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

Возможно всё-таки имеет смысл учесть опыт обоих подходов и, может быть, выработать какой-то новый.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *