12. Слоёная архитектура для ИС
Приведенные в этой книге схемы анализа будут очень полезны для разработчиков корпоративных информационных систем. Однако разработка информационной системы (ИС) предполагает не только понимание области. Необходимо приспособиться к миру множества пользователей, баз данных и унаследованных систем. В этой главе рассматриваются архитектурные паттерны для информационных систем. Архитектурный паттерн описывает высокоуровневое разделение системы на основные подсистемы и зависимости между подсистемами. Архитектурный паттерн информационной системы делит систему на слои (или уровни). Архитектурные паттерны полезны сами по себе, но они также показывают, как паттерны анализа вписываются в более широкий контекст. В главе 13 описана техника использования паттернов, приведенных в этой главе.
На заре становления объектной технологии разработке ИС уделялось не так много внимания. Основная проблема заключается в том, что большие объемы зачастую сложной информации должны совместно использоваться многими людьми. Несмотря на то, что эта информация является общей, у разных пользователей разные потребности. Предоставление общей информации, которая может быть адаптирована к местным условиям, является основной задачей больших информационных систем. Кроме того, для удовлетворения постоянно меняющихся потребностей в информации требуется большая гибкость. В большинстве информационных систем доминируют задачи поддержки, которые в первую очередь связаны с удовлетворением меняющихся информационных потребностей. Основное преимущество объектной технологии в этих условиях заключается не в скорости создания новых систем, а в снижении бремени обслуживания [3],
Наиболее фундаментальным вопросом при разработке современной информационной системы является понимание лежащей в ее основе архитектуры программного обеспечения. Широкое представление об архитектуре ПО, подходящего для информационных систем, должно предшествовать любому обсуждению того, какие методы следует использовать или какие процессы следует рассматривать.
Большинство разработок в области ИС негласно предполагают двузвенную архитектуру (12.1), которая возникла на базе интерактивных систем мэйнфреймов и сегодня часто встречается в разработках клиент/сервер. Несмотря на широкое распространение, двузвенная архитектура имеет множество недостатков, связанных с жесткой привязкой пользовательского интерфейса к физическому расположению данных. Трехзвенная архитектура (12.2), также называемая архитектурой трех схем, решает эту проблему, помещая промежуточное звено между пользовательским интерфейсом и физическими данными. Это доменное звено точнее моделирует концептуальную структуру проблемной области. Объектная технология особенно хорошо подходит для использования трехзвенной архитектуры, а звено домена может быть размещено как на клиентских, так и на серверных машинах.
Далее мы обратимся к приложениям, которые манипулируют объектами доменного звена и отображают информацию на пользовательском интерфейсе. Эти две обязанности можно использовать для разделения системы на презентацию и логику приложения (12.3). Логика домена может быть организована как набор фасадов на доменном уровне, по одному фасаду для каждой презентации. Такое разделение имеет множество преимуществ, а фасады приложений можно использовать для упрощения взаимодействия клиента и сервера.
Взаимодействие с базой данных (12.4) может осуществляться двумя способами. Слой домена может отвечать за доступ к базе данных, которая сама управляет своей сохранностью. Это хорошо работает для объектно-ориентированных или простых реляционных систем. При наличии сложных форматов данных или нескольких источников данных может потребоваться дополнительный слой интерфейса данных.
В основу этой главы положен различный опыт, в частности проект Cosmos Национальной службы здравоохранения Великобритании и система торговли деривативами для одного из лондонских банков.
12.1 Двухуровневая архитектура
Большинство разработок интерактивных ИС организовано, по крайней мере приблизительно, по двузвенному принципу, как показано на рис. 12.1. Двузвенная архитектура делит систему на общую базу данных и несколько приложений. Общая база данных располагается на сервере, который имеет достаточное дисковое пространство и обработку данных, необходимую для удовлетворения бизнес требований. База данных содержит данные, необходимые значительной части предприятия, и структурирована для удовлетворения всех потребностей этой части. (Для крупных компаний создание единой общекорпоративной базы данных нецелесообразно, поэтому база данных будет занимать лишь некоторую часть). База данных разрабатывается и поддерживается группой специалистов. Хотя здесь используется термин «база данных», следует помнить, что данные часто хранятся в плоских файлах (большинство коммерческих данных по-прежнему хранятся в плоских файлах, таких как VSAM). Таким образом, термин «база данных» может относиться к любому источнику данных.

Приложения напрямую обращаются к базам данных.
Рисунок 12.1 Двузвенная архитектура.
Приложения разрабатываются для конкретного локального использования. Традиционно использовался CICS/COBOL, но в последнее время стали применяться 4GL и популярные средства разработки приложений PowerBuilder и Visual Basic. Эти инструменты предоставляют богатые возможности для разработки систем с графическим интерфейсом, а хороший интерфейс Windows обычно востребован пользователями ПК, которые привыкли к таким возможностям в своих электронных таблицах и текстовых процессорах. Приложения обычно создаются по отдельности. Все необходимые новые возможности работы с данными запрашиваются у группы поддержки баз данных.
Двузвенная архитектура имеет ряд преимуществ. В большинстве организаций есть данные, которые нуждаются в централизованном контроле и согласованном обслуживании. Приложения, интерпретирующие эти данные, нуждаются в гораздо меньшем централизованном контроле. Большая часть работы по ИС заключается в представлении существующих данных в новой полезной форме.
У двузвенной архитектуры также много недостатков, большинство из которых присущи современным технологиям. Идея о том, что все данные являются общими, а вся обработка — локальной, в целом верна, но является грубым упрощением. Многие аспекты обработки данных на предприятии являются общими. Базы данных, будь то SQL или более старые, не могут обеспечить полный язык для вычислений. Кроме того, данные не инкапсулируются, что оставляет контроль целостности в руках прикладного программиста. Это затрудняет изменение структуры базы данных, на которой уже работает множество приложений. Эти проблемы решаются с помощью хранимых процедур, которые могут обеспечить поддержку обработки и инкапсуляции данных.
Базы данных часто не могут дать истинное представление о бизнесе. Это связано с отсутствием конструктов моделирования, которые распространены в методах концептуального моделирования, но все еще далеки от поддержки в повседневных базах данных. Плоские файлы и иерархические базы данных имеют хорошо известные ограничения на структуру данных. Текущий стандарт для новых разработок, реляционные базы данных, также страдают от высокой стоимости объединения данных. Модели данных, соответствующие семантике бизнеса, обычно сильно нормализованы и нуждаются в реорганизации, чтобы производительность была приемлемой.
Данные для приложения также вряд ли будут находиться в одной базе данных. Хранилища, даже если они разумно организованы в момент создания, обычно не столь согласованны после нескольких лет изменений в бизнес-процессах и корпоративных реорганизаций. Двузвенная архитектура требует, чтобы приложения знали, в каких базах данных хранятся те или иные данные, а также структуру данных в каждой базе, которая может быть весьма далека от семантики этих данных.
12.2 Трехуровневая архитектура
На самом деле более удобная архитектура существует уже очень давно. Трехзвенная архитектура была предложена еще в 1970-х годах [4]. Она предусматривает три логических звена, как показано на рис. 12.2: внешняя схема, концептуальная схема и схема хранения (внутренняя). Схема хранения — это дизайн базы данных, а внешняя схема — это приложения; новый элемент — концептуальная схема, которую я называю звеном домена. Он представляет собой истинную семантику предприятия и должна игнорировать ограничения структур хранения данных и их расположения.

Рисунок 12.2 Трехзвенная архитектура.
Основное преимущество трехзвенного подхода заключается в том, что он позволяет описывать приложения исключительно на основе семантики домена. Не нужно заботиться о физическом расположении и структуре данных, вместо этого можно смотреть на логическую картину, которая устраняет эти зависимости. Это также позволяет администраторам данных изменять физическую структуру и расположение данных, не ломая существующие приложения.
Трехзвенная архитектура широко одобряется, но редко реализуется. Основная причина этого — сложность ее использования в существующих технологиях. Есть инструменты для хранения данных и разработки приложений, но не для реализации доменного звена. Наиболее полезным шагом разработки является логическая модель данных, которая обычно рассматривается как необходимый первый шаг в проектировании базы данных. Это позволяет разработчикам учитывать семантику предприятия до того, как они приступят к физическому проектированию. Таким образом, модификации для физического проектирования могут быть сделаны обоснованно.
Большинство практиков рассматривают звено домена как логическую модель данных. Они могут заниматься моделированием процессов, но обычно разработчики приложений рассматривают их отдельно. Однако эту точку зрения разделяют не все специалисты по моделированию данных. Сильная школа разработчиков семантических данных рассматривает моделирование данных как очень похожее на объектно-ориентированное моделирование, поскольку оно охватывает подтипизацию и производные данные, связывает процессы с объектами, рассматривает процессы как данные и встраивает процессы в семантическую модель.
С развитием объектно-ориентированных методов звено домена может выйти на первый план. Объекты представляют собой очень хороший способ реализации доменных слоев. Они поддерживают инкапсуляцию, сложные структурные отношения, правила, процессы и все то, что рассматривается продвинутыми разработчиками семантических моделей. Многоразовые библиотеки классов (или, что еще лучше, фреймворки) также лежат в основе доменного слоя. Ключевыми объектами многократного использования на предприятии являются те, которые описывают домен — фреймворк, реализующий доменное звено (отсюда и термин «фреймворк домена»). Таким образом, объектное моделирование и разработка доменного слоя совпадают очень эффективно.
Вопросы реализации несколько сложнее, но основной принцип по-прежнему работает очень хорошо: если слой домена выражен в виде объектно-ориентированной модели и реализован в виде доменного фреймворка, то приложения могут быть написаны на основе этого доменного фреймворка. Это обеспечивает разделение между приложениями и базами данных, которое так необходимо.
12.2.1 Расположение звена домена
В мире клиент-серверного подхода важным вопросом является — где расположить звено домена. При двузвенном подходе прикладное программное обеспечение размещается на клиенте (настольных машинах), а данные — на различных серверах данных. В случае со звеном домена у нас есть два основных варианта: мы можем разместить звено домена на клиентах, или мы можем ввести новый слой обработчиков, который является сервером домена и состоит из одной или многих машин, объединенных в сеть.
Клиентские доменные фреймворки позволяют нам сосредоточить разработку на клиентских машинах, упрощая поддержку систем. Внедрение нового уровня машин вполне может стать новой головной болью для многих организаций по поддержке еще одного набора машин и систем для обслуживания. Звено домена предоставляется в виде набора библиотек разработчикам приложений для клиентских систем, которые затем могут писать код приложений по мере необходимости.
Одна из проблем со звеном домена заключается в том, что нам может потребоваться выполнить много операций по выбору и обработке данных на клиенте. Это вынуждает нас использовать мощные клиентские машины. По мере того как настольные машины становятся все мощнее, это становится все меньшей проблемой, но мы не можем рассчитывать на такую мощность. Технологии толкают нас на все более компактные устройства; некоторые пользователи хотят использовать наладонники и КПК, которые могут накладывать ограничения на обработку данных. Часто проще модернизировать серверы, когда требуется большая вычислительная мощность.
Имеющееся программное обеспечение вполне соответствует написанию клиентского кода. Smalltalk, как правило, самый полезный язык для приложений ИС. Он требует пользовательский интерфейс, связанный со звеном домена, хотя начинают появляться «безголовые» Smalltalk вариации, которые работают на сервере без потребности в пользовательском интерфейсе.
Звено домена легче контролировать и обновлять когда оно находится на серверной стороне. Если звено домена находится на клиентской стороне, то любые изменения необходимо рассылать каждому клиенту. Обновления программного обеспечения на сервере могут быть обработаны по более простой схеме. Этот контроль также распространяется на поддержку постоянных данных, особенно тех, которые связаны с настройкой доступа к данным.
Нам необходимо рассмотреть вопросы параллелизма. Интересно, что прикладное ПО, вероятно, используют больше параллелизма, чем любой другой тип программного обеспечения, но при этом меньше всего беспокоятся о нем. Это связано с мощной моделью транзакций, которая обычно очень хорошо обрабатывается базой данных, освобождая прикладного программиста от большинства головных болей, связанных с параллелизмом. Когда вводится звено домена, мы должны задаться вопросом, где должна находиться граница транзакций. Мы можем разместить ее либо на серверах данных, либо на самом доменном звене. Логичным местом является звено домена, но это потребует от нас встроить функции управления транзакциями, а это непростое дело. Такое размещение также мотивирует использовать близость серверной стороны, поскольку подтверждение транзакции (commit) на многих клиентах прагматично выходит за рамки текущего состояния технологий. Я никогда не призываю клиентов создавать свои собственные системы управления транзакциями; эта задача выходит за рамки большинства разработок в области ИС.
Объектно-ориентированные базы данных предлагают решение этой проблемы. Основная проблема, с которой сталкиваются сообщества разработки ИС при использовании OO баз данных — это недоверие корпораций к хранению данных в новой технологии. ОО базы данных в ответ предоставили шлюзы к традиционным базам данных. При таком подходе OO база данных может выступать в качестве механизма управления транзакциями, не храня при этом никаких данных. Со временем некоторые данные, особенно сложные и связанные, которыми так хорошо управляет OO база данных, могут быть в неё же и перенесены. Тем не менее ключевые корпоративные данные могут оставаться в более традиционных местах до тех пор, пока разработчики этого хотят. Важным предупреждением здесь является то, что информации о многопользовательской производительности OO баз данных очень мало. Многие из заявленных значительных улучшений производительности основаны на небольших однопользовательских примерах. Любой, кто использует OO базу данных, даже если она предназначена только для управления транзакциями, должен провести сравнительный анализ, прежде чем брать на себя обязательства по её использованию.
Если используется только одна OO база данных, то слой хранения данных эффективно сворачивается в слой домена. Это допустимо при следующих условиях. Во-первых, разработана эффективная архитектура. Во-вторых, расширения системы для поддержки других баз данных могут быть сделаны таким образом, что они будут предоставлены слоем доступа к данным, без доступа к доменному слою.
12.3 Логика слоев представления и приложения
Трехзвенная архитектура дает ряд очень важных преимуществ. Много внимания было уделено тому, как может быть построено звено домена, и значительная часть ОО моделирования непосредственно применяется к этому ключевому звену. Однако мало что было сказано о слое приложения. Программы создаются путем сборки многократно используемых компонентов на уровне домена, и для этой задачи также существуют рекомендации, хотя они часто не описаны подробно.
Как правило, в современном мире программист разрабатывает ПО в среде графического интерфейса, используя/проектируя слой домена. Это требует знания среды GUI и слоя домена, а сложный уровень домена может сделать кривую обучения довольно крутой. Программирование во многих графических средах (таких как Visual C++) также может быть довольно сложным.
Рассмотрим относительно простой пример финансового учреждения, имеющего портфель производных контрактов между долларами США (USD) и японскими иенами (JPY). Такая организация заинтересована в управлении рисками, связанными с таким портфелем. На риск могут влиять несколько факторов, включая обменный спот-курс, волатильность обменного курса и процентные ставки по двум валютам. Чтобы учесть риски, аналитик хочет посмотреть на цену портфеля при различных комбинациях этих факторов. Один из способов сделать это — использовать таблицу, показанную на рис. 12.3. Аналитик выбирает две переменные для анализа, устанавливает для них различные значения и видит таблицу, показывающую стоимость портфеля при различных комбинациях значений.

Рисунок 12.3 Пример приложения для управления рисками по деривативам.
Каковы задачи обработки и как их разделить между прикладным и доменным звеньями? Одна из фундаментальных задач — определение стоимости контракта на дериватив, сложный процесс, обычно выполняемый с помощью анализа Блэка-Шоулза (Black-Scholes) [2]. Этот процесс будет широко использоваться любой системой в среде торговли деривативами, поэтому его следует отнести к звену домена. Другой распространенной задачей является оценка стоимости многих контрактов, объединенных в портфель, которая тоже обычно помещается в доменное звено. Следующая задача — построить таблицу значений из параметров (от, до, размер шага, количество шагов). Эта задача уникальна для данного экрана отчета о рисках, поэтому по логике должна быть частью прикладного звена, вместе с кодом, который создает и управляет графическим интерфейсом.
Задача построения таблицы довольно сложна и требует более детального рассмотрения. Она включает в себя установку различных параметров, поддержание их согласованности, а затем использование параметров для построения таблицы значений. Этот процесс может и должен быть отделен от отображения на экране графического интерфейса. Поэтому я рекомендую разделить звено приложения на два: звено представления и звено прикладной логики, как показано на рис. 12.4.

Рисунок 12.4 Разделение уровня приложения на представления и логику приложения
Разделить обязанности этих двух звеньев довольно просто. Звено представления отвечает только за пользовательский интерфейс. Он обрабатывает окна, меню, шрифты, цвета и всё позиционирование на экране или бумаге. Обычно он использует фреймворк пользовательского интерфейса, такой как MFC или MacApp. Он не выполняет никаких вычислений, запросов или обновлений на уровне домена. Ему вообще не нужно иметь никакого знания о звене домена. Звено прикладной логики не выполняет никакой обработки пользовательского интерфейса. Он отвечает за все обращения к звену домена и любую обработку, кроме обработки пользовательского интерфейса. Он выбирает информацию из базового доменного звена и упрощает ее до той формы, которая требуется для представления. Таким образом, сложные взаимосвязи доменного звеня скрываются от представления. Кроме того, уровень прикладной логики выполняет преобразование типов. Презентация обычно имеет дело только с небольшим набором общих типов (integer, real, string и date, а также классы коллекций, используемые в программном обеспечении). Звено прикладной логики предоставляет только эти типы и отвечает за преобразование базовых типов домена в эти типы и интерпретацию любых обновлений, запрашиваемых представлением.
Полезным способом организации яруса прикладной логики является разработка серии фасадов. Фасад — это тип, предоставляющий упрощенный интерфейс к сложной модели. Мы можем подготовить фасад для каждого визуального представления. Фасад имеет функцию для каждого элемента соответствующего пользовательского интерфейса. Таким образом, каждый экран интерфейса имеет простой программный интерфейс к доменной модели, который минимизирует любую обработку презентации, кроме пользовательского интерфейса. (В главе 13 рассматривается техника проектирования таких фасадов).
На рис. 12.5 показано, как такая организация работает для экрана отчета о рисках, о котором говорилось выше. Нам нужны два класса: представление отчета о рисках и фасад отчета о рисках. Презентация создает макет экрана и управляет взаимодействием пользователя с ним. Фасад предоставляет базовую структуру, которая имитирует презентацию. Он содержит операции для получения и установки параметра, верхнего, нижнего значения, количества шагов и размера шага для координат x и y таблицы. Фасад содержит правила, необходимые для обеспечения надлежащей согласованности этих значений (например, инвариант xUpper — xLower == xNumberOfSteps * xStepSize
). Он также предоставляет метод для возврата сетки ответов. В идеале он возвращает одну матрицу, используя общий класс матриц. (Если по каким-то причинам это недоступно или нежелательно, то фасад предоставляет операции для получения конкретных ячеек, но класс матрицы многократного использования, по сути, новый вид коллекции, обычно является лучшим решением).

Рисунок 12.5 Диаграмма взаимодействия, обобщающая взаимодействие между уровнями представления, фасада и домена.
Метод получитьМатрицу
на фасаде проверяет, достаточно ли информации было предоставлено презентацией (если нет, он может добавить значения по умолчанию), а затем просит доменное звено оценить портфель с различными комбинациями параметров. Доменный уровень заносит результаты в матрицу и возвращает ее презентации.
Установка параметров — это пример использования преобразования типов. В качестве параметров в этот список могут быть помещены различные объекты, включая спот USD/JPY, волатильность USD/JPY, процентную ставку USD и процентную ставку JPY. (Список зависит от валют контрактов в портфеле). Фасад предоставляет соответствующие строки для представления, переводя их из типов на уровне домена (см. раздел 13.5). Фасад обычно предоставляет список таких строк, которые презентация может поместить в свое всплывающее меню. Затем презентация может выбрать строку. Фасад соотносит выбранную строку с нижележащими объектами домена (с этим прекрасно справляется словарь). Таким образом, пользовательский интерфейс полностью изолирован от доменной модели.
В этой ситуации видимости между доменами определяются так, как показано на рис. 12.6. Видимость идет только от представления к логике приложения и доменному уровню. Такая линия видимости ценна тем, что она полностью изолирует уровень домена от приложений, которые на него полагаются. Однако может возникнуть проблема, если презентация должна автоматически обновляться при изменении модели домена. Один из вариантов — опрашивать презентацию через регулярные промежутки времени, но это может оказаться довольно запутанным. Лучшим вариантом является использование паттерна наблюдателя. Это позволяет автоматически обновлять фасад и презентацию, не нарушая правил видимости.

Рисунок 12.6 Видимость между презентацией, фасадом и доменом.
12.3.1 Преимущества разделения логики представления/приложения
В принципе, многослойность — хорошая идея, но у нее есть и недостатки: для создания слоя требуется дополнительная работа, а его использование может привести к снижению производительности. Важный вопрос — стоят ли преимущества затрат?
Одно из преимуществ связано с разными стилями программирования, используемыми в этих двух слоях. Программирование графического интерфейса может быть очень сложным, требующим знания фреймворков графического интерфейса и умения правильно их использовать. Если требуются новые элементы управления GUI, программирование становится еще более сложным. С другой стороны, разработка GUI может быть довольно простой, если у нас есть хороший конструктор форм, позволяющий рисовать элементы управления на экране и создавать обработчики событий, которые обычно передаются как вызовы фасада приложения. В любом случае организации, занимающиеся разработкой, могут использовать специалистов по графическому интерфейсу, которым не нужно много знать о модели домена. Точно так же программистам фасада не нужно ничего знать о том, как работает система GUI, их задача — обеспечить правильное взаимодействие с типами домена. Разделение на презентацию и прикладную логику разделяет необходимые навыки работы, позволяя разработчикам изучать меньше, чтобы внести свой вклад.
Разделение позволяет разрабатывать несколько презентаций на основе одного фасада; это особенно удобно, когда требуются индивидуальные экранные или бумажные макеты, содержащие одну и ту же информацию. Когда используются инструменты для создания экранов и отчетов, это позволяет быстро создавать новые стили презентаций.
Фасады обеспечивают хорошую платформу для тестирования. Когда фасад и презентация объединены, базовые вычисления можно протестировать только через графический интерфейс, что требует ручного тестирования (или программного обеспечения для тестирования графического интерфейса для регрессионного тестирования). Когда они разделены, для интерфейса фасада можно написать тестовый пакет. Таким образом, остается только код представления, который нужно тестировать с помощью более неудобных инструментов. Разделение тестирования подкрепляет мысль о том, что оба слоя можно создавать отдельно, хотя презентация должна быть определена до создания фасада.
12.3.2 Растягивание фасадов в окружении клиент/сервер
Фасад ценен как фокусная точка для взаимодействия клиента и сервера, если уровень домена базируется на сервере. Полезной техникой в таких случаях является «растягивание» фасада между клиентом и сервером, размещая класс фасада и на клиенте, и на сервере. Когда пользователь открывает презентацию, соответствующий фасад открывается на стороне клиента. Клиентский фасад передает запрос на серверный фасад. Серверный фасад проходит процесс создания, извлекая информацию из классов домена. Когда вся информация для фасада готова, серверный фасад отправляет всю информацию для фасада клиенту. Поскольку серверный и клиентский фасады могут находиться в разных объектных пространствах, между двумя классами фасадов может происходить ряд приватных коммуникаций. Пользователь может взаимодействовать с презентацией, которая будет обновлять клиентский фасад при каждом изменении. Эти изменения не передаются на фасад сервера до тех пор, пока пользователь не зафиксирует их. В этот момент измененный объект фасада передается обратно на сервер, а серверный фасад обновляет уровень домена, как показано на рис. 12.7.

Рисунок 12.7 Диаграмма взаимодействия рисунка 12.3 с использованием вытянутых фасадов.
Смысл растягивания фасада в том, что он обеспечивает единую точку обращения для взаимодействия клиента и сервера. Если клиентский фасад (или презентация) обращается к классам домена сервера напрямую, то для наполнения клиента потребуется множество вызовов по сети. Эти сетевые вызовы могут существенно повлиять на производительность. Фасады могут иметь методы для создания одного пакета передачи и интерпретации такого пакета в данные фасада. Затем мы можем передавать всю информацию в одном сетевом вызове.
Различные обязанности фасада могут быть разделены между классами клиента и сервера. Только серверный фасад должен отвечать за взаимодействие с доменной моделью. Оба класса должны иметь возможность отправлять и получать информацию друг от друга. В идеале только клиентский фасад должен выполнять операции по поддержке представления. Однако на практике я считаю целесообразным дать обоим классам одинаковый интерфейс, чтобы облегчить тестирование (то есть они должны быть одного типа). Обеим сторонам требуются операции загрузки и сохранения. Клиентский фасад реализует эти операции, взаимодействуя с серверным фасадом, а сервер реализует их, взаимодействуя с доменной моделью.
12.4 Взаимодействие с базой данных
Нам нужно тщательно продумать, как интегрировать базы данных и унаследованные (legacy) приложения в эту структуру. Самый простой случай — использование объектной базы данных. В этом случае простым подходом является простая интеграция базы данных в уровень домена. Объектная база данных предоставляет средства для персистентности, управления транзакциями и другие возможности, о которых не должен беспокоиться ни один корпоративный программист.
Однако лишь малая часть приложений в каталоге организаций настолько просты. Многие организации с недоверием относятся к объектным базам данных и неохотно размещают в них важные данные. Отчасти это объясняется их новизной, но также и сложностью. Реляционные таблицы относительно легко вскрыть, если что-то пойдет не так. Объектные базы данных, с огромным количеством дисковых указателей, гораздо сложнее.
Даже если бы объектные базы данных были уверенным выбором для новых разработок, все равно остается проблема существующих данных. Даже реляционные базы данных, несмотря на их нынешнее положение в качестве проверенной технологии для разработки баз данных, еще не достигли уровня, позволяющего управлять большинством корпоративных данных. Подавляющее большинство корпоративных данных находится в иерархических базах данных, плоских файлах и т.п. Объектные системы должны взаимодействовать с этими системами, по мере необходимости принимая информацию и учитывая тот факт, что для получения целостной картины необходимо обращаться ко многим системам. Существует два глобальных подхода: позволить доменной модели взаимодействовать с источниками данных или использовать слой интерфейса базы данных.
12.4.1 Связывание уровня домена с источниками данных
Рассмотрим простой случай автономной системы, которая должна использовать реляционную базу данных для хранения данных. Мы можем спроектировать реляционную базу данных специально для поддержки доменной модели. Сначала мы должны спроектировать уровень домена и на его основе разработать схему базы данных. Для всех систем, кроме самых простых, невозможно просто взять каждый тип объекта в доменной модели и превратить его в реляционную таблицу. Несмотря на свое название, реляционные базы данных имеют проблемы со связью данных, поскольку вычисление соединений занимает много времени. Таким образом, хороший реляционный дизайн должен значительно денормализоваться, чтобы получить хорошую производительность. Модель домена служит отправной точкой для проектирования базы данных, но для качественного проектирования базы данных необходимо время. Результирующая схема базы данных может выглядеть совсем иначе, чем исходные диаграммы объектов.
Очевидный способ связать уровень домена с базой данных заключается в том, чтобы классы домена умели создавать себя на основе базы данных. Классы могут иметь процедуры загрузки, которые извлекают данные из базы данных и используют их для создания и связывания доменных объектов. Важно, чтобы слой приложения не был вовлечен в такой процесс. Когда приложение запрашивает объект, уровень домена должен посмотреть, есть ли он в памяти. Если нет, то он должен сам создать объект из базы данных. Слою приложения не нужно знать, как происходит это взаимодействие.
Исключение составляют случаи, когда слою приложения требуется определенная конфигурация данных для работы, и эти данные могут быть получены из базы данных за один шаг в самом начале, что повышает производительность. В этом случае доменному уровню может быть полезно предлагать специфические для слоя приложения запросы загрузки, которые дают приложению возможность сообщить доменному уровню, что от него хотят получить. В некоторой степени это нарушает принцип, согласно которому доменное звено не должно знать, какие приложения его используют, но в некоторых случаях выигрыш в производительности может быть убедительным.
12.4.2 Уровень интерфейса базы данных
Прямая связь между уровнем домена и базой данных имеет ряд существенных проблем. Она может чрезмерно усложнить доменные классы, наделив их двумя независимыми обязанностями: предоставлять исполняемую модель бизнеса и извлекать данные из базы данных. Код, необходимый для взаимодействия с базой данных, может быть весьма значительным, чрезмерно раздувая классы. Если данные необходимо получать из нескольких баз данных и каналов, то эта проблема становится критической.
Ответ, конечно, заключается в добавлении еще одного уровня — уровня интерфейса базы данных, который отвечает за загрузку уровня домена данными из базы данных и за обновление базы данных при изменении домена. Этот уровень также отвечает за обработку каналов данных и других унаследованных взаимодействий.
Во многом интерфейсный уровень базы данных очень похож на уровень логики приложения. В обоих случаях фасад позволяет сложному уровню домена коммуницировать с менее мощным слоем представления. Этот фасад выбирает и упрощает структуру объектов и выполняет преобразование типов к более простой внешней системе типов. Опять же, уровень домена не должен знать о различных представлениях, которые могут быть в нем реализованы. Обычно классы интерфейсов баз данных основываются на источнике данных, с которым они работают. Класс интерфейса базы данных может быть создан для каждой таблицы в реляционной базе данных или для каждого типа записи в потоке данных. Библиотеки классов для поддержки взаимодействия с базами данных часто поддерживают такое сопоставление.
Самое большое различие между этим уровнем и уровнем логики приложения заключается в инициировании активности. В пользовательском интерфейсе действие пользователя заставляет презентацию инициировать активность. Поскольку презентация имеет доступ к слою логики приложения, ей несложно вызвать доменные операции. Инициация активности следует за линией видимости. Однако с интерфейсом базы данных дело обстоит иначе. Доменный уровень начинает процесс с желания сохранить свои объекты, но мы не хотим, чтобы доменная модель видела базу данных. Таким образом, инициация активности противоположна желаемой видимости. Одним из решений является повторное использование наблюдателя, но это может привести к очень большому объему трафика сообщений.
Альтернативой является расширение архитектуры с помощью интерфейсного брокера, который виден на уровне домена. Этот брокер предоставляет очень маленький интерфейс, который допускает только сообщения, инициирующие интерфейс базы данных. Обычно это могут быть такие общие вызовы, как loadMe(anObject)
и saveMe(anObject)
, которые передают всю ответственность за обработку запроса на уровень интерфейса базы данных. Ответственность брокера заключается в том, чтобы передать этот запрос классу в интерфейсе базы данных, который может наилучшим образом обработать запрос. Таким образом, если у нас есть спот-контракты, хранящиеся в одной таблице базы данных, и обычные опционы, хранящиеся в другой, интерфейсный брокер сначала опрашивает объект, чтобы выяснить, какой из них является объектом, а затем передает запрос соответствующему классу интерфейса базы данных, как показано на рис. 12.8 и 12.9.

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

