Дорога, вымощенная благими намерениями
185
И конечно, кажется полезным, что на основе одной и той же бизнес-логики
могут создаваться несколько приложений – внутренняя логика приложения
не должна дублироваться для каждого нового окружения.
Пока все хорошо, так в чем проблема? К сожалению, есть много подвод-
ных камней, и методология не совсем обеспечивает обещанную выгоду – по
крайней
мере в том виде, в каком она применяется в реальных условиях.
Рассмотрим идею централизации бизнес-логики. Во-первых, преимущест-
ва объединения всей логики в одном месте, на бизнес-уровне,
несколько
уменьшаются, когда это «одно место» составляют несколько сотен тысяч
строк кода. На практике такой большой бизнес-уровень приводит к дублиро-
ванию кода или, что еще хуже, к попыткам дублирования кода. Когда уровень
бизнес-логики увеличивается в размерах, трудно найти функцию, которая
делает именно то, что нужно. В результате авторы часто наблюдали одну и ту
же бизнес-логику, реализованную разными способами, разными методами
и с разными результатами.
Во-вторых, бизнес-логика может быть доступна для дополнительных
пользовательских интерфейсов, но она недоступна для других бизнес-при-
ложений, которые напрямую взаимодействуют с базой данных, – в первую
очередь для создания отчетов. Таким образом, авторы отчетов в конечном
итоге дублируют логику приложения или в хранилище данных, или, что еще
хуже, в отдельных отчетах, без гарантий эквивалентности исходной логике
приложения.
Кроме того, при таком подходе взаимодействие с
уровнем персистент-
ности ограничивается отдельными объектами или даже отдельными ска-
лярными значениями, что сводит на нет возможности движка базы данных.
Интерфейс конечного пользователя может знать все необходимые ему эле-
менты данных, но, поскольку он не взаимодействует напрямую с уровнем
персистентности, запросы данных опосредуются уровнем бизнес-логики.
Типичная реализация уровня персистентности содержит классы досту-
па к данным, которые однозначно соответствуют классам бизнес-объектов.
Базовые DML-функции (
INSERT
,
UPDATE
,
DELETE
) написать легко, но что проис-
ходит, когда операции должны выполняться над множеством объектов этого
класса? Есть два пути: разработчик может создать еще один набор методов,
которые будут повторять те же функции для объектов из множества. Однако
это нарушит принцип повторного использования кода. Есть альтернативный
и более распространенный вариант: разработчик просто перебирает элемен-
ты коллекции, вызывая функции, определенные для обработки отдельных
объектов.
Представьте себе интерфейс приложения, в котором перечислены все пас-
сажиры, вылетевшие из аэропорта О’Хара. Разработчик базы данных сооб-
разит, что для составления
списка всех пассажиров, вылетевших из аэро-
порта, необходимо соединить таблицу
flight
с таблицей
boarding_pass
. Вся
информация будет получена за одно обращение. Для разработчика прило-
жения задача может оказаться сложнее. У него может быть метод
GetFlight-
ByDepartureAirport
, который принимает код аэропорта в качестве параметра
и возвращает набор рейсов. Затем он может перебрать рейсы, возвращая все
посадочные талоны на рейс. Фактически он реализует алгоритм соединения
186
Разработка приложений и производительность
вложенными циклами внутри приложения.
Чтобы избежать этого, можно использовать несколько разных решений.
Можно добавить атрибут аэропорта вылета к объекту посадочного талона. Но
тогда возможны проблемы с целостностью данных: что, если время вылета
рейса обновится в записи рейса, но не во всех посадочных талонах? Можно
определить метод получения посадочных талонов для данного
аэропорта
вылета, но это нарушит правило, согласно которому объекты не знают друг
о друге. При чистом многоуровневом подходе объект посадочного талона
ничего не знает об объекте рейса, а объект рейса ничего не знает про объект
посадочного талона. Метод, извлекающий данные для обоих объектов, не
может принадлежать ни к одному из них.
Do'stlaringiz bilan baham: