Что такое бизнес логика в программировании

Где наша бизнес-логика, сынок?

Время на прочтение
18 мин

Количество просмотров 77K

Спасибо небу за то, что в субботу шел дождь, и я это прочитал (а вы скажите спасибо за то, что перевел). В воскресенье, однако, светило солнце и форматирование текста было отложено.

Отдельное спасибо автору, за разрешение отдельной публикации.

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

Где наша бизнес логика, сынок?

Введение

За годы развития мы продвинулись от десктопа к клиент-серверной архитектуре, потом к 3-х звенной конструкции, к n-звенной, к сервис ориентированной. Во время этого процесса многие вещи изменились, но многие привычки остались. Зачастую, сопротивление изменениям происходит от привычек. Однако, во многих случаях оно процедурное. Эта статья описывает, что мы делаем неправильно и возможные решения.

О статье

То, что я здесь опишу, один из методов построения n-звенных систем с точки зрения проектирования и архитектуры. Эта статья не фокусируется на коде. Есть много методов построения n-звенных систем, это только один из них. Если вы строите систему, я надеюсь, вы найдете хороший совет, методику или шаблон использования этого подхода.
Хотя данная статья может предлагать несколько отправных точек из «стандартных методов», все в этой статье базируется на Шаблонах и Методах Microsoft и описывается в Designing Data Tier Components and Passing Data through Tiers и других документах.

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

Цель

Спросите любого разработчика, где должна быть бизнес логика, и получите ответ: «Конечно же в бизнес слое».
Спросите того же разработчика, где находится бизнес логика в их организации, и снова услышите: «Конечно же в бизнес слое».

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

Термины

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

Звено (tier)

Когда я использую слово звено, я подразумеваю физическое звено состоящее из физического сервера или группы серверов, выполняющих одинаковую функцию и сгруппированных только для повышения емкости.

Слой (layer)

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

Развитие проблемы

Десктоп

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

image

Клиент-сервер

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

image

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

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

image

3-звенка

Когда проблема клиент-серверной архитектуры стала явной, возросла популярность 3-х звенного подхода. Наибольшей и самой тяжелой проблемой того времени было количество подключений. Сейчас многие базы данных могут обрабатывать тысячи единовременных подключений, в девяностых большинство баз данных падали где-то на 500 подключений. Сервера зачастую лицензировались по кол-ву клиентских подключений. Это все и привело к тому, что потребовалось сократить количество подключений к базе данных.

Стало популярным объединение подключений в пул, однако для реализации пула подключений в системе с множеством отдельных клиентов, необходимо внедрить третье звено между клиентом и сервером. Среднее звено так и стало называться «среднее звено». В большинстве случаев среднее звено существовало только для управления пулом соединений, но в некоторых случаях бизнес логика начала перемещаться в среднее звено потому, что языки разработки (C++, VB, Delphi, Java) гораздо лучше подходили для реализации бизнес логики, чем языки хранимых процедур. Вскоре стало очевидно, что среднее звено –это наилучшее место для бизнес логики.

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

Что такое бизнес логика?

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

Сервер базы данных – это уровень хранения. Базы данных разработаны для хранения, получения и обновления данных с максимально высокой эффективностью. Функционал зачастую является СУПОм (Создать, Удалить, Получить, Обновить). Некоторые базы данных СУПОм и являются, но разговор не об этом.

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

Удалить Покупателя

И все это относится не только к сложным вещам. Давайте представим себе простую задачу и такую, которую зачастую даже не относят к бизнес логике. Задача – Удалить Покупателя. Практически во всех системах, что я видел, удаление покупателя обрабатывается исключительно хранимой процедурой. Однако в удаление покупателя довольно многие решения должны быть приняты на уровне бизнес логики. Можно ли удалить покупателя? Какие процессы должны быть запущены до и после? Какие предосторожности должны быть соблюдены? Из каких таблиц записи должны быть удалены или обновлены в последствие?

Базе данных не должно быть дела до того, что такое покупатель, она должна заботиться только об элементах, используемых для хранения покупателя. У базы данных не должно быть возможности разобраться, какие таблицы должны хранить объект покупатель, и она должна работать с таблицами не обращая внимания на объект покупатель. Задача базы данных – хранить ряды в таблицах, которые описывают покупателя. Кроме базовых ограничений вроде каскадной целостности, типов данных, индексов и пустых значений, база данных не должна иметь функционального знания о том, что же из себя представляет покупатель в бизнес слое.

Хранимые процедуры, если они есть, должны оперировать только одной таблицей; исключение – это процедуры запрашивающие выборку из нескольких таблиц для выдачи данных. В этом случае, хранимые процедуры работают как представления (view). Представления и хранимые процедуры должны использоваться для консолидации значений, но исключительно для более быстрой и эффективной работы с данными в бизнес слое.

Но даже в компаниях, гордящихся новейшими достижениями в разработках и технологиях, и в тех, что с пеной у рта кричат о всей их бизнес логике в бизнес слое, короткий анализ базы данных быстро выявляет: удалить покупателя, добавить покупателя, заблокировать покупателя, заморозить покупателя и т.д. и т.п. И не только с покупателем, но и с многими другими объектами бизнес логики.

Я часто встречал хранимые процедуры вроде этой:
sp_DeleteCustomer(x)
Select row in customer table, is Locked field
If true then throw error
Sum total of customer billing table
If balance > 0 then throw error
Delete rows in customer billing table (A detail table)
if Customer table Created field older than one year then
Insert row in survey table
Delete row in customer table

Регулярно часть бизнес логики отъезжает в бизнес слой.
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
sp_DeleteCustomer(x)
Delete rows in customer billing table (A detail table)
Delete row in customer table

В этом случае, часть бизнес логики была перемещена, но не вся. Некоторые таблицы обрабатываются и в слое бизнес логики. База данных не должна иметь ни малейшего представления о том, какие таблицы формируют покупателя в бизнес слое. Для всех трех операций, бизнес слой должен выдать SQL команду или вызвать три отдельные хранимые процедуры для реализации функционала в приведенной sp_DeleteCustomer.
Передав всю бизнес логику в бизнес слой, мы получим:
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
Delete rows in customer billing table (A detail table)
Delete row in customer table

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

Переведя даже модификацию таблиц в бизнес слой, мы получим следующие преимущества:

  • Перенос базы данных может быть осуществлен с меньшими усилиями, т.к. все эти хранимые процедуры не нужно отлаживать для каждой СУБД.
  • Модификация проще, т.к. вся логика содержится в одном слое, а не в двух.
  • Отладка проще – логика не размазана по двум слоям.
  • Другая логика не сможет проскользнуть в хранимую процедуру только потому, что «так проще».

В виду того, что такой метод требует три успешных обращения к базе данных вместо одного, ваш узел бизнес логики должен быть подключен к базе данных по отдельному высокоскоростному сегменту, типа гигабита. Отправка 300 байт вместо 100 байт станет непринципиальной. Большинство баз данных поддерживают пакетную передачу SQL запросов, и все три запроса могут быть посланы в одном пакете, уменьшив нагрузку на сеть. Для выдачи таких запросов следует использовать слой доступа к данным, а не включать запросы прямо в код.

Некоторые администраторы баз данных и даже разработчики могут не принять этот уровень интеграции и настаивать на реализации таких пакетных обновлений в хранимых процедурах. Это выбор, который вы должны сделать, и он очень зависит от вашей базы данных и ваших приоритетов. Т.к. практически все современные базы данных используют механизмы кэширования запросов, выигрыш в производительности в большинстве случаев минимален, а четкие технологические причины не нагружать логикой хранимые процедуры есть. Если вы выберите оставить такие пакетные обновления в хранимых процедурах, вы должны быть очень осторожны, чтобы не допустить проскальзывания другой бизнес логики в хранимые процедуры, и ограничить свои хранимые процедуры СУПОвыми операциями, без каких либо условных операций и другой бизнес логики.

Форматирование

Давайте разберем еще один пример, обнаруженный мной и сеющий зерна войны среди разработчиков – является это бизнес логикой или нет. Я расскажу, почему я считаю это бизнес логикой, а не пользовательским интерфейсом или хранением. Этот пример не относится к легко реализуемому форматированию. Пример, который я буду использовать, — телефонные номера.
Каждая страна имеет свой собственный формат отображения телефонных номеров в приятной глазу манере. В некоторых странах их даже больше одной. Ниже несколько примеров:

Кипр:
+357 (25) 66 00 34
+357 (25) 660 034
+357 25 660 034
+357 2566 0034
Германия:
+49 211 123456
+49 211 1234-0
Северная Америка (США, Канада)
+1 (423) 235-2423
+1-423-235-2423
Россия:
+7 (812) 438-46-02
+7 (812) 438-4602

В Германии есть даже специальный официальный стандарт для форматирования – DIN 5008.

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

Договоримся форматировать телефоны следующим образом:

  • Данные поступают в различных форматах.
  • У каждой страны есть свой уникальный способ отображать телефоны.
  • Форматы некоторых стран не просты и меняются в зависимости от первых цифр.
  • Первые несколько цифр (обычно код страны и региона) не всегда имеют фиксированную длину. Например, в России, 812 – код города Санкт-Петербург, 495 – Москва, но некоторые регионы имеют 4 знака (3952). Это приводит и к изменению и общей длины, и формата, в зависимости от регионального кода.
  • При выходе новых законов, появлении новых операторов, интеграции Евросоюза, обновления телефонных систем и еще множестве всего, форматы и длины телефонов меняются довольно часто в глобальном масштабе. За недавнее время Кипр сменил свой код страны дважды: один раз при обновление системы, второй раз из-за возросшего числа сотовых операторов. Имея сотни стран во всем мире, следует ожидать изменений на регулярной основе.

Обычно делается следующее, все не цифровые символы убираются и номер становится похожим на:
Phone: 35725660034

Иногда отделяется код страны и номер становится таким:
PhoneCountry: 357
PhoneLocal: 25660034

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

Зачастую обработка ввода (если код страны отделен) и логика отображения реализованы на клиенте, т.к. клиент написан на традиционном языке, который хорошо для этого подходит. Проблема в том, что клиенту требуется огромное количество данных для определения длины кодов стран, и потребуется обновление клиента каждый раз, когда изменился формат отображения.

Иногда форматирование осуществляется в хранимой процедуре. Проблема этого подхода в том, что языки хранимых процедур, не приспособленны для такого типа логики, и он часто приводит к багам и тормозам в работе с настоящей логики.

Еще чаще телефонные номера хранятся дважды. Один раз в чистом виде для хорошей индексации и поиска, и второй – в отформатированном для отображения. В дополнении к проблемам, описанным выше, получаем проблемы избыточных записей и обновления.

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

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

Исключения

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

Я еще вернусь в статье к этой проблеме.

Сегодняшние системы

Клиент-сервер

В клиент-серверных приложениях бизнес логика обычно имеется и на клиенте, и на сервере.

image

Реальное соотношение будет меняться от приложения и компании, предыдущий пример хорошо описывает клиент-серверные приложения. Большая часть бизнес логики была реализована в хранимых процедурах и представлениях в попытке централизовать бизнес логику. Однако многие бизнес правила не могут быть реализованы просто на SQL или хранимыми процедурами, или их быстрее выполнять на клиенте, так как они основываются на интерфейсе пользователя. Из-за этих противоположных факторов бизнес логика распределена между клиентом и сервером.

N-звенка

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

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

Сценарий 1

Типичное распределение бизнес логики по n-звенной системе:

image

В таких случаях бизнес слой не содержит бизнес правил. Это не настоящий бизнес слой, а только форматер XML (или другого потокового формата) и адаптер наборов данных базы данных. Хотя некоторые плюсы такие как: пул соединений и изоляция БД, могут быть достигнуты, это не настоящий слой бизнес логики. Это скорее инородный физический слой без слоя логики.

Сценарий 2

Другой типичный сценарий:

image

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

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

image

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

Консолидация

Вместо всего вышеперечисленного, бизнес слой должен содержать все бизнес правила.

image7

Такая разработка имеет следующие преимущества:

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

Приведенный сценарий – это цель. Однако, некоторое дублирование, особенно для проверки данных, должно быть и на клиенте. Эти правила должны быть поддержаны и бизнес слоем. Кроме этого, в некоторых системах отдельные высоко емкие операции, такие как пакетные обновления, могут привести к исключениям и должны быть размещены в базе данных. Потому более реалистичных подход представлен ниже. Обратите внимание, что вся бизнес логика должна быть реализована в бизнес слое, и те минимальные наборы, присутствующие в других слоях, являются просто дублями исключительно для повышения производительности или отключения тех или иных компонент пользовательского интерфейса.

image

Переезд на центральный узел

Скользкий путь

При переходе на центральный узел всегда есть искус «реализовать эту часть в хранимой процедуре». Потом «ту» и «вот эту». И скоро вы окажетесь в той же ситуации, что и были, без существенных изменений.

Хранимые процедуры должны использоваться для выполнения SQL и получения наборов данных в базах данных, которые оптимизируют хранимые процедуры лучше, чем представления. Но хранимые процедуры не должны быть использованы ни для чего другого, нежели объединения и выдачи данных. При обновлении данных она должна именно и только обновлять, но не интерпретировать данные каким-либо образом.

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

Дешевле

Звучит несколько странно, что покупка железа может сделать дешевле. Но при внедрении серверов среднего звена, практически никакого дополнительного ПО, кроме ОС, не требуется. А стоимость наращивания мощности сервера базы данных существенна по следующим причинам:

  • Сервера баз данных, как правило, более высокого класса, чем сервера среднего звена, и стоят дороже.
  • Базы данных зачастую лицензируются на процессор и добавление процессора – дорогостоящая процедура в терминах лицензий. Лицензионные сборы могут составлять от 5000 до 40000 долларов на процессор.

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

Проще

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

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

Топология

Давайте рассмотрим утверждения, которые я только что привел, используя следующую диаграмму. Заливка в сегментах показывает направление или важность их названия в отношении звеньев на диаграмме. Цена единицы возрастает, когда мы движемся от клиента, к среденму звену, к базе данных. Я использую слово единица для обозначения процессора или сервера, в зависимости от конфигурации.
(сверху вниз: цена единицы, средняя полоса пропускания, сложность развертывания, количество)

image

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

image

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

Вырасти середину

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

image

При переносе логики в среднее звено, вы можете серьезно снизить нагрузку на базу данных. Цифры представленные здесь, приведены только для демонстрации и будут меняться от системы к системе, но они могут помочь уловить идею. Хотя на следующей диаграмме и больше аппаратуры, суммарная стоимость системы будет меньше, и ее будет проще развернуть. Гораздо дешевле и проще наращивать среднее звено.

image

Бутылочное горлышко

Давайте посмотрим еще раз на один из предыдущих графиков:

image

Какое единственное узкое место в системе? Какое из звеньев имеет выраженный предел наращивания? Это однозначно база данных. Все упирается в базу данных.

image

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

Сложности

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

Привычки

Есть поговорка: «сложно избавиться от старых привычек». Это применимо и к команде. В команде вам нужно убедить не только себя, но и большинство команды.

Процедуры

Многие компании имеют устоявшиеся политики безопасности, предписывающие обеспечение безопасности в базе данных, а использование хранимых процедур в качестве представлений не дает достаточного контроля. Изменение корпоративных политик безопасности для перехода в n-звенный мир может оказаться очень сложным, если не невозможным.
В .Net безопасность, как и в новых технологиях Microsoft, ориентирована на корпоративную безопасность в среднем звене как никогда ранее, но многие компании все еще опираются на базы данных и либо не заботятся об изменениях, либо не хотят менятся.

Администраторы баз данных

Это рискованное утверждение. Настолько рискованная, что есть еще кое-что, что нужно сказать. Если вы администратор БД или разработчик, пожалуйста, не воспринимайте то, что я хочу сказать как стереотип или правду о всех администраторах баз данных. Однако, это превалирует и часто встречается. Если вы администратор БД, который не попадает под это описание – браво! Вы Президент баз данных, а не лорд баз данных.

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

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

Администраторы баз данных не мигрируют по компаниям с такой частотой как разработчики, и многие из них руководят корпоративной базой данных на протяжении последних 10 и даже 20 лет. База данных очень важная для них вещь, и они не хотят идти ни на какие сделки. Они построили свое королевство и не хотят потерять контроль. Заставить такого администратора отдать часть безопасности и реализации можно только в серьезной битве и при поддержке менеджмента.

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

Инструментарий

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

Решения

Архитектура

Я обнаружил большую пользу в регулярном аудите архитектуры системы, при котором помечается некорректное размещение бизнес логики. Чем раньше они обнаружены, тем проще и дешевле их исправить. Если у вас нет специального главного архитектора, тогда разработчики из команды могут проверять друг друга. Если что-то найдено не в том месте, разработчик может оповестить команду и тимлидера.

Обучение ассистентов

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

Все равно процесс затронет ассистентов. Они пишут запросы, оптимизируют их и обслуживают базу данных. Также они должны отслеживать SQL, приходящий из среднего звена, и производительность БД. Ассистенты также продолжат проектировать архитектуру БД.

Обучение менеджеров

Часто встречается сопротивление менеджмента, хотя, это скорее простое препятствие, чем сложное. Менеджменту наплевать, стала ли легче ваша работа, но их заботят накладные расходы, время разработки, преимущества для бизнеса, ну и не плохо бы им рассказать о текущих потерях.

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

Что еще почитать

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

Во время своей работы, я прочитал много материала, написанного «экспертами». Большая часть их была написана разработчиками, хорошими в создании теорий и обучении других в том как надо делать, но никогда не применявшими свои собственные методы на практике. Другие были написаны опытными разработчиками с узким кругозором, а эти знания очень зависят от конкретного приложения. Когда разработчики читают такие материалы, они становятся уверенны в том, что есть только один путь решения проблемы. Разработчикам нужно мыслить шире и понимать, что описанное решение проблемы является только направлением, а не доктриной.

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

Пожалуйста, обратите внимание на Designing data tier components and passing data through tiers.

Заключение

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

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

UPD: по подсказке maovrn перенесено в «Проектирование и рефакторинг».
UPD1:
Для тех кто в танке:
1. На Хабре есть правила оформления переводов см. помощь
2. Для тех, кто не может осилить п.1. автор статьи Chad Z. Hower aka Kudzu
3. Для тех, кто читает только середину без начала и конца — статье три года. Потому, как минимум некорректно объявлять автора статьи безграмотным на основание того, что он не читал на момент публикации материалов, выпущенных после публикации.
4. Если данный апдейт вас задел — это ваши проблемы.

Бизнес-логика — то же самое что и логика предметной/доменной/прикладной области. Допустим, вы программируете софт для приюта животных и для детского приюта.

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

По бизнес-логике детского приюта — ребенка надо кормить, поить и спать укладывать. В него нельзя втыкать шприц со смертельной дозой морфия.

При этом все структуры данных, алгоритмы и т.д. — в двух программах практически одинаковы. Кроме вот этой маленькой детали.

«ЭТОТ один ИФЧИК решил СУДЬБУ КОТЕЙКИ», или, например «начинающий программист УБИЛ младенца ВЕКТОРОМ»

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

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

Если не отделять, допустим интерфейс от бизнес-логики, то вместо нажатия кнопки «отдать ребенка новым родителям» или «усыпить котенка», на двух аккуратных — почти похожих — пультах управления (интерфейсах) вы будете бегать туда-сюда, пытаясь понять, кого утопить, кого усыпить, кого отдать новым родителям и почему ничего не работает.

Вы не отделили интерфейс (панель управления для запуска котят на луну) от бизнес-логики и все запуталось.

Ну, я предупреждал.

Используете вы синглтоны, очереди, базы данных, флэт-файлы, микросервисы — не важно — важно, чтобы бизнес-логика работала правильно.

Под правильно подразумевается корректность результатов в приемлемое время. Все остальное ваших заказчиков не интересует. До тех пор, пока они не являются вашими владельцами.

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

P.S. Маленький исторический экскурс.
Бизнес-логикой это называется потому, что в Нормальном Мире, во Внешней Империи, программирование в коммерции и корпорациях развивалось еще с 50х-60х годов: банки, страховые агентства, туроператоры, медицина.

Т.е. тебе платили за то, чтобы ты внедрил требования конкретного бизнеса

Хорошо, что это бизнес-логика, а не партийная логика, как в Северной Корее.

{«id»:13888,»url»:»/distributions/13888/click?bit=1&hash=b9ef1acfaff33313e209ff706cdc085257b1aa0628eda8cd82c15ab939b88cb6″,»title»:»u0414u0435u043bu0430u0442u044c u043fu0440u0435u0434u0441u043au0430u0437u0430u043du0438u044f u0434u043bu044f u0431u0438u0437u043du0435u0441u0430 u0431u0435u0437 u0442u0430u0440u043e»,»buttonText»:»u041du0430u0443u0447u0438u0442u044cu0441u044f»,»imageUuid»:»5a8d05f2-0e2c-5a89-8e96-98d923aa05a2″,»isPaidAndBannersEnabled»:false}

Бизнес-логика приложения – это, по сути, описание схем, по которым приложение взаимодействует с пользователем. Когда пользователь оформляет подписку, или заполняет форму заказа, или просто авторизуется – все эти действия обрабатываются «под капотом» приложения в определенном порядке.

Какие данные нужно запросить? Соответствуют ли введенные данные заданному формату? Что произойдет после того, как пользователь нажмет кнопку «Подтвердить»? А есть ли вообще у него права доступа к данной операции? На все эти и многие другие вопросы можно ответить, изучив, как построена бизнес-логика конкретного приложения.

Простейший пример: администратор авиакомпании (пользователь) регистрирует пассажира на рейс (вносит информацию в базу данных).

Что делает пользователь:

1.Открывает информацию о выбранном рейсе, переходит к списку уже зарегистрированных пассажиров, нажимает «Зарегистрировать пассажира».

2.Заполняет форму регистрации: вводит номер рейса, выбирает пассажира, указывает место и статус регистрации.

3.Нажимает кнопку «Подтвердить»

4.Видит нового пассажира в общем списке.

Как это выглядит с точки зрения бизнес-логики приложения:

1.Приложение проверяет, авторизован ли пользователь и имеет ли права доступа к выбранной странице, а также операции регистрации.

2.Ждет, пока пользователь заполнит форму.

3.Обрабатывает введенные данные:

a. Проверяет, соответствуют ли введенные данные требованиям приложения (эти требования заранее прописаны программистом): например, в поле «Номер рейса» должно быть целое число.

b. Получает из базы данных информацию: например, о рейсе и связанных с ним регистрациях (чтобы внести изменения), пассажире (чтобы проверить, действительно ли этот пассажир есть в базе данных).

c. Выдает сообщения об ошибках, если поля заполнены неверно.

d. Отправляет информацию в базу данных, отдавая команды на создание в ней новых записей или обновлении существующих.

4.Выводит обновленную информацию на экран.

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

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

Именно благодаря этой «шаблонности» в no-code разработке появилась возможность использовать инструменты визуального программирования – так называемые дизайнеры бизнес-логики. Они помогают выбрать нужные блоки, скомпоновать в нужной последовательности, настроить. И даже создать некоторые блоки автоматически, в зависимости от настроек других компонентов приложения. Итог – готовая бизнес-логика без необходимости проводить многие часы над строками кода.

Проектирование Сервисного Слоя и Логики Приложения¶

Эта статья посвящена вопросам управления Логикой Приложения и проектированию Сервисного Слоя (Service Layer), Use Case, CQRS, Event Sourcing, MVC и др.

Содержание

  • Проектирование Сервисного Слоя и Логики Приложения
  • Виды логики
    • Layered Architecture
    • Что такое Бизнес-Логика (Business Logic)?
    • Подвиды Бизнес-Правил (Business Rules)
    • Почему важно отделять Business Logic от Application Logic?
  • Способы организации Логики Приложения (Application Logic)
  • Что такое Сервис?
  • Классификация Сервисов по уровням логики
    • Сервисы уровня Доменной Логики (Domain Logic)
    • Сервисы уровня Логики Приложения (Application Logic)
    • Сервисы уровня Инфраструктурного Слоя (Infrastructure Layer)
  • Классификация Сервисов по способу взаимодействия
    • Оркестровые Сервисы
    • Хореографические Сервисы
      • Частые ошибки проектирования Хореографических Сервисов
  • Классификация Сервисов по способу обмена данными
  • Классификация Сервисов по состоянию
    • Stateless Service
    • Statefull Service
  • Назначение Сервисного Слоя
  • Когда Сервисный Слой не нужен?
  • Сервис — не обертка для DataMapper
  • Реализация Сервисного Слоя
  • Инверсия Управления
  • Распространенная проблема Django-приложений
  • Проблема Django-аннотаций
  • Особенности сервисного слоя на стороне клиента
  • Проблема параллельного обновления
  • CQRS
  • Event Sourcing
  • Что почитать

Виды логики¶

Прежде чем копнуть вглубь, было бы неплохо разобраться с тем, что такое Логика Приложения (Application Logic) и чем она отличается от Бизнес-Логики (Business Logic).

Layered Architecture¶

Одно из наиболее часто-цитируемых определений основных концептуальных слоев дает Eric Evans:

User Interface (or Presentation Layer)
Responsible for showing information to the user and interpreting the user’s
commands. The external actor might sometimes be another computer
system rather than a human user.
Application Layer
Defines the jobs the software is supposed to do and directs the expressive
domain objects to work out problems. The tasks this layer is responsible
for are meaningful to the business or necessary for interaction with the
application layers of other systems.
This layer is kept thin. It does not contain business rules or knowledge, but
only coordinates tasks and delegates work to collaborations of domain
objects in the next layer down. It does not have state reflecting the
business situation, but it can have state that reflects the progress of a task
for the user or the program.
Domain Layer (or Model Layer)
Responsible for representing concepts of the business, information about
the business situation, and business rules. State that reflects the business
situation is controlled and used here, even though the technical details of
storing it are delegated to the infrastructure. This layer is the heart of
business software.
Infrastructure Layer
Provides generic technical capabilities that support the higher layers:
message sending for the application, persistence for the domain, drawing
widgets for the UI, and so on. The infrastructure layer may also support
the pattern of interactions between the four layers through an
architectural framework.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4] by Eric Evans

Ward Cunningham дает следующие определения:

Factor your application classes into four layers in the following way (see Figure 1: FourLayerArchitecture):

The View layer. This is the layer where the physical window and widget objects live. It may also contain Controller classes as in classical MVC. Any new user interface widgets developed for this application are put in this layer. In most cases today this layer is completely generated by a window-builder tool.

The ApplicationModel layer. This layer mediates between the various user interface components on a GUI screen and translates the messages that they understand into messages understood by the objects in the domain model. It is responsible for the flow of the application and controls navigation from window to window. This layer is often partially generated by a window-builder and partially coded by the developer.

The DomainModel layer. This is the layer where most objects found in an OO analysis and design will reside. Examples of the types of objects found in this layer may be Orders, Employees, Sensors, or whatever is appropriate to the problem domain.

The Infrastructure layer. This is where the objects that represent connections to entities outside the application (specifically those outside the object world) reside. Examples of objects in this layer would include SQLTables, 3270Terminals, SerialPorts, SQLBrokers and the like.

— Four Layer Architecture, Ward Cunningham

Но что означает сам термин Бизнес (Business)?
Непонимание этого термина часто приводит к серьезным проблемам проектирования.
В это трудно поверить, но большинство разработчиков, даже с многолетним стажем, этого не понимают, и полагают что это что-то связанное с финансами.

Что такое Бизнес-Логика (Business Logic)?¶

Самое авторитетное пояснение термина Business можно найти, как обычно, на сайте Ward Cunningham:

Software intersects with the Real World. Imagine that.

Там же можно найти и определение термина Business Rule:

A Business Rule (in a programming context) is knowledge that gets applied to a set of data to create new value. Or it may be a rule about how to create, modify, or remove data. Or perhaps it is a rule that specifies when certain processes occur.

For example, we have a rule about email addresses – when the Driver Name field on our object identifier changes, we erase the email address. When we receive a new email address, we make sure that it contains an “@” sign and a valid domain not on our blacklist.

Business Logic Definition:

Business logic is that portion of an enterprise system which determines how data is:

  • Transformed and/or calculated. For example, business logic determines how a tax total is calculated from invoice line items.
  • Routed to people or software systems, aka workflow.

Следует отличать термин Business (по сути — синоним слова Domain) от термина Business Domain:

A category about the business domain, such as accounting, finance, inventory, marketing, tracking, billing, reporting, charting, taxes, etc.

Также следует отличать Business и от Business Process:

A Business Process is some reproduceable process within an organization. Often it is a something that you want to setup once and reuse over and over again.

Companies spend a lot of time and money identifying Business Processes, designing the software that captures a Business Process and then testing and documenting these processes.

One example of a Business Process is “Take an order on my web site”. It might involve a customer, items from a catalog and a credit card. Each of these things is represented by business objects and together they represent a Business Process.

Википедия дает следующее определение термину Business Logic:

In computer software, business logic or domain logic is the part of the program that encodes the real-world Business Rules that determine how data can be created, stored, and changed. It is contrasted with the remainder of the software that might be concerned with lower-level details of managing a database or displaying the user interface, system infrastructure, or generally connecting various parts of the program.

И поясняет, чем отличается Business Logic от Business Rules:

Business logic should be distinguished from business rules.[“Definition of business logic“] Business logic is the portion of an enterprise system which determines how data is transformed or calculated, and how it is routed to people or software (workflow). Business rules are formal expressions of business policy. Anything that is a process or procedure is business logic, and anything that is neither a process nor a procedure is a business rule. Welcoming a new visitor is a process (workflow) consisting of steps to be taken, whereas saying every new visitor must be welcomed is a business rule. Further, business logic is procedural whereas business rules are declarative.[William Ulrich. “OMG Business Rules Symposium” (архив оригинала от 2013-12-24)]

Craig Larman считает термин Business синонимом к термину Domain, и в книге “Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development” он многократно приводит их рядом, дополняя один термин другим, взятым в скобки.
Термину Business Rules он дает следующее определение:

Business Rules — Business rules (also called Domain Rules) typically describe requirements or policies that transcend one software project — they are required in the domain or business, and many applications may need to conform to them. An excellent example is government tax laws. Domain rule details may be recorded in the Supplementary Specification, but because they are usually more enduring and applicable than for one software project, placing them in a central Business Rules artifact (shared by all analysts of the company) makes for better reuse of the analysis effort.

<…>

The Business Rules (or Domain Rules) capture long-living and spanning rules or policies, such as tax laws, that transcend one particular application.

<…>

Domain rules [Ross97, GK00] dictate how a domain or business may operate. They are not requirements of any one application, although an application’s requirements are often influenced by domain rules. Company policies, physical laws (such as how oil flows underground), and government laws are common domain rules.

They are commonly called business rules, which is the most common type, but that term is poor, as many software applications are for non-business problems, such as weather simulation or military logistics. A weather simulation has “domain rules,” related to physical laws and relationships, that influence the application requirements.

It’s useful to identify and record domain rules in a separate application-independent artifact — what the UP calls the Business Rules artifact — so that this analysis can be shared and reused across the organization and across projects, rather than buried within a project-specific document.

—“Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development” by Craig Larman

Резюмируя, я обобщу все своими словами:

Бизнес-Логика (деловые регламенты, доменные модели)
это моделирование объектов и процессов предметной области (т.е. реального мира).
Это то, что программа должна делать (от слова “дело” — именно так переводится слово “business”), и ради чего она создается.
Логика приложения
это то, что обеспечивает и координирует работу Бизнес-Логики.

Подвиды Бизнес-Правил (Business Rules)¶

Robert Martin в “Clean Architecture” подразделяет Бизнес-Правила на два вида:

  • Application-specific Business Rules

  • Application-independent Business Rules

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

    Thus we find the system divided into decoupled horizontal layers—the UI, application-specific Business Rules, application-independent Business Rules, and the database, just to mention a few.

    — “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin

Главы 16, 20 и 22 of Clean Architecture разъясняют в подробностях типы Бизнес-Правил.

При этом, Robert Martin выводит свои 4 слоя: Entities, Use Cases, Interface Adapters, Frameworks and Drivers.

Нужно отметить, что Robert Martin под “Business Rules” понимает не только правила, но и процедуры, смывая грань между “Business Rules” и “Business Logic”:

Строго говоря, бизнес-правила — это правила или процедуры, делающие или экономящие деньги.

Strictly speaking, business rules are rules or procedures that make or save the business money.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

При этом, у него можно наблюдать небольшое противоречие.
С одной стороны, вся суть “Business Rules” у него сводится к тому, что они относятся исключительно к реальному миру:

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

Банк взимает N% за кредит — это бизнес-правило, которое приносит банку деньги.
И неважно, имеется ли компьютерная программа, вычисляющая процент, или служащий вычисляет его на счетах.

Strictly speaking, business rules are rules or procedures that make or save the business money.
Very strictly speaking, these rules would make or save the business money, irrespective of whether they were implemented on a computer.
They would make or save money even if they were executed manually.

The fact that a bank charges N% interest for a loan is a business rule that makes the bank money.
It doesn’t matter if a computer program calculates the interest, or if a clerk with an abacus calculates the interest.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

Далее Robert Martin говорит важную информацию — “Business Rules” являются причиной существования Приложения.
Из этого следует, что Приложение уже не может являться причиной существования “Business Rules”:

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

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

Business rules are the reason a software system exists.
They are the core functionality.
They carry the code that makes, or saves, money.
They are the family jewels.

The business rules should remain pristine, unsullied by baser concerns such as the user interface or database used.
Ideally, the code that represents the business rules should be the heart of the system, with lesser concerns being plugged in to them.
The business rules should be the most independent and reusable code in the system.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

Однако, с другой стороны, он допускает существование “Business Rules” в контексте функционирования приложения:

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

Not all business rules are as pure as Entities.
Some business rules make or save money for the business by defining and constraining the way that an automated system operates.
These rules would not be used in a manual environment, because they make sense only as part of an automated system.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

Не совсем понятно — “Business Rules” являются причиной существования Приложения, или имеют имеют смысл только как часть Приложения?
“Business rules are the reason a software system exists” или “they make sense only as part of an automated system”?

Тут просматривается небольшое взаимоисключение, и это именно та причина, по которой я придерживаюсь формулировки Eric Evans — “Application Layer does not contain business rules”.
Тут нужно добавить, что в силу “DDD Trilemma”, доменная логика все-таки может просачиваться на уровень логики приложения, см. вариант “Domain model purity + Performance” (“Split the decision-making process between the domain layer and controllers ”).

Понятно, что здесь не хватает термина для выражения различных явлений, и Robert Martin решает дифференцировать уже существующий термин “Business Rules”, разделив его на два уровня — “Critical Business Rules” и “Application-specific Business Rules”:

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

A use case is a description of the way that an automated system is used.
It specifies the input to be provided by the user, the output to be returned to the user, and the processing steps involved in producing that output.
A use case describes application-specific business rules as opposed to the Critical Business Rules within the Entities.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

Но далее он сводит обязанности Use Case к обязанностям Application Logic, и подчеркивает, что Use Case координирует “Critical Business Rules”, реализованных в виде Entities:

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

<…>

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

Use cases contain the rules that specify how and when the Critical Business Rules within the Entities are invoked.
Use cases control the dance of the Entities.

<…>

Why are Entities high level and use cases lower level?
Because use cases are specific to a single application and, therefore, are closer to the inputs and outputs of that system.
Entities are generalizations that can be used in many different applications, so they are farther from the inputs and outputs of the system.
Use cases depend on Entities; Entities do not depend on use cases.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin, Chapter 20 “Business Rules”

Хотя, Robert Martin выделяет отдельную категорию классов UseCase (Interactor) для Application-specific Business Rules, на практике этот уровень часто “округляется” до уровня Application Logic.
Так, например, Martin Fowler и Randy Stafford разделяют “Business Logic” на два вида — Логика Домена (Domain Logic) и Логика Приложения (Application Logic):

Подобно сценарию транзакции (Transaction Script, 133) и модели предметной области
(Domain Model, 140), слой служб представляет собой типовое решение по организации
бизнес-логики. Многие проектировщики, и я в том числе, любят разносить бизнес-логику
по двум категориям: логика домена (domain logic) имеет дело только с предметной
областью как таковой (примером могут служить стратегии вычисления зачтенного дохода
по контракту), а логика приложения (application logic) описывает сферу ответственности
приложения [11] (скажем, уведомляет пользователей и сторонние приложения о протекании
процесса вычисления доходов). Логику приложения часто называют также
“логикой рабочего процесса”, несмотря на то что под “рабочим процессом” часто понимаются
совершенно разные вещи.

Like Transaction Script (110) and Domain Model (116), Service Layer is a pattern for organizing business logic.
Many designers, including me, like to divide “business logic” into two kinds: “domain logic,” having to
do purely with the problem domain (such as strategies for calculating revenue recognition on a contract), and
“application logic,” having to do with application responsibilities [Cockburn UC] (such as notifying contract
administrators, and integrated applications, of revenue recognition calculations). Application logic is
sometimes referred to as “workflow logic,” although different people have different interpretations of
“workflow.”

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler, Randy Stafford

Местами он склонен относить “Business Rules” к Доменой Логике (Domain Logic):

Проблемы возникли с усложнением доменой логики — бизнес-правил, алгоритмов вычислений, условий проверок и т.д.

The problem came with domain logic: business rules, validations, calculations, and the like.

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler

И даже признает наличие определенной расплывчатости:

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

Then there’s the matter of what comes under the term “business logic.”
I find this a curious term because there are few things that are less logical than business logic.

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler

Почему важно отделять Business Logic от Application Logic?¶

Поскольку целью создания приложения является реализация именно Business Logic — критически важно обеспечить их переносимость, и отделить их от Application Logic.
Эти два вида логики будут изменяться в разное время, с разной частотой и по разным причинам, поэтому их следует разделить
так, чтобы их можно было изменять независимо [2] .
В свое время Гради Буч сказал, что “Архитектура отражает важные проектные решения по формированию системы, где важность определяется стоимостью изменений” [2] .

Способы организации Логики Приложения (Application Logic)¶

Широко распространены четыре способа организации Логики Приложения (Application Logic):

  1. Оркестровый Сервис (“request/response”, т.е. сервис осведомлен об интерфейсе других сервисов), он же — Сервисный Слой (Service Layer).
  2. Хореографический Сервис (Event-Driven, т.е. loosely coupled), который является разновидностью паттерна Command, и используется, как правило, в Event-Driven Architecture (в частности, в CQRS и Event Sourcing приложениях, наглядный пример — reducer в Redux), и в DDD-приложениях (обработчик Domain/Integration Event).
  3. Front Controller и Application Controller (которые тоже, по сути, является разновидностью паттерна Command).

“A Front Controller handles all calls for a Web site, and is usually structured in two parts: a Web handler and a command hierarchy.”

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler and others.

“For both the domain commands and the view, the application controller needs a way to store something it can invoke.
A Command [Gang of Four] is a good choice, since it allows it to easily get hold of and run a block of code.”

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler and others.

4. Use Case (см. также), который также, является разновидностью паттерна Command.
На 15:50 Robert C. Martin проводит параллель между Use Case и паттерном Command.

Собственно говоря, производной паттерна Command является даже Method Object.

Use Case обязан своим существованием именно наличию application-specific Business Rules, которые не имеют смысла существования вне контекста приложения.
Он обеспечивает их независимость от приложения путем инверсии контроля (IoC).

Если бы Use Case не содержал Бизнес-Логики, то не было бы и смысла отделять его от Page Controller, иначе приложение пыталось бы абстрагироваться от самого себя же.

Мы видим, что в организации Логики Приложения широко применяются разновидности паттерна Команда (Command).

Рассмотренные способы организовывают, в первую очередь, Логику Приложения, и лишь во вторую очередь, Бизнес-Логику, которая не обязательно должна присутствовать, кроме случая использования Use Case, т.к. иначе он утратил бы причины для существования.

При правильной организации Бизнес-Логики, и высоком качестве ORM (в случае его использования, конечно же), зависимость Бизнес-Логики от приложения будет минимальна.
Основная сложность любого ORM заключается в том, чтобы организовать доступ к связанным объектам не подмешивая Логику Приложения (и логику доступа к данным) в Domain Models, — эту тему мы подробно рассмотрим в одном из следующих постов.

Понимание общих признаков в способах управления Логикой Приложения позволяет проектировать более гибкие приложения, и, как результат, более безболезненно заменять архитектурный шаблон, например, из Layered в Event-Driven.
Частично эта тема затрагивается в Chapter 16 “Independence” of “Clean Architecture” by Robert C. Martin и в разделе “Premature Decomposition” of Chapter 3 “How to Model Services” of “Building Microservices” by Sam Newman.

Что такое Сервис?¶

SERVICE — An operation offered as an interface that stands alone in the model, with no encapsulated state.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

In some cases, the clearest and most pragmatic design includes operations that do not
conceptually belong to any object. Rather than force the issue, we can follow the natural contours
of the problem space and include SERVICES explicitly in the model.

There are important domain operations that can’t find a natural home in an ENTITY or VALUE
OBJECT . Some of these are intrinsically activities or actions, not things, but since our modeling
paradigm is objects, we try to fit them into objects anyway…

A SERVICE is an operation offered as an interface that stands alone in the model, without
encapsulating state, as ENTITIES and VALUE OBJECTS do. S ERVICES are a common pattern in technical
frameworks, but they can also apply in the domain layer.

The name service emphasizes the relationship with other objects. Unlike ENTITIES and VALUE
OBJECTS , it is defined purely in terms of what it can do for a client. A SERVICE tends to be named for
an activity, rather than an entity—a verb rather than a noun. A SERVICE can still have an abstract,
intentional definition; it just has a different flavor than the definition of an object. A SERVICE should
still have a defined responsibility, and that responsibility and the interface fulfilling it should be
defined as part of the domain model. Operation names should come from the UBIQUITOUS
LANGUAGE or be introduced into it. Parameters and results should be domain objects.

SERVICES should be used judiciously and not allowed to strip the ENTITIES and VALUE OBJECTS of all
their behavior. But when an operation is actually an important domain concept, a SERVICE forms a
natural part of a MODEL-DRIVEN DESIGN . Declared in the model as a SERVICE, rather than as a
phony object that doesn’t actually represent anything, the standalone operation will not mislead
anyone.

A good SERVICE has three characteristics.

1. The operation relates to a domain concept that is not a natural part of an ENTITY or VALUE
OBJECT .
2. The interface is defined in terms of other elements of the domain model.
3. The operation is stateless.

Statelessness here means that any client can use any instance of a particular SERVICE without
regard to the instance’s individual history. The execution of a SERVICE will use information that is
accessible globally, and may even change that global information (that is, it may have side
effects). But the SERVICE does not hold state of its own that affects its own behavior, as most
domain objects do.

When a significant process or transformation in the domain is not a natural
responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as a
standalone interface declared as a SERVICE. Define the interface in terms of the
language of the model and make sure the operation name is part of the UBIQUITOUS
LANGUAGE. Make the SERVICE stateless.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

Классификация Сервисов по уровням логики¶

Eric Evans разделяет Сервисы на три уровня логики:

Partitioning Services into Layers

Application

Funds Transfer App Service

  • Digests input (such as an XML request).
  • Sends message to domain service for fulfillment.
  • Listens for confirmation.
  • Decides to send notification using infrastructure service.
Domain

Funds Transfer Domain Service

  • Interacts with necessary Account and Ledger objects, making appropriate debits and credits.
  • Supplies confirmation of result (transfer allowed or not, and so on).
Infrastructure Send Notification Service
Sends e-mails, letters, and other communications as directed by the application.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

Most SERVICES discussed in the literature are purely technical and belong in the infrastructure layer.
Domain and application SERVICES collaborate with these infrastructure SERVICES.
For example, a bank might have an application that sends an e-mail to a customer when an account balance falls below a specific threshold.
The interface that encapsulates the e-mail system, and perhaps alternate means of notification, is a SERVICE in the infrastructure layer.

It can be harder to distinguish application SERVICES from domain SERVICES.
The application layer is responsible for ordering the notification.
The domain layer is responsible for determining if a threshold was met—though this task probably does not call for a SERVICE, because it would fit the responsibility of an “account” object.
That banking application could be responsible for funds transfers.
If a SERVICE were devised to make appropriate debits and credits for a funds transfer,that capability would belong in the domain layer.
Funds transfer has a meaning in the banking domain language, and it involves fundamental business logic.
Technical SERVICES should lack any business meaning at all.

Many domain or application SERVICES are built on top of the populations of ENTITIES and VALUES, behaving like scripts that organize the potential of the domain to actually get something done.
ENTITIES and VALUE OBJECTS are often too fine-grained to provide a convenient access to the capabilities of the domain layer.
Here we encounter a very fine line between the domain layer and the application layer.
For example, if the banking application can convert and export our transactions into a spreadsheet file for us to analyze, that export is an application SERVICE.
There is no meaning of “file formats” in the domain of banking, and there are no business rules involved.

On the other hand, a feature that can transfer funds from one account to another is a domain SERVICE because it embeds significant business rules (crediting and debiting the appropriate accounts, for example) and because a “funds transfer” is a meaningful banking term.
In this case, the SERVICE does not do much on its own; it would ask the two Account objects to do most of the work.
But to put the “transfer” operation on the Account object would be awkward, because the operation involves two accounts and some global rules.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

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

Domain Models (116) are preferable to Transaction Scripts (110) for avoiding domain logic duplication and
for managing complexity using classical design patterns.
But putting application logic into pure domain object classes has a couple of undesirable consequences.
First, domain object classes are less reusable across applications if they implement application-specific logic and depend on application-specific packages.
Second, commingling both kinds of logic in the same classes makes it harder to reimplement the application
logic in, say, a workflow tool if that should ever become desirable.
For these reasons Service Layer factors each kind of business logic into a separate layer, yielding the usual benefits of layering and rendering the pure domain object classes more reusable from application to application.

— “Patterns of Enterprise Application Architecture” [3]

Сервисы уровня Доменной Логики (Domain Logic)¶

Политика самого высокого уровня принадлежит Доменной Логике (Domain Logic), поэтому, с нее и начнем.
К счастью, это самый немногочисленный представитель Сервисов.

Подробно тему Сервисов Логики Предметной Области и причины их существования раскрывает Vaughn Vernon:

Further, don’t confuse a Domain Service with an Application Service.
We don’t want to house business logic in an Application Service, but we do want business logic housed in a Domain Service.
If you are confused about the difference, compare with Application.
Briefly, to differentiate the two, an Application Service, being the natural client of the domain model, would normally be the client of a Domain Service.
You’ll see that demonstrated later in the chapter.
Just because a Domain Service has the word service in its name does not mean that it is required to be a coarse-grained, remote-capable, heavyweight transactional operation.

You can use a Domain Service to

  • Perform a significant business process
  • Transform a domain object from one composition to another
  • Calculate a Value requiring input from more than one domain object

— “Implementing Domain-Driven Design” by Vaughn Vernon

Сервисы уровня Логики Приложения (Application Logic)¶

Это самый многочисленный представитель Сервисов.
Именно его часто называют Сервисный Слой (Service Layer).

Сервисы уровня Инфраструктурного Слоя (Infrastructure Layer)¶

Отдельно следует выделять Сервисы уровня Инфраструктурного Слоя (Infrastructure Layer).

The infrastructure layer usually does not initiate action in the domain layer. Being “below” the
domain layer, it should have no specific knowledge of the domain it is serving. Indeed, such
technical capabilities are most often offered as SERVICES . For example, if an application needs to
send an e-mail, some message-sending interface can be located in the infrastructure layer and the
application layer elements can request the transmission of the message. This decoupling gives
some extra versatility. The message-sending interface might be connected to an e-mail sender, a
fax sender, or whatever else is available. But the main benefit is simplifying the application layer,
keeping it narrowly focused on its job: knowing when to send a message, but not burdened with
how.

The application and domain layers call on the SERVICES provided by the infrastructure layer. When
the scope of a SERVICE has been well chosen and its interface well designed, the caller can remain
loosely coupled and uncomplicated by the elaborate behavior the SERVICE interface encapsulates.

But not all infrastructure comes in the form of SERVICES callable from the higher layers. Some
technical components are designed to directly support the basic functions of other layers (such as
providing an abstract base class for all domain objects) and provide the mechanisms for them to
relate (such as implementations of MVC and the like). Such an “architectural framework” has
much more impact on the design of the other parts of the program.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

Infrastructure Layer — Provides generic technical capabilities that support the higher layers:
message sending for the application, persistence for the domain, drawing
widgets for the UI, and so on. The infrastructure layer may also support
the pattern of interactions between the four layers through an
architectural framework.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

Классификация Сервисов по способу взаимодействия¶

По способу взаимодействия Сервисы разделяются на Оркестровые (“request/response”, т.е. сервис осведомлен об интерфейсе других сервисов) и Хореографические (Event-Driven, т.е. loosely coupled) [8].
Их еще называют идиоматическими стилями взаимодействия.
Главный недостаток первого — это высокая осведомленность об интерфейсе других Сервисов, т.е. Высокое Сопряжение (High Coupling), что снижает их реиспользование.
Последний же является разновидностью паттерна Command, и используется, как правило, в Event-Driven Architecture (в частности, в CQRS и Event Sourcing приложениях, наглядный пример — reducer в Redux), и в DDD-приложениях (обработчик Domain/Integration Event).

With orchestration, we rely on a central brain to guide and drive the process, much like the conductor in an orchestra. With choreography, we inform each part of the system of its job, and let it work out the details, like dancers all finding their way and reacting to others around them in a ballet.

<…>

The downside to this orchestration approach is that the customer service can become too much of a central governing authority. It can become the hub in the middle of a web, and a central point where logic starts to live.
I have seen this approach result in a small number of smart “god” services telling anemic CRUD-based services what to do.

With a choreographed approach, we could instead just have the customer service emit an event in an asynchronous manner, saying Customer created.
The email service, postal service, and loyalty points bank then just subscribe to these events and react accordingly, as in Figure 4-4.
This approach is significantly more decoupled.
If some other service needed to reach to the creation of a customer, it just needs to subscribe to the events and do its job when needed.
The downside is that the explicit view of the business process we see in Figure 4-2 is now only implicitly reflected in our system.

— “Building Microservices. Designing Fine-Grained Systems” [8] by Sam Newman

Оркестровые Сервисы¶

Оркестровые Сервисы являются представителями классического Сервисного Слоя, и подробнее рассматриваются ниже по тексту.

Хореографические Сервисы¶

Существует интересная статья “Clarified CQRS” by Udi Dahan, на которую ссылается Martin Fowler в своей статье “CQRS”.

И в этой статье есть интересный момент.

The reason you don’t see this layer explicitly represented in CQRS is that it isn’t really there…

— “Clarified CQRS” by Udi Dahan

На самом деле, обработчик команды — это и есть Сервис, только событийно-ориентированный, который следует заданному интерфейсу.
Он должен содержать логику уровня приложения (а не бизнес-логику).

Our command processing objects in the various autonomous components actually make up our service layer.

— “Clarified CQRS” by Udi Dahan

Хореографические Сервисы бывают только уровня Логики Приложения, даже если они подписаны на Доменные События (Domain Event).

Частые ошибки проектирования Хореографических Сервисов¶

Иногда, особенно у frontend-разработчиков, можно наблюдать как они проксируют Оркестровыми Сервисами обращения к Хореографическим Сервисам.
Часто это происходит при использовании Redux/NgRx в Angular-приложении, в котором широко используются Сервисы.
Имея слабо-сопряженные (Low Coupling) событийно-ориентированные Сервисы в виде обработчиков команды, было бы проектной ошибкой пытаться связать их в сильно-зацепленные (High Coupling) классические Сервисы Оркестрового типа (с единственной целью — помочь Логике Приложения скрыть их от самой же себя).

Each command is independent of the other, so why should we allow the objects which handle them to depend on each other?

— “Clarified CQRS” by Udi Dahan

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

Другой распространенной ошибкой является размещение Бизнес-Логики в Хореографических Сервисах и искусственное вырождение поведения Доменных Моделей с выносом всей бизнес-логики в обработчики команд, т.е. в Сервисы.

Это приводит к появлению проблемы, о которой говорил Eric Evans:

“Если требования архитектурной среды к распределению обязанностей таковы, что элементы, реализующие концептуальные объекты, оказываются физически разделенными, то код больше не выражает модель.

Нельзя разделять до бесконечности, у человеческого ума есть свои пределы, до которых он еще способен соединять разделенное;
если среда выходит за эти пределы, разработчики предметной области теряют способность расчленять модель на осмысленные фрагменты.”

“If the framework’s partitioning conventions pull apart the elements implementing the
conceptual objects, the code no longer reveals the model.

There is only so much partitioning a mind can stitch back together, and if the framework uses
it all up, the domain developers lose their ability to chunk the model into meaningful pieces.”

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” by Eric Evans

В приложениях с обширной бизнес-логикой это может сильно ухудшить качество бизнес-моделирования, и препятствовать процессу дистилляции моделей по мере переработки бизнес-знаний [4].
Также такой код обретает признаки “Divergent Change” [7] и “Shotgun Surgery” [7], что сильно затрудняет исправление ошибок бизнес-моделирования и Итерационное Проектирование (Evolutionary Design).
В конечном итоге это приводит к стремительному росту стоимости изменения программы.

Должен заметить, что Udi Dahan в своей статье допускает и использование Transaction Script для организации бизнес-логики.
В таком случае, выбор между Transaction Script и Domain Model подробно рассмотрен в “Patterns of Enterprise Application Architecture” by M. Fowler and others.
Transaction Script может быть уместным при сочетании Redux и GraphQL для минимизации сетевого трафика.
При использовании же REST-API, и наличии обширной бизнес-логики, более уместным будет использование Domain Model и DDD.

Классификация Сервисов по способу обмена данными¶

По способу обмена данными Сервисы разделяются на Синхронные и Асинхронные.

Классификация Сервисов по состоянию¶

Stateless Service¶

Как правило, большинство сервисов являются stateless, т.е. не имеют состояния.
Они хорошо изучены, и добавить по ним нечего.

Statefull Service¶

Классы UseCases/Interactors [2] являются разновидностью паттерна Команда (Command), и, в определенной мере, могут рассматриваться как Statefull Сервис.

Похожую идею выражает и Eric Evans:

We might like to create a Funds Transfer object to represent the two entries plus the rules and history around the transfer. But we are still left with calls to SERVICES in the interbank networks.
What’s more, in most development systems, it is awkward to make a direct interface between a domain object and external resources. We can dress up such external SERVICES with a FACADE that takes inputs in terms of the model, perhaps returning a Funds Transfer object as its result.
But whatever intermediaries we might have, and even though they don’t belong to us, those SERVICES are carrying out the domain responsibility of funds transfer.

— “Domain-Driven Design: Tackling Complexity in the Heart of Software” [4]

И Randy Stafford с Martin Fowler:

Двумя базовыми вариантами реализации слоя служб являются создание интерфейса
доступа к домену (domain facade) и конструирование сценария операции (operation script).
При использовании подхода, связанного с интерфейсом доступа к домену, слой служб
реализуется как набор “тонких” интерфейсов, размещенных “поверх” модели предметной
области. В классах, реализующих интерфейсы, никакая бизнес-логика отражения не
находит — она сосредоточена исключительно в контексте модели предметной области.
Тонкие интерфейсы устанавливают границы и определяют множество операций, посредством
которых клиентские слои взаимодействуют с приложением, обнаруживая тем самым
характерные свойства слоя служб.

Создавая сценарий операции, вы реализуете слой служб как множество более “толстых”
классов, которые непосредственно воплощают в себе логику приложения, но за бизнес-логикой
обращаются к классам домена. Операции, предоставляемые клиентам слоя
служб, реализуются в виде сценариев, создаваемых группами в контексте классов, каждый
из которых определяет некоторый фрагмент соответствующей логики. Подобные
классы, расширяющие супертип слоя (Layer Supertype, 491) и уточняющие объявленные
в нем абстрактные характеристики поведения и сферы ответственности, формируют “службы”
приложения (в названиях служебных типов принято употреблять суффикс “Service”).
Слой служб и заключает в себе эти прикладные классы.

The two basic implementation variations are the domain facade approach and the operation script approach. In
the domain facade approach a Service Layer is implemented as a set of thin facades over a Domain Model
(116). The classes implementing the facades don’t implement any business logic. Rather, the Domain Model
(116) implements all of the business logic. The thin facades establish a boundary and set of operations through
which client layers interact with the application, exhibiting the defining characteristics of Service Layer.

In the operation script approach a Service Layer is implemented as a set of thicker classes that directly
implement application logic but delegate to encapsulated domain object classes for domain logic. The
operations available to clients of a Service Layer are implemented as scripts, organized several to a class
defining a subject area of related logic. Each such class forms an application “service,” and it’s common for
service type names to end with “Service.” A Service Layer is comprised of these application service classes,
which should extend a Layer Supertype (475), abstracting their responsibilities and common behaviors.

— “Patterns of Enterprise Application Architecture” [3] by Martin Fowler, Randy Stafford

Обратите внимание на использование термина “Domain Model”.
Эти ребята — последние из числа тех, кто может спутать “Domain Model” и “DataMapper”, особенно, при таком количестве редакторов и рецензентов.
Т.е. клиент ожидает от доменной модели интерфейс, который она, по какой-то причине (обычно это Single Responsibility Principle), не реализует и не должна реализовать.
С другой стороны, клиент не может реализовать это поведение сам, так как это привело бы к появлению “G14: Feature Envy” [1].
Для выравнивания интерфейсов служит паттерн Adapter (aka Wrapper), см. “Design Patterns Elements of Reusable Object-Oriented Software” [6].
Отличается Statefull Services от обычного Adapter только тем, что он содержит логику более низкого уровня, т.е. Логику Приложения (Application Logic), нежели Доменная Модель.

Этот подход сильно напоминает мне “Cross-Cutting Concerns” [1] с тем только отличием, что “Cross-Cutting Concerns” реализует интерфейс оригинального объекта, в то время как domain facade дополняет его.
Когда объект-обертка реализует интерфейс оригинального объекта, то его обычно называют Aspect или Decorator.
Часто в таких случаях можно услышать термин Proxy, но, на самом деле паттерн Proxy имеет немного другое назначение.
Такой подход часто используется для того, чтобы наделить Доменную Модель логикой доступа к связанным объектам, при этом сохраняя Доменную Модель совершенно “чистой”, т.е. отделенной от поведения логики более низкого уровня.

При работе с унаследованным кодом мне доводилось встречать разбухшие Доменные Модели с огромным числом методов (я встречал до нескольких сотен методов).
При анализе таких моделей часто обнаруживаются посторонние обязанности в классе, а размер класса, как известно, измеряется количеством его обязанностей.
Statefull Сервисы и паттерн Adapter — хорошая альтернатива для того, чтобы вынести из модели несвойственные ей обязанности, и заставить похудеть разбухшие модели.

Назначение Сервисного Слоя¶

Слой служб устанавливает множество доступных действий и координирует отклик приложения на каждое действие.

A Service Layer defines an application’s boundary with a layer of services that establishes a set of available
operations and coordinates the application’s response in each operation.

— “Patterns of Enterprise Application Architecture” [3]

Корпоративные приложения обычно подразумевают применение разного рода интерфейсов к хранимым данным и реализуемой логике — загрузчиков данных, интерфейсов пользователя, шлюзов интеграции и т.д.
Несмотря на различия в назначении, подобные интерфейсы часто нуждаются в одних и тех же функциях взаимодействия с приложением для манипулирования данными и выполнения бизнес-логики.
Функции могут быть весьма сложными и способны включать транзакции, охватывающие многочисленные ресурсы, а также операции по координации реакций на действия.
Описание логики взаимодействия в каждом отдельно взятом интерфейсе сопряжено с многократным повторением одних и тех же фрагментов кода.

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

Enterprise applications typically require different kinds of interfaces to the data they store and the logic they implement: data loaders, user interfaces, integration gateways, and others.
Despite their different purposes, these interfaces often need common interactions with the application to access and manipulate its data and invoke its business logic.
The interactions may be complex, involving transactions across multiple resources and the coordination of several responses to an action.
Encoding the logic of the interactions separately in each interface causes a lot of duplication.

A Service Layer defines an application’s boundary and its set of available operations from the perspective of interfacing client layers.
It encapsulates the application’s business logic, controlling transactions and coordinating responses in the implementation of its operations.

— “Patterns of Enterprise Application Architecture” [3]

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

The benefit of Service Layer is that it defines a common set of application operations available to many kinds
of clients and it coordinates an application’s response in each operation. The response may involve application
logic that needs to be transacted atomically across multiple transactional resources. Thus, in an application
with more than one kind of client of its business logic, and complex responses in its use cases involving
multiple transactional resources, it makes a lot of sense to include a Service Layer with container-managed
transactions, even in an undistributed architecture.

— “Patterns of Enterprise Application Architecture” [3]

Один из общих подходов к реализации бизнес-логики состоит в расщеплении слоя
предметной области на два самостоятельных слоя: “поверх” модели предметной области
или модуля таблицы располагается слой служб (Service Layer, 156). Обычно это целесообразно
только при использовании модели предметной области или модуля таблицы, поскольку
слой домена, включающий лишь сценарий транзакции, не настолько сложен,
чтобы заслужить право на создание дополнительного слоя. Логика слоя представления
взаимодействует с бизнес-логикой исключительно при посредничестве слоя служб, который
действует как API приложения.

Поддерживая внятный интерфейс приложения (API), слой служб подходит также для
размещения логики управления транзакциями и обеспечения безопасности. Это дает
возможность снабдить подобными характеристиками каждый метод слоя служб. Для таких
целей обычно применяются файлы свойств, но атрибуты .NET предоставляют удобный
способ описания параметров непосредственно в коде.

A common approach in handling domain logic is to split the domain layer in two. A Service Layer (133) is
placed over an underlying Domain Model (116) or Table Module (125). Usually you only get this with a
Domain Model (116) or Table Module (125) since a domain layer that uses only Transaction Script (110) isn’t
complex enough to warrant a separate layer. The presentation logic interacts with the domain purely through
the Service Layer (133), which acts as an API for the application.

As well as providing a clear API, the Service Layer (133) is also a good spot to place such things as
transaction control and security. This gives you a simple model of taking each method in the Service Layer
(133) and describing its transactional and security characteristics. A separate properties file is a common
choice for this, but .NET’s attributes provide a nice way of doing it directly in the code.

— “Patterns of Enterprise Application Architecture” [3]

Традиционно Сервисный Слой относится к логике уровня Приложения.
Т.е. Сервисный Слой имеет более низкий уровень, чем слой предметной области (domain logic), именуемый так же деловыми регламентами (business rules).
Из этого также следует и то, что объекты предметной области не должны быть осведомлены о наличии Сервисного Слоя.

Кроме перечисленного выше, сервисный слой может выполнять следующие обязанности:

  • Компоновки атомарных операций (например, требуется одновременно сохранить данные в БД, редисе, и на файловой системе, в рамках одной бизнес-транзакции, или откатить все назад).
  • Сокрытия источника данных (здесь он дублирует функции паттерна Repository) и может быть опущен, если нет других причин.
  • Компоновки реиспользуемых операций уровня приложения (например, некая часть логики уровня приложения используется в нескольких различных контроллерах).
  • Как основа для реализации Интерфейса удаленного доступа.
  • Когда контроллер имеет какой-то большой метод, он нуждается в декомпозиции, и к нему применяется Extract Method для вычленения обязанностей в отдельные методы. При этом растет количество методов класса, что влечет за собой падение его сфокусированности или Связанности (т.е. коэффициент совместного использования свойств класса его методами). Чтобы восстановить связанность, эти методы выделяются в отдельный класс, образуя Method Object. И вот этот метод-объект и может быть преобразован в сервисный слой.
  • Сервисный слой можно использовать в качестве концентратора запросов, если он стоит поверх паттерна Repository и использует паттерн Query object. Дело в том, что паттерн Repository ограничивает свой интерфейс посредством интерфейса Query Object. А так как класс не должен делать предположений о своих клиентах, то накапливать предустановленные запросы в классе Repository нельзя, ибо он не может владеть потребностями всех клиентов. Клиенты должны сами заботиться о себе. А сервисный слой как раз и создан для обслуживания клиентов.

В остальных случаях логику сервисного слоя можно размещать прямо на уровне приложения (обычно — контроллер).

Когда Сервисный Слой не нужен?¶

Гораздо легче ответить на вопрос, когда слой служб не нужно использовать. Скорее
всего, вам не понадобится слой служб, если у логики приложения есть только одна категория
клиентов, например пользовательский интерфейс, отклики которого на варианты
использования не охватывают несколько ресурсов транзакций. В этом случае управление
транзакциями и выбор откликов можно возложить на контроллеры страниц (Page
Controller, 350), которые будут обращаться непосредственно к слою источника данных.
Тем не менее, как только у вас появится вторая категория клиентов или начнет
использоваться второй ресурс транзакции, вам неизбежно придется ввести слой служб, что
потребует полной переработки приложения.

The easier question to answer is probably when not to use it. You probably don’t need a Service Layer if your
application’s business logic will only have one kind of client say, a user interface and its use case responses
don’t involve multiple transactional resources. In this case your Page Controllers can manually control
transactions and coordinate whatever response is required, perhaps delegating directly to the Data Source
layer.
But as soon as you envision a second kind of client, or a second transactional resource in use case responses, it
pays to design in a Service Layer from the beginning.

— “Patterns of Enterprise Application Architecture” [3]

Тем не менее, широко распространена точка зрения, что доступ к модели должен всегда производиться через сервисный слой:

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

My preference is thus to have the thinnest Service Layer (133) you can, if you even need one. My usual
approach is to assume that I don’t need one and only add it if it seems that the application needs it. However, I
know many good designers who always use a Service Layer (133) with a fair bit of logic, so feel free to ignore
me on this one.

— “Patterns of Enterprise Application Architecture” [3]

Идея вычленения слоя служб из слоя предметной области основана на подходе, предполагающем возможность отмежевания логики процесса от “чистой” бизнес-логики.
Уровень служб обычно охватывает логику, которая относится к конкретному варианту
использования системы или обеспечивает взаимодействие с другими инфраструктурами
(например, с помощью механизма сообщений).
Стоит ли иметь отдельные слои служб и предметной области — вопрос, достойный обсуждения.
Я склоняюсь к мысли о том, что подобное решение может оказаться полезным, хотя и не всегда, но некоторые уважаемые мною коллеги эту точку зрения не разделяют.

The idea of splitting a services layer from a domain layer is based on a separation of workflow logic from
pure domain logic. The services layer typically includes logic that’s particular to a single use case and also
some communication with other infrastructures, such as messaging. Whether to have separate services and
domain layers is a matter some debate. I tend to look as it as occasionally useful rather than mandatory, but
designers I respect disagree with me on this.

— “Patterns of Enterprise Application Architecture” [3]