Рисунок 12.9 Категории интерфейсного уровня базы данных.
Преимущества такого использования слоев аналогичны преимуществам разделения ответственности по слоям в других местах. Опять же, ответственность разделена полезным образом, отделяя интерфейс данных от бизнес-модели. Форматы таблиц или изменения в подаче данных могут быть выполнены без изменения модели домена. Это особенно важно, когда форматы таблиц находятся вне контроля проектной группы или когда есть вероятность, что структура данных может измениться для повышения производительности. Чем выше волатильность этих источников, тем важнее использовать промежуточный слой.
Для доступа к различным базам данных могут потребоваться различные инструменты и навыки. Существуют специализированные библиотеки классов для взаимодействия с продуктами баз данных. Может потребоваться знание SQL и конкретного формата базы данных. Другие базы данных (многомерные, иерархические) имеют свои собственные интерфейсы и структуры, которые необходимо изучить. Разделение этого взаимодействия, особенно при наличии большого количества различных источников данных, позволяет членам команды сосредоточиться на тех областях, в которых они наиболее сильны.
12.5 Заключительные размышления
Создание крупных информационных систем в среде клиент/сервер по-прежнему остается сложным занятием со множеством подводных камней. Многие из них связаны с использованием двухуровневой архитектуры, которая хорошо подходит для небольших систем, но плохо масштабируется. Трехуровневая архитектура значительно улучшает ситуацию и хорошо поддерживается объектной технологией. В табл. 12.1 приведены краткие описания трех уровней.
УРОВЕНЬ | ОПИСАНИЕ |
---|---|
Домен | Оригинальная модель бизнес-объектов, применимая ко всему домену. Независимая от отдельных приложений и источников данных. |
Логика приложения | Выбор и упрощение модели домена для приложения. Не содержит кода пользовательского интерфейса, но предоставляет набор фасадов доменных уровней для пользовательского интерфейса. Преобразует богатые типы доменных уровней в типы, необходимые для представления. |
Презентация | Выполняет форматирование информации из фасада приложения в графический интерфейс или бумажный отчет. Занимается только пользовательским интерфейсом и не имеет знаний о базовом уровне домена. |
Интерфейс данных | Отвечает за перемещение информации между источниками данных и доменным уровнем. Предоставляет простой интерфейсный брокер для доменного уровня, который будет отправлять запросы. Имеет доступ как до доменного уровня, так и до источников данных. Разделяется на подсистемы в зависимости от типа используемых источников данных. |
Таблица 12.1 Краткое описание слоев и их назначения.
Разделение звена приложения для отделения логики приложения от пользовательского интерфейса — ценная техника. Его преимущества включают повторное использование логики приложения для различных графических интерфейсов, простоту тестирования, управление производительностью для систем клиент/сервер и поддержку более специализированного состава разработчиков. Промежуточный уровень также полезен для доступа к данным, особенно при наличии множества сложных источников данных.
Некоторые классы должны использоваться на всех уровнях. К ним относятся общие фундаментальные типы (integer, date, quantity), коллекции, а также некоторые фундаментальные типы, специфичные для конкретной области.
Ссылки
Gamma, E., R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.
Hull, J.C. Options, Futures, and Other Derivative Securities (Second Edition). London: Prentice-Hall International, 1993.
Kain, J.B. Measuring the return on investment of reuse. Object Magazine, 4, 3 (1994), pp. 49–54.
Tsichiritzis, D.C., and A. Klug. The ANSI/X3/SPARC DBMS framework: report of the study group on database management systems. Information Systems, 3 (1978).