Сервис — не обертка для DataMapper¶

Часто Service Layer ошибочно делают как враппер над DataMapper.
Это не совсем верно.
Data Mapper обслуживает одну Domain Model (модель предметной области), Repository обслуживает один Aggregate [9], а Cервис обслуживает клиента (или группу клиентов).
Сервисный слой может манипулировать в рамках бизнес-транзакции или в интересах клиента несколькими мапперами и другими сервисами.
Поэтому методы сервиса обычно содержат имя возвращаемой Модели Домена в качестве суффикса (например, getUser()), в то время как методы Маппера и Хранилища в этом суффиксе не нуждается (так как имя МОдели Домена уже и так присутствует в имени класса Маппера, и Маппер обслуживает только одну Модель Домена).

Установить, какие операции должны быть размещены в слое служб, отнюдь не сложно.
Это определяется нуждами клиентов слоя служб, первой (и наиболее важной) из
которых обычно является пользовательский интерфейс.

Identifying the operations needed on a Service Layer boundary is pretty straightforward. They’re determined
by the needs of Service Layer clients, the most significant (and first) of which is typically a user interface.
(“Patterns of Enterprise Application Architecture” [3])

Инверсия Управления¶

Используйте инверсию управления, желательно в виде “Пассивного внедрения зависимостей” [1], Dependency Injection (DI).

Истинное внедрение зависимостей идет еще на один шаг вперед. Класс не
предпринимает непосредственных действий по разрешению своих зависимостей;
он остается абсолютно пассивным. Вместо этого он предоставляет set-методы
и/или аргументы конструктора, используемые для внедрения зависимостей.
В процессе конструирования контейнер DI создает экземпляры необходимых
объектов (обычно по требованию) и использует аргументы конструктора или
set-методы для скрепления зависимостей. Фактически используемые
зависимые объекты задаются в конфигурационном файле или на программном уровне
в специализированном конструирующем модуле.

True Dependency Injection goes one step further. The class takes no direct steps to
resolve its dependencies; it is completely passive. Instead, it provides setter methods or
constructor arguments (or both) that are used to inject the dependencies. During the con-
struction process, the DI container instantiates the required objects (usually on demand)
and uses the constructor arguments or setter methods provided to wire together the depen-
dencies. Which dependent objects are actually used is specified through a configuration
file or programmatically in a special-purpose construction module.
“Clean Code: A Handbook of Agile Software Craftsmanship” [1]

Одна из основных обязанностей Сервисного Слоя — это сокрытие источника данных.
Для тестирования можно использовать фиктивный Сервис (Service Stub).
Этот же прием можно использовать для параллельной разработки, когда реализация сервисного слоя еще не готова.
Иногда бывает полезно подменить Сервис генератором фэйковых данных.
В общем, пользы от сервисного слоя будет мало, если нет возможности его подменить (или подменить используемые им зависимости).

Распространенная проблема Django-приложений¶

Широко распространенная ошибка — использование класса django.db.models.Manager (а то и django.db.models.Model) в качестве сервисного слоя.
Нередко можно встретить, как какой-то метод класса django.db.models.Model принимает в качестве аргумента объект HTTP-запроса django.http.request.HttpRequest, например, для проверки прав.

Объект HTTP-запроса — это логика уровня приложения (application), в то время как класс модели — это логика уровня предметной области (domain), т.е. объекты реального мира, которую также называют правилами делового регламента (business rules).
Проверка прав — это тоже логика уровня приложения.

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

Классу django.db.models.Manager более всего соответствует класс Finder описанный в “Patterns of Enterprise Application Architecture” [3].

При реализации шлюза записи данных возникает вопрос: куда “пристроить” методы
поиска, генерирующие экземпляр данного типового решения? Разумеется, можно
воспользоваться статическими методами поиска, однако они исключают возможность
полиморфизма (что могло бы пригодиться, если понадобится определить разные методы
поиска для различных источников данных). В подобной ситуации часто имеет смысл
создать отдельные объекты поиска, чтобы у каждой таблицы реляционной базы данных
был один класс для проведения поиска и один класс шлюза для сохранения результатов
этого поиска.

Иногда шлюз записи данных трудно отличить от активной записи (Active Record, 182).
В этом случае следует обратить внимание на наличие какой-либо логики домена; если
она есть, значит, это активная запись. Реализация шлюза записи данных должна включать
в себя только логику доступа к базе данных и никакой логики домена.

With a Row Data Gateway you’re faced with the questions of where to put the find operations that generate this
pattern. You can use static find methods, but they preclude polymorphism should you want to substitute
different finder methods for different data sources. In this case it often makes sense to have separate finder
objects so that each table in a relational database will have one finder class and one gateway class for the results.

It’s often hard to tell the difference between a Row Data Gateway and an Active Record (160). The crux of the
matter is whether there’s any domain logic present; if there is, you have an Active Record (160). A Row Data
Gateway should contain only database access logic and no domain logic.
(Chapter 10. “Data Source Architectural Patterns : Row Data Gateway”, “Patterns of Enterprise Application Architecture” [3])

Хотя Django не использует паттерн Repository, она использует абстракцию критериев выборки, своего рода разновидность паттерна Query Object.
Подобно паттерну Repository, класс модели (ActiveRecord) ограничивает свой интерфейс посредством интерфейса Query Object.
Клиенты должны пользоваться предоставленным интерфейсом, а не возлагать на модель и ее менеджер свои обязанности по знанию своих запросов.
А так как никакой класс не должен делать предположений о своих клиентах, то накапливать предустановленные запросы в классе модели нельзя, ибо он не может владеть потребностями всех клиентов.
Клиенты должны сами заботиться о себе.
А сервисный слой как раз и создан для обслуживания клиентов.

Попытки исключить Сервинсый Слой из Django-приложений приводит к появлению менеджеров с огромным количеством методов.

Хорошей практикой было бы сокрытие посредством сервисного слоя способа реализации Django Models в виде ActiveRecord.
Это позволит безболезненно подменить ORM в случае необходимости.

Можно было бы поспорить и о размещении логики приложения. Думаю, некоторые
предпочли бы реализовать ее в методах объектов домена, таких, как
Contract. calculateRevenueRecognitions (), ИЛИ вообще В слое источника данных, ЧТО
позволило бы обойтись без отдельного слоя служб. Тем не менее подобное размещение
логики приложения кажется мне весьма нежелательным, и вот почему. Во-первых, классы
объектов домена, которые реализуют логику, специфичную для приложения (и зависят
от шлюзов и других объектов, специфичных для приложения), менее подходят для
повторного использования другими приложениями. Это должны быть модели частей
предметной области, представляющих интерес для данного приложения, поэтому подобные
объекты вовсе не обязаны описывать возможные отклики на все варианты использования
приложения. Во-вторых, инкапсуляция логики приложения на более высоком
уровне (каковым не является слой источника данных) облегчает изменение реализации
этого слоя, возможно, посредством некоторых специальных инструментальных средств.

Some might also argue that the application logic responsibilities could be implemented in domain object
methods, such as Contract.calculateRevenueRecognitions(), or even in the data source layer,
thereby eliminating the need for a separate Service Layer. However, I find those allocations of responsibility
undesirable for a number of reasons. First, domain object classes are less reusable across applications if they
implement application-specific logic (and depend on application-specific Gateways (466), and the like). They
should model the parts of the problem domain that are of interest to the application, which doesn’t mean all of
application’s use case responsibilities. Second, encapsulating application logic in a “higher” layer
dedicated to that purpose (which the data source layer isn’t) facilitates changing the implementation of that
layer perhaps to use a workflow engine.
(“Patterns of Enterprise Application Architecture” [3])

Проблема Django-аннотаций¶

Я часто наблюдал такую проблему, когда в Django Model добавлялось какое-то новое поле, и начинали сыпаться проблемы, так как это имя уже было использовано либо с помощью аннотаций, либо с помощью Raw-SQL.
Также реализация аннотаций в Django ORM делает невозможным использование паттерна Identity Map.
Storm ORM/SQLAlchemy реализуют аннотации более удачно.
Если Вам все-таки пришлось работать с Django Model, воздержитесь от использования механизма Django аннотаций в пользу голого паттерна DataMapper.

Особенности сервисного слоя на стороне клиента¶

Использование концепции агрегата и библиотек реактивного программирования, таких как RxJS, позволяет реализовывать Сервисный Слой с помощью простейшего паттерна Gateway, смотрите, например, учебный пример из документации Angular.
В таком случае, Query Object обычно реализуется в виде простого словаря, который преобразуется в список GET-параметров URL.
Общается такой Сервис с сервером обычно либо посредством JSON-RPC, либо посредством REST-API Actions.

Все работает хорошо до тех пор, пока не возникает необходимость выражать приоритезированные запросы, например, использующие логический оператор OR, который использует меньший приоритет чем логический оператор AND.
Это порождает вопрос, кто должен отвечать за построение запроса, Сервисный Слой клиента или Сервисный Слой сервера?

С одной стороны, сервер не должен делать предположений о своих клиентах, и должен ограничивать свой интерфейс посредством интерфейса Query Object.
Но это резко увеличивает уровень сложности клиента, в частности, при реализации Service Stub.
Для облегчения реализации можно использовать библиотеку rql, упомянутую в статье “Реализация паттерна Repository в браузерном JavaScript”.

С другой стороны, Сервисный Слой, пусть и удаленного вызова, предназначен для обслуживания клиентов, а значит, может концентрировать в себе логику построения запросов.
Если клиент не содержит сложной логики, позволяющей интерпретировать приоритезированные запросы для Service Stub, то нет необходимости его усложнять этим.
В таком случае проще добавить новый метод в сервисе удаленного вызова, и избавиться от необходимости в приоритезированных запросах.

Проблема параллельного обновления¶

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

Одна из самых острых проблем — это проблема параллельного обновления данных.

Все состояния гонки (race condition), взаимоблокировки (deadlocks) и проблемы параллельного обновления обусловлены изменяемостью переменных.
Если в программе нет изменяемых переменных, она никогда не окажется в состоянии гонки и никогда не столкнется с проблемами одновременного изменения.
В отсутствие изменяемых блокировок программа не может попасть в состояние взаимоблокировки.

All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables.
You cannot have a race condition or a concurrent update problem if no variable is ever updated.
You cannot have deadlocks without mutable locks.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin

Любой порядок выражается в правильном наложении ограничений.

CQRS¶

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

“it allows us to host the two services differently eg: we can host the read service on 25 servers and the write service on two.
The processing of commands and queries is fundamentally asymmetrical, and scaling the services symmetrically does not make a lot of sense.”

— “CQRS, Task Based UIs, Event Sourcing agh!” by Greg Young

Управление Логикой Приложения и Бизнес-Логикой хорошо раскрывается в статье “Clarified CQRS” by Udi Dahan.

Использование CQRS способствует использованию парадигмы Функционального Программирования.

— В последнее время наметилась тенденция в популяризации функциональных языков и функциональной парадигмы программирования. Что вы скажите, является ли объектная технология конкурентом функциональному программированию?

— Нет, эти две парадигмы не являются конкурентами, они успешно могут дополнять друг друга. Тем не менее, тенденция к функциональному программированию является важной и интересной.

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

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

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

— Да, я кажется читал эту статью, которая затем вошла в качестве одной из глав в книгу “Beautiful Architecture”.

— Вы знаете об этом? Я очень впечатлен.

— (Смеюсь…) Да, и насколько я помню, это был ваш ответ на статью Саймона Пейтона Джонса, в которой автор старался показать, что ФП подход является более предпочтительным.

— Да, совершенно верно.

ПРИМЕЧАНИЕ: Речь идет о статье Бертрана “Software Architecture: Functional vs. Object-Oriented Design in Beautiful Architecture”, опубликованной в книге “Идеальная архитектура. Ведущие специалисты о красоте программных архитектур.”. Эта статья Мейера была ответом на статью Саймона “Composing contracts: an adventure in financial engineering.”

— Давайте все же немного вернемся к вопросу OOP vs FP. Какие именно преимущества у функционального подхода на “низком уровне”?

— В Eiffel существует очень важный принцип, под названием Command-Query Separation Principle, который можно рассматривать, в некотором роде, как сближение ОО и ФП миров. Я не считаю, что наличие состояния – это однозначно плохо. Но очень важно, чтобы мы могли ясно различать операции, которые это состояние изменяют (т.е. командами), и операции, которые лишь возвращают информацию о состоянии, его не изменяя (т.е. запросами). В других языках эта разница отсутствует. Так, например, в С/С++ часто пишут функции, которые возвращают результат и изменяют состояние. Следование этому принципу позволяет безопасно использовать выражения с запросами зная, что они не изменяют состояние. В некоторых случаях можно пойти еще дальше и работать в чисто функциональном мире с полным отсутствием побочных эффектов.

— Bertrand Meyer в интервью Сергея Теплякова “Интервью с Бертраном Мейером“

For both theoretical and practical reasons detailed elsewhere [10], the command-query separation principle is a methodological rule, not a language feature, but all serious software developed in Eiffel observes it scrupulously, to great referential transparency advantage.
Although other schools of object-oriented programming regrettable do not apply it (continuing instead the C style of calling functions rather than procedures to achieve changes), but in my view it is a key element of the object-oriented approach.
It seems like a viable way to obtain the referential transparency goal of functional programming — since expressions, which only involve queries, will not change the state, and hence can be understood as in traditional mathematics or a functional language — while acknowledging, through the notion of command, the fundamental role of the concept of state in modeling systems and computations.

— “Software architecture: object-oriented vs functional” by Bertrand Meyer

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

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

Однако, несмотря на открывшиеся возможности использовать Функциональное Программирование в коде, само хранилище данных (IO-устройство) все еще подвержено проблемам параллельного обновления, поскольку имеет изменяемые записи, а значит, имеет побочный эффект.

Решением этой проблемы обычно является замена CRUD (Create, Read, Update, Delete) на CR, т.е. наложение ограничения на изменение (Update) и удаление (Delete) записей в хранилище, что получило распространение под термином Event Sourcing.
Существуют специализированные хранилища, реализующие его, но он реализуется не обязательно специализированными инструментами.

Event Sourcing¶

Если CQRS позволяет работать с хранилищами данных в Императивном стиле, и отделяет действия (побочный эффект) от запроса (чтения) данных, то Event Sourcing идет еще дальше, и накладывает ограничение на изменение и удаление данных, превращая CRUD в CR.
Такой шаблон позволяет работать с хранилищами данных в Функциональном стиле, и предоставляет такие же выгоды: нет изменяемого состояния — нет проблемы параллельного обновления.
И такие же недостатки — потребность в большом количестве памяти и процессорной мощности.
Именно поэтому, данный шаблон широко используется в распределенных системах, где остро проявляется потребность в его достоинствах, и, вместе с тем, не проявляются его недостатки (ведь распределенные системы не лимитированы ни в памяти, ни в процессорной мощности).

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

Наиболее ясно эта тема раскрывается в Chapter 6 “Functional Programming” of “Clean Architecture” by Robert C. Martin.

Что особенно важно, никакая информация не удаляется из такого хранилища и не изменяется.
Как следствие, от набора CRUD-операций в приложениях остаются только CR.
Также отсутствие операций изменения и/или удаления с хранилищем устраняет любые проблемы конкурирующих
обновлений.

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

Если это все еще кажется вам абсурдным, вспомните, как работают системы управления версиями исходного кода.

More importantly, nothing ever gets deleted or updated from such a data store.
As a consequence, our applications are not CRUD; they are just CR. Also, because neither updates nor deletions occur in the data store, there cannot be any concurrent update issues.

If we have enough storage and enough processor power, we can make our applications entirely immutable—and, therefore, entirely functional.

If this still sounds absurd, it might help if you remembered that this is precisely the way your source code control system works.

— “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin

Event Sourcing is naturally functional.
It’s an append only log of facts that have happened in the past.
You can say that any projection any state is a left fold over your previous history.

— Greg Young, “A Decade of DDD, CQRS, Event Sourcing” at 16:44

I have always said that Event Sourcing is “Functional Data Storage”.
In this talk we will try migrating to a idiomatic functional way of looking at Event Sourcing.
Come and watch all the code disappear!
By the time you leave you will never want an “Event Sourcing Framework (TM)” ever again!

— Greg Young, “Functional Data”, NDC Conferences

Что почитать¶

  • “Clean Code: A Handbook of Agile Software Craftsmanship” by Robert C. Martin [1], chapters:
    • Dependency Injection … 157
    • Cross-Cutting Concerns … 160
    • Java Proxies … 161
    • Pure Java AOP Frameworks … 163
  • “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” [2] by Robert C. Martin
    • Chapter 6 Functional Programming : Event Sourcing
    • Chapter 16 Independence
    • Chapter 18 Boundary Anatomy : Services
    • Chapter 20 Business Rules
    • Chapter 22 The Clean Architecture
    • Chapter 34 The Missing Chapter
  • “Patterns of Enterprise Application Architecture” by Martin Fowler [3], chapters:
    • Part 1. The Narratives : Chapter 2. Organizing Domain Logic : Service Layer
    • Part 1. The Narratives : Chapter 8. Putting It All Together
    • Part 2. The Patterns : Chapter 9. Domain Logic Patterns : Service Layer
  • “Domain-Driven Design: Tackling Complexity in the Heart of Software” by Eric Evans [4], chapters:
    • Part II: The Building Blocks of a Model-Driven Design : Chapter Four. Isolating the Domain : Layered Architecture
    • Part II: The Building Blocks of a Model-Driven Design : Chapter Five. A Model Expressed in Software : Services
  • “Implementing Domain-Driven Design” [5] by Vaughn Vernon
    • Chapter 4 Architecture : Command-Query Responsibility Segregation, or CQRS
    • Chapter 4 Architecture : Event-Driven Architecture : Long-Running Processes, aka Sagas
    • Chapter 4 Architecture : Event-Driven Architecture : Event Sourcing
    • Chapter 7 Services
    • Chapter 14 Application : Application Services
    • Appendix A Aggregates and Event Sourcing: A+ES : Inside an Application Service
  • “Microsoft Application Architecture Guide” 2nd Edition (Patterns & Practices) by Microsoft Corporation (J.D. Meier, David Hill, Alex Homer, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr., Akshay Bogawat), chapters:
    • Chapter 5: Layered Application Guidelines … 55
    • Chapter 5: Layered Application Guidelines : Services and Layers … 58
    • Chapter 9: Service Layer Guidelines … 115
    • Chapter 17: Crosscutting Concerns … 205
    • Chapter 21: Designing Web Applications : Service Layer … 288
    • Chapter 25: Designing Service Applications : Service Layer … 371
  • “Microsoft .NET: Architecting Applications for the Enterprise” 2nd Edition by Dino Esposito, Andrea Saltarello, chapters:
    • Chapter 5 Discovering the domain architecture : The layered architecture … 129
    • Chapter 10 Introducing CQRS … 255
    • Chapter 11 Implementing CQRS … 291
    • Chapter 12 Introducing event sourcing … 311
    • Chapter 13 Implementing event sourcing … 325
  • “Design Patterns Elements of Reusable Object-Oriented Software” by Erich Gamma [6], chapters:
    • Design Pattern Catalog : 4 Structural Patterns : Adapter … 139
    • Design Pattern Catalog : 4 Structural Patterns : Decorator … 175
  • “Building Microservices. Designing Fine-Grained Systems” by Sam Newman, chapters:
    • Chapter 3 How to Model Services : Premature Decomposition … 33
  • “Monolith to Microservices Evolutionary Patterns to Transform Your Monolith” by Sam Newman
    • Chapter 4. Decomposing the Database : Sagas
  • “Cloud Design Patterns. Prescriptive architecture guidance for cloud applications” by Alex Homer, John Sharp, Larry Brader, Masashi Narumoto, Trent Swanson, chapters:
    • Command and Query Responsibility Segregation (CQRS) pattern
    • Event Sourcing pattern
    • Compensating Transaction pattern
  • “.NET Microservices: Architecture for Containerized .NET Applications” edition v2.2.1 (mirror) by Cesar de la Torre, Bill Wagner, Mike Rousos, chapters:
    • Tackle Business Complexity in a Microservice with DDD and CQRS Patterns
    • Apply simplified CQRS and DDD patterns in a microservice
    • Apply CQRS and CQS approaches in a DDD microservice in eShopOnContainers
    • Implement reads/queries in a CQRS microservice
  • “CQRS Journey” by Dominic Betts, Julián Domínguez, Grigori Melnik, Fernando Simonazzi, Mani Subramanian, chapters:
    • Reference 1: CQRS in Context
    • Reference 2: Introducing the Command Query Responsibility Segregation Pattern
    • Reference 3: Introducing Event Sourcing
    • Reference 4: A CQRS and ES Deep Dive
    • Reference 6: A Saga on Sagas
  • “Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions” by Gregor Hohpe, Bobby Woolf, chapters:
      1. Message routing : Process manager … 278
  • “Microservices Patterns: With examples in Java” 1st Edition by Chris Richardson
    • Pattern: Command Query Responsibility Segregation (CQRS)
    • Pattern: Event sourcing
    • Pattern: Saga
  • “CQRS“

  • “Command Query Separation

  • “Event Sourcing“

  • “What do you mean by “Event-Driven”?“

  • “Patterns for Accounting“

  • “Accounting Patterns“

  • “CQRS, Task Based UIs, Event Sourcing agh!” by Greg Young

  • “Clarified CQRS” by Udi Dahan

  • “CQRS Documents” by Greg Young

  • “Sagas” by Hector Garcia-Molina and Kenneth Salem

  • “Domain services vs Application services” by Vladimir Khorikov

  • “Sagas” by Clemens Vasters (“Sample Code”)

This article in English “Design of Service Layer and Application Logic”.

Footnotes

[1] (1, 2, 3, 4, 5) “Clean Code: A Handbook of Agile Software Craftsmanship” by Robert C. Martin
[2] (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” by Robert C. Martin
[3] (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) “Patterns of Enterprise Application Architecture” by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford
[4] (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) “Domain-Driven Design: Tackling Complexity in the Heart of Software” by Eric Evans
[5] “Implementing Domain-Driven Design” by Vaughn Vernon
[6] (1, 2) “Design Patterns Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, 1994
[7] (1, 2) “Refactoring: Improving the Design of Existing Code” by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts
[8] (1, 2) “Building Microservices. Designing Fine-Grained Systems” by Sam Newman
[9] “.NET Microservices: Architecture for Containerized .NET Applications” edition v2.2.1 (mirror) by Cesar de la Torre, Bill Wagner, Mike Rousos

Updated on Oct 12, 2019

From Wikipedia, the free encyclopedia

In computer software, business logic or domain logic is the part of the program that encodes the real-world business rules that determine how data can be created, stored, and changed. It is contrasted with the remainder of the software that might be concerned with lower-level details of managing a database or displaying the user interface, system infrastructure, or generally connecting various parts of the program.

Details and example[edit]

Business logic:

  • Prescribes how business objects interact with one another
  • Enforces the routes and the methods by which business objects are accessed and updated

Business rules:

  • Model real-life business objects (such as accounts, loans, itineraries, and inventories)

Business logic comprises:[1]

  • Workflows that are the ordered tasks of passing documents or data from one participant (a person or a software system) to another.

Business logic should be distinguished from business rules.[2] Business logic is the portion of an enterprise system which determines how data is transformed or calculated, and how it is routed to people or software (workflow). Business rules are formal expressions of business policy. Anything that is a process or procedure is business logic, and anything that is neither a process nor a procedure is a business rule. Welcoming a new visitor is a process (workflow) consisting of steps to be taken, whereas saying every new visitor must be welcomed is a business rule. Further, business logic is procedural whereas business rules are declarative.[3]

For example, an e-commerce website might allow visitors to add items to a shopping cart, specify a shipping address, and supply payment information. The business logic of the website might include a workflow such as:

  • The sequence of events that happens during checkout, for example a multi-page form which first asks for the shipping address, then for the billing address, next page will contain the payment method, and last page will show congratulations.

There will also be business rules of the website:

  • Adding an item more than once from the item description page increments the quantity for that item.
  • Specific formats that the visitor’s address, email address, and credit card information must follow.
  • A specific communication protocol for talking to the credit card network

The web site software also contains other code which is not considered part of business logic nor business rules:

  • Peripheral content not related to the core business data, such as the HTML that defines the colors, appearance, background image, and navigational structure of the site
  • Generic error-handling code (e.g., which displays the HTTP Error Code 500 page)
  • Initialization code that runs when the web server starts up the site, which sets up the system
  • Monitoring infrastructure to make sure all the parts of the site are working properly (e.g., the billing system is available)
  • Generic code for making network connections, transmitting objects to the database, parsing user input via HTTP POST events, etc.

Business logic and tiers/layers[edit]

Business logic in theory occupies the middle tier of a 3-tier architecture.

Business logic could be anywhere in a program. For example, given a certain format for an address, a database table could be created which has columns that correspond exactly to the fields specified in the business logic, and type checks added to make sure that no invalid data is added.

Business logic often changes. For example, the set of allowable address formats might change when an online retailer starts shipping products to a new country. Thus it is often seen as desirable to make the code that implements the business logic relatively isolated, or loosely coupled. This makes it more likely that changes to business logic will require a small set of code changes, in only one part of the code. Distant but strongly coupled code also creates more of a risk that the programmer will only make some of the necessary changes and miss part of the system, leading to incorrect operation.[4]

A multitier architecture formalizes this decoupling by creating a business logic layer which is separate from other tiers or layers, such as the data access layer or service layer. Each layer «knows» only a minimal amount about the code in the other layers—just enough to accomplish necessary tasks. For example, in a model–view–controller paradigm, the controller and view layers might be made as small as possible, with all the business logic concentrated in the model. In the e-commerce example, the controller determines the sequence of web pages in the checkout sequence, and is also responsible for validating that email, address, and payment information satisfy the business rules (rather than leaving any of that up to the database itself or lower-level database access code).

Alternative paradigms are possible. For example, with relatively simple business entities, a generic view and controller could access database objects which themselves contain all the relevant business logic about what formats they accept and what changes are possible (known as the database model).

Some tiered schemes use either a distinct application layer or a service layer, or consider the business logic layer to be the same as one of those.

Tools and techniques[edit]

Business logic can be extracted from procedural code using a business rule management system (BRMS).[5]

The business rules approach of software development uses BRMSs and enforces a very strong separation of business logic from other code. User interface management systems are another technology used to enforce a strong separation between business logic and other code. The magic pushbutton is considered an «anti-pattern»: a technique that in this case creates undesirable constraints which make it difficult to code business logic in an easy-to-maintain way.

A domain model is an abstract representation of the data storage types required by business rules.

See also[edit]

  • Drakon-chart
  • Relocating logic
  • Business process modeling
  • Model–view–controller

References[edit]

  1. ^ Steven Minsky (2005-03-27). «The Challenge of BPM Adoption». eBizQ.
  2. ^ «Definition of business logic». 2013-12-24.
  3. ^ William Ulrich. «OMG Business Rules Symposium» (PDF). Archived from the original (PDF) on 2013-12-24.
  4. ^ Khawar Zaman Ahmed & Cary E. Umrysh (2001-10-17). «Introduction to Enterprise Software». Developing Enterprise Java Applications with J2EE and UML. Addison-Wesley. ISBN 0-201-73829-5.
  5. ^ Owen, James (September 19, 2003). «Bring business logic to light». Enterprise Java. InfoWorld. Retrieved 2020-07-21.

Further reading[edit]

  • Brett McLaughlin (March 2002). «Business Logic, Part 1». Building Java Enterprise Applications, Vol I: Architecture. O’Reilly and Associates. ISBN 0-596-00123-1. — McLaughlin discusses the façade pattern for implementing the business layer of an application.
  • Kathy Bohrer (November 1997). «Middleware isolates business logic». Object Magazine. New York, USA: SIGS Publications, Inc. 7 (9): 41–46. ISSN 1055-3614.
  • Harumi Kuno; Mike Lemon; Alan Karp & Dorothea Beringer (2001). «Conversations + Interfaces = Business Logic». In F. Casati; D. Georgakopoulos & M.-C. Shan (eds.). Technologies for E-Services: Second International Workshop, TES 2001, Rome, Italy, September 14–15, 2001, Proceedings. Lecture Notes in Computer Science. Vol. 2193. Springer Berlin / Heidelberg. ISSN 0302-9743.
  • Volker Turau (2002). «A framework for automatic generation of web-based data entry applications based on XML». Proceedings of the 2002 ACM symposium on Applied computing, Madrid, Spain: Web and e-business application. ACM Press. pp. 1121–1126. ISBN 1-58113-445-2. — Turau presents an application framework implemented using Java Servlets and JavaServer Pages that enables the separation between business logic and presentation logic, allowing development of each to proceed in parallel along relatively independent but cooperating tracks.
  • Pau, L.-F. & Vervest, P.H.M. (2003-12-08). «Network-based business process management: embedding business logic in communications networks». ERIM Report Series Research in Management. Erasmus University. hdl:1765/1070. — Pau and Vervest develop an approach for the embedding of business logic into the communications network that underlies a distributed application with a multiplicity of actors, in order to optimise the allocation of business resources from a network point of view.

External links[edit]

  • Business Layer Guidelines

Что такое бизнес-логика в программировании?

Что такое бизнес-логика в программировании?

При проектировании и реализации программных систем часто сталкиваешься с такими понятиями как:

  • Бизнес-логика;
  • Бизнес-правила;
  • Бизнес-ограничение;
  • Бизнес-операция;
  • и т.д.

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

Бизнес (англ. business — «дело», «предприятие») — деятельность, направленная на получение прибыли; любой вид деятельности, приносящий доход или иные личные выгоды (wiki). Данное определение не применимо в рамках реализации программного продукта, и не связано с какой-либо коммерческой деятельностью. Термин Бизнес можно заменить на понятие Предметная Область(ПО), от которого и надо отталкиваться.

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

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

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

  • Название книги
  • Ф.И.О. автора
  • Количество экземпляров данной книги
  • Ф.И.О. читателя
  • Дата рождения читателя
  • Экземпляры книг, которые имеются у него на руках
  • и т.д.

Где и как мы будем манипулировать этими данными в программе? Мартин Фаулер описывает три шаблона по организации бизнес-логики в проекте:

  • Сценарий транзакций;
  • Модуль таблицы;
  • Модель предметной области.

Нас интересует последний пункт, поэтому данные будут храниться в таких классах-сущностях как  Читатель, Книга, Абонемент и т.д. Именно в них и будет содержаться большая чать бизнес-логики. Бизнес-логика реализует бизнес-правила. А что такое бизнес-правило?

Бизнес-правило – это положение, определяющее или ограничивающее какие-либо стороны бизнеса (предметной области). Его назначение – защитить структуру бизнеса, контролировать или влиять на его операции.

Бизнес-правила разделяют примерно на шесть основных категорий:

1. Бизнес-термины – фундаментальная форма бизнес-правила. Это фразы, слова, аббревиатуры из предметной области. Обычно такие термины хранятся в документе под названием «бизнес глоссарий» или «словарь терминов». Примеры бизнес-терминов: читатель; книга; ISBN (англ. International Standard Book Number, сокращённо — англ. ISBN) — уникальный номер книжного изданиячитательский абонемент – документ, где учитываются книги выданные читателю; и т.д.

2. Факты (facts) — это верные утверждения о бизнесе. Зачастую они описывают связи и отношения между важными бизнес-терминами. Факты также называют инвариантами — неизменными истинами о сущности данных и их атрибутах. Бизнес-правила во многих случаях могут ссылаться на определенные факты, однако последние обычно не преобразуются напрямую в функциональные требования к программному обеспечению. Сведения о сущности данных, важных для системы, применяют в моделях данных, создаваемых аналитиком или архитектором базы данных.


Примеры фактов:

  • каждая книга должна иметь международный стандартный книжный номер;
  • клиент оплачивает доставку каждого заказа;
  • заказ должен содержать не менее одной позиции;
  • блиц-цена лота аукциона устанавливается продавцом;
  • каждый авиарейс имеет аэропорт вылета и аэропорт прилета;
  • автосалон реализует автомобили нескольких производителей (является мультибрэндовым дилером).

3. Ограничения (constraints) — определяют, какие операции может выполнять система и ее пользователи. Вот некоторые слова и фразы, которые применяются при описании ограничивающего бизнес-правила: должен / не должен, может / не может, только.

Примеры ограничений:

  • постоянный посетитель библиотеки может отложить для себя до 10 книг;
  •  сотрудник может запросить вещество из списка химикатов первого уровня опасности, только если за последние 12 месяцев он прошел обучающий курс работы с опасными соединениями;
  • все программы должны соответствовать правительственным постановлениям, касающимся использования их людьми с ослабленным зрением;
  •  экипажи коммерческих авиарейсов должны каждые 24 часа отдыхать не менее 8 часов;
  •  возраст участника аукциона должен превышать 18 лет;
  • автосалон может обменять старый автомобиль клиента на новый с минимальными для клиента финансовыми потерями.

    Как правило, в целевой организации существуют политики безопасности, определяющие порядок доступа к информационным системам. Обычно они констатируют, какие пароли следует применять, как часто их необходимо менять, можно ли применять старые пароли и т.д. Все эти ограничения, касающиеся доступа к приложению, можно считать бизнес-правилами. Ввод каждого такого правила в конкретный код упрощает обновление систем, необходимое для соответствия их новым правилам. Например, изменение необходимой частоты обновления паролей с 90 до 30 дней.

    4. Активатором операции (action enabler) называется бизнес-правило, приводящее к выполнению каких-либо действий при определенных условиях. Человек может выполнять эти действия вручную. Иногда правило может управлять некоторыми функциями программы, благодаря которым приложение при выполнении определенных условий реализует нужную модель поведения. Выражение вида «Если <некоторое условие верно или наступило определенное событие>, то <что-то произойдет>»— это ключ, который описывает активатор операции.


    Примеры активаторов:

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

    5. Выводы (inference), иногда называемые предположительным знанием — это правила, устанавливающие новые реалии на основе достоверности определенных условий. Вывод создает новый факт на основе других фактов или вычислений. Выводы зачастую записывают в формате «если — то», применяемом также при записи бизнес-правил, активирующих операции. Тем не менее, раздел «то» вывода заключает в себе факт или предположение, а не действие.

    Примеры выводов:

    •  если поставщик не может поставить заказанный товар в течение пяти дней с момента получения заказа, заказ считается невыполненным;
    • считается, что срок хранения контейнеров с химикатами, разлагающимися на взрывоопасные составляющие, истекает через один год c даты изготовления;
    • если выставленный участнику аукциона счет не был оплачен в течение трех дней с момента окончания аукциона, счет считается просроченным;
    • если привезенный автосалоном под заказ автомобиль не был выкуплен клиентом в течение 10 дней, автомобиль считается находящимся в свободном наличии;
    • если в расписании зимнего сезона отсутствуют сведения о рейсе, выполняемом в летний период, рейс считается отмененным на весь период действия нового расписания.

    6. Вычисления (computations) представляют собой еще один тип бизнес-правил, реализуемых с использованием математических формул или алгоритмов. Многие вычисления выполняются по внешним для предприятия правилам, например по формулам удержания подоходного налога. В отличие от активаторов, реализация которых предполагает создание специфических функциональных требований к системе, правила вычислений в той форме, в которой они выражены, можно рассматривать в качестве требований к программному обеспечению. Ниже в текстовой форме дано несколько примеров бизнес-правил для вычислений; как вариант, их можно представить в символьной форме, например в виде математического выражения.

    • цена единицы товара снижается на 10% при заказе от 6 до 10 единиц, на 20% — при заказе от 11 до 20 единиц и на 30% — при заказе свыше 20 единиц;
    • стоимость автомобиля «Opel» в салоне рассчитывается путем сложения стоимости базовой модели, стоимости выбранных покупателем пакетов, стоимости опций, за минусом скидки при повторной покупке в салоне, и скидки корпоративного клиента, но при условии, что продаваемый автомобиль не реализуется по акции «КАСКО в подарок».

    Отдельное вычисление может включать множество элементов. Во втором примере для расчета общей стоимости автомобиля использует алгоритм подсчета суммы, скидки и дополнительные условия. Это правило запутанно и сложно для понимания. Чтобы избавиться от данного недостатка, рекомендуется писать бизнес-правила на элементарном уровне, а не объединять множество деталей в одно правило. Сложное правило может ссылаться на используемые в нем отдельные правила. Это сделает их краткими и простыми. Кроме того, появляется возможность их повторного использования и создания различных комбинаций. Чтобы писать вычисления и активирующие операции бизнес-правила на элементарном уровне, не используйте в левой части конструкции «если — то» логику «или», а в правой части этой же конструкции — логику «и». К элементарным бизнес-правилам, влияющим на вычисление общей стоимости автомобиля из примера выше, относятся следующие:

    • если выбранная клиентом комплектация автомобиля содержит пакеты опций, стоимость пакетов добавляется к стоимости базовой комплектации;
    •  если выбранная клиентом комплектация автомобиля содержит опции, стоимость опций добавляется к стоимости базовой комплектации;
    • если клиент совершает повторную покупку, стоимость автомобиля уменьшается пропорционально скидке постоянного клиента;
    • если клиент является корпоративным, стоимость автомобиля уменьшается пропорционально скидке корпоративного клиента;
    • скидки корпоративного и постоянного клиента суммируются;
    • если автомобиль реализуется по акции «КАСКО в подарок», скидки корпоративного и постоянного клиента не действуют.

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

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

    //дата рождения читателя

    DateTime dateOfBirth = new DateTime(1995, 3, 16);

    //текущая дата

    DateTime nowDate = new DateTime(2005, 3, 16);

    int age = nowDate.Year — dateOfBirth.Year;

    if (nowDate.Month < dateOfBirth.Month)

    {

        age = age — 1;

    }

    else if (nowDate.Month == dateOfBirth.Month)

    {

        if (nowDate.Day < dateOfBirth.Day)

        {

            age = age — 1;

        }

    }

    //реализация бизнеслогики

    if (age < 7 || age > 21)

    {

        throw new Exception(«Возраст должен быть от 7 до 21 года»);

    }

    else { //здесь регистрируем читателя в системе…}

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

    Ссылки:

    Что такое бизнес-логика

    Бизнес-логика – это набор правил (условий), которым подчиняются объекты, сущности, классы и данные внутри программы. Просто посмотрите на обложку этой статьи, на ней изображен пример простой бизнес-логики.

    Не стоит бояться бизнес-логики

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

    В любом приложении есть какая-то логика, присущая только ему. Данный код невозможно перенести в другую программу (другой бизнес) как библиотеку или фреймворк. Бизнес-логика может быть как относительно простой – пару условий, так и очень сложной, где не обойтись без цепочки условий или даже машинного обучения.

    Интерфейс отдельно, бизнес-логика отдельно

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

    пример бизнес логики

    MVC – (с анг. Model, View, Controller) это схема разделения данных в приложении на три компонента: модель, представление, контроллер.

    MVC приложение состоит из 3 частей. Controller – обрабатывает все запросы с браузера, которые генерирует пользовать (например, запрашивает открытие какой-то страницы). Когда пользователь вызвал Controller, тот в свою очередь вызывает какой-то участок кода из Model. А это уже наш слой с бизнес-логикой, он связывается с базой данных и как-то обрабатывает данные. Когда Model выполнила код, то результат (объект с преобразованными данными) возвращается в Controller, и тот вызывает View, запихивая в него данные и отдавая пользователю (уже готовую веб-страницу).

    Как видите, это позволяет разделять приложение на разные слои и в последствии позволяет гораздо проще его обслуживать. Вообще, существует множество паттернов проектирования, и все они призваны разделять данные между собой (чтоб каши не было в одном файле). MVC тоже не идеальный пример архитектуры, и когда данных становится очень много, то люди придумывают новые схемы разделения (MVP, MVVM, Monkey Patching и еще куча разных схем).

    Итог

    Когда в следующий раз увидите определение “бизнес-логика”, читайте просто как “логика”.

    Понравилась статья? Поделить с друзьями:
  • Что такое бизнес функциональные требования
  • Что значит в реквизитах наименование банка
  • Что такое бик банка в реквизитах сбербанка
  • Что значит время работы в режиме разговора
  • Что такое бик в реквизитах россельхозбанка