Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Архитектура ПО на практике.doc
Скачиваний:
3
Добавлен:
01.05.2025
Размер:
63 Мб
Скачать
☆

17.3. Архитектурное решение

В ответ на предъявленные требования было принято принципиальное архитек­турное решение, согласно которому архитектуру Luther следовало сконструиро­вать поверх архитектуры J2EE. У этого решения есть ряд преимуществ.

  • Архитектура J2EE существует во множестве коммерческих версий от раз­ных производителей. Компоненты, которые потенциально могли оказаться полезными для архитектуры Luther, разрабатывались повсеместно (в част­ности, речь идет о компонентах технологического управления).

  • Протокол HTTP, расположенный на верхнем уровне стека TCP/IP, стано­вился основным средством передачи данных. Сам же стек TCP/IP поддер­живался различными коммерческими беспроводными стандартами, в том числе IEEE 802.11b. В рамках инфраструктуры беспроводной локальной сети любого веб-клиента можно сделать мобильным. Кроме того, большин­ство устройств, которые архитектура Luther должна была поддерживать, в свою очередь поддерживают HTTP.

  • Принятое решение предусматривает отделение пользовательского интер­фейса и позволяет реализовать парадигму пользовательского опыта (user experience paradigm). Парадигма эта предполагает, что компьютер станет для рабочего одним из инструментов, причем инструмент этот будет но­сить ненавязчивый характер. Компьютер, согласно упомянутой парадигме, должен стать естественным расширением инструментов рабочего. При этом он приносит выгоды по части производительности — как самому рабочему, так и компании, в которой тот работает.

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

К примеру, если клавиатурный ввод в конкретном случае не подходит, его можно заменить речевым вводом. Если условия работы слишком шумные, имеет смысл обратиться к специализированному устройству ввода — на­пример, диску управления (dial). Поворачивая диск (который закрепляется на униформе рабочего — см. рис. 17.2), пользователь переходит по ссыл­кам, нажимает кнопки, выбирает положения переключателей и манипулирует другими средствами пользовательского интерфейса, предусмотренными в клиентском приложении, тем самым активизируя их. В средней части диска находится клавиша Enter, предназначенная для нажатия кнопок, пе­реходу по ссылкам и тому подобных действий. Диск применяется и в са­мых трудных условиях — с ним можно работать даже и толстых перчатках.

В главе 5 мы рассматривали тактику реализации практичности под назва­нием «отделение пользовательского интерфейса». В рамках архитектуры Luther эта тактика обеспечивает гибкость, позволяющую менять пользова­тельский интерфейс, адаптировать его к различным устройствам и потреб­ностям. Здесь, между прочим, проявляется другой атрибут качества — мо­дифицируемость. Это очередное подтверждение нашего постулата о том, что некоторые тактики позволяют реализовывать сразу несколько атрибу­тов качества.

  • Рассматриваемое решение позволяет разделять и абстрагировать источни­ки данных. В зависимости от конкретной ситуации использования устрой­ства пользователю могут потребоваться фильтрация, объединение, синтез и отображение данных, исходящих из разнородных источников. Среди этих источников — системы управления базами данных, а также унаследован­ные приложения, сконструированные на основе корпоративных систем планирования ресурсов с инкапсуляцией корпоративных данных. Сотруд­ники Inmedius поняли, что при условии абстрагирования и отделения ис­точников данных от приложений, которые к ним обращаются, а также при предоставлении для них четко очерченных стандартных интерфейсов при­ложения гарантированно придерживаются заданных абстракций и, таким образом, предусматривают возможность повторного использования. Кроме того, некоторые интерфейсы приняты в качестве стандартных (к таким интерфейсам, в частности, относится JDBC/ODBC). Они позволяют трак­товать источники данных как абстрактные компоненты, которые при жела­нии можно ввести или извлечь из корпоративного приложения.

Рис. 17.3. Представление размещения приложения Luther

На рис. 17.3 изображена схема взаимодействия приложения Luther со средой (элементы J2EE на ней не показаны — отображение приложения на J2EE мы еще обсудим). Во-первых, обратите внимание на отношение (n:1:m) между пользова­тельскими интерфейсами, приложениями и тем, что сотрудники Inmedius назы­вают компонентами, — иначе говоря, стандартными блоками конструирования функциональности приложения. Приложение Luther является топким; значитель­ная часть его бизнес-логики собрана из существующих компонентой и не привязана к какому-либо конкретному пользовательскому интерфейсу. Обобщенно, прикладной код состоит из следующих элементов:

  • определение состояния сеанса и управление этим состоянием;

  • прикладная (то есть не предусматривающая повторного использования) бизнес-логика;

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

В этом приложении нет основного метода — зато в нем есть интерфейс при­кладного программирования (application programming interface, AP1), выражающий характеристики и функции, которые приложение представляет пользовательс­ким интерфейсам. Пользовательский интерфейс независим от приложения. Он может включать любое подмножество характеристик, применимое к целевому интерфейсу устройства. К примеру, при создании интерфейса для устройства с микрофоном и динамиками, но без дисплея, интерфейс не предлагает средств графики.

Теперь попробуем провести углубленный анализ трех основных элементов, показанных на рис. 17.3: пользовательского интерфейса, приложения и компо­нентов.

Пользовательский интерфейс

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

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

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

В конце концов, для каждого конкретного приложения могут существовать разные клиентские устройства и пользовательские интерфейсы. Таким образом, от программной архитектуры требуется значительная гибкость — иначе она про­сто не сможет справиться с многочисленными разнородными клиентами. На рис. 17.4 и 17.5 изображены два типа реализации пользовательского интерфейса, предусмотренные архитектурой Luther, а именно: клиент на основе браузера (рис. 17.4) и специализированный веб-клиент (рис. 17.5). На рис. 17.6 уточняет­ся представление, приведенное на рис. 17.3; там же изображается структура каж­дого из упомянутых типов.

Клиенты на основе браузера

Клиенты пользовательского интерфейса на основе браузера напрямую соответ­ствуют предусмотренным в архитектуре J2EE клиентам на основе браузера. При этом они не ограничены веб-браузерами. В равной степени они поддерживают другие формы разметки — в частности, язык разметки беспроводных систем (Wireless Markup Language, WML) для беспроводного прикладного протокола (Wireless Application Protocol, WAP), применяемого в мобильных телефонах. Несмотря на различия по части языка разметки, для предоставления контента используются все те же механизмы, а именно: сочетание сервлетов и JavaServer Pages OSP).

Обмен информации осуществляется клиентом на основе браузера посредством стандартных методов (то есть коммерческих веб-браузеров на стороне клиента, HTTP посредством стека TCP/IP в качестве сетевого протокола и JSP и Java-сервлетов на стороне сервера) в универсальных форматах данных (гипертекстовые документы и таблицы стилей). Для того чтобы сделать клиента тонким, большая часть логики представления реализуется на сервере. Таким образом, возможно­сти создания интерфейса, обладающего переносимостью на браузеры разных про­изводителей и версий, значительно увеличивается.

Рис. 17.4. Интерфейс, отображаемый в браузере и предназначенный для выполнения

процедуры технического обслуживания

Рис. 17.5. Специализированный пользовательский веб-интерфейс

Рис. 17.6. Пользовательский интерфейс в представлении «компонент и соединитель»,

наложенном на представление размещения

Клиенты на основе браузера в основном ориентируются на:

  • устройства с поддержкой браузеров и традиционных устройств ввода (пе­рьев, клавиатуры и мыши);

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

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

Применение интерфейсов на основе браузера характеризуется некоторыми ограничениями. К примеру, с точки зрения проектирования они не всегда спо­собствуют оптимальному применению ограниченных ресурсов, таких как пло­щадь экрана. Кроме того, типы взаимодействия с пользователем, поддержива­емые моделью браузера, весьма ограничены и построены на основе цикла «запрос/ отклик» по протоколу HTTP. Кроме того, интерфейсы на основе браузера подхо­дят не для всех мобильных устройств, поскольку для некоторых из них браузе­ров не существует вообще. Если же они и реализованы, то поддержка важнейших характеристик (таких, как фреймы, графика и JavaScript) в них может отсутство­вать.

Специальные веб-клиенты

Специальные пользовательские веб-интерфейсы довольно сложны. Они не де­монстрируют прямого соответствия специальному клиенту, который в рамках архитектуры J2EE рассматривается как автономная программа, реализующая всю логику представления и взаимодействующая напрямую с бизнес-логикой (и част­ности, с элементами EJB) посредством удаленного вызова методов (remote method invocation, RMI) по межброкерному протоколу Интернета (Internet inter-ORB protocol, IIOP). Специальные веб-клиенты действительно представляют собой автономные программы, однако, в отличие от специальных клиентов по версии J2EE, для связи с сервером и взаимодействия с сущностями веб-звена (наподо­бие сервлетов nJSP) они используют протокол HTTP, демонстрируя тем самым схожесть с клиентами на основе браузера. Специальные веб-клиенты пишутся в собственной среде разработки в расчете на конкретное устройство или класс устройств. Являясь автономной программой, пользовательский интерфейс рас­сматриваемого типа предоставляет проектировщикам значительную свободу по части поддерживаемых моделей взаимодействия с пользователем. Отсюда — воз­можность оптимального освоения ресурсов наподобие пространства экрана. Воз­можность эта достигается за счет повышения стоимости разработки.

Как показано на рис. 17.6, в архитектуре Luther предпринята попытка мини­мизировать объем собственного кода при написании специального веб-клиента. Задача эта решается с помощью клиентского каркаса, поддерживающего интер­фейсы данного типа. По сути, этот каркас стандартизирует элементы, задейство­ванные в разных приложениях, — в частности, такие элементы, как управление сеансом, аутентификация, а также средства создания и упорядочивания логики представления со стороны клиента, веб-контейнера или с обеих этих сторон. Та­ким образом, клиент представляет собой тонкую автономную программу, которая создает или систематизирует свойственные пользовательским интерфейсам сред­ства. Кроме того, она реализует некоторую часть логики приложения — в частно­сти, проверку входных данных на правильность и сортировку информации в таб­личном представлении. Равно как и в случае с клиентами на основе браузера, большая часть логики представления реализуется в веб-звене, а конкретнее — в компонентах, управляемых клиентским каркасом.

Специальные веб-клиенты обладают множеством преимуществ над другими типами специализированных пользовательских интерфейсов. Во-первых, они тон­кие — другими словами, в сравнении с толстым клиентом (то есть специальной программой, в которой вся логика представления реализуется в клиентском зве­не) они компактнее, удобнее в сопровождении, а кроме того, способствуют пере­носимости между разными устройствами. Во-вторых, для взаимодействия с веб­-звеном они обращаются к протоколу HTTP и этим отличаются от специальных клиентов по версии J2EE, которые используют удаленный вызов методов (RMI) по протоколу IIOP Таким образом, они лучше подходят для реализаций, напи­санных не на Java, и применения в беспроводных сетях.

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

Приложения

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

Приложения могут находиться между произвольным числом пользователь­ских интерфейсов и компонентов. Таким образом, приложения связывают m ком­понентов и выставляют напоказ совокупную «прикладную» функциональность n пользовательских интерфейсов. Такие приложения «не распознают» пользова­тельские интерфейсы — иначе говоря, они способны выставлять напоказ такую функциональность, которую может использовать любой пользовательский интер­фейс. В зависимости от ситуации любой пользовательский интерфейс выставля­ет напоказ всю функциональность или какое-то из ее подмножеств. К примеру, пользовательский интерфейс, исполняемый на мобильном клиенте (например, на устройстве с операционной системой Windows СЕ), не может предлагать воз­можности администрирования, которые были бы вполне приемлемы в рамках версии этого интерфейса для настольной системы. Идея в том, чтобы выставлять напоказ все функции, которые могут быть выполнены в данной системе. Реше­ние о том, какие из них предоставить пользователю и как это сделать, каждый пользовательский интерфейс принимает самостоятельно.

Согласно требованию об оперативности разработки и размещения, приложе­ние разрабатывается в как можно более тонком виде. Реализуется эта задача путем делегирования большей части бизнес-задач компонентам (об этом мы по­говорим в следующем разделе). Критерий, исходя из которого прикладной код передается компонентам, очень прост. Сформулировать его можно так: «Преду­сматривает ли данная функциональность возможность повторного использова­ния?». Если предусматривает, то ее необходимо обобщить, тем самым увеличив шансы на многократное применение, и, соответственно, реализовать как компо­нент. Если же вероятность повторного использования данного функционального блока низка, значит, его стоит встроить в приложение.

Ниже перечислены основные элементы приложений.

  • Интерфейс прикладного программирования. Представляет собой фасад функ­ций, которые система выставляет напоказ пользовательским интерфейсам. Обратите внимание на то, что данные, передаваемые через интерфейс при­кладного программирования, не адаптированы к конкретному представле­нию (например, HTML) и носят универсальный характер (например, XML).

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

  • Прикладная бизнес-логика. Это любая логика, которая является уникаль­ной для приложения и не предусматривает повторного использования в дру­гих приложениях.

  • Делегирование компонентам. Это код, предназначенный для делегирования задач компонентам. Как правило, реализуется посредством образца проек­тирования под названием «бизнес-делегат» (Business Delegate9).

Эти элементы появляются в результате применения тактики «прогнозирова­ние ожидаемых изменений» и родственны тактике реализации модифицируемо­сти под названием «отделение пользовательского интерфейса».

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

Компоненты

Компонент по определению выражает практику многократного применения. Стра­тегия, таким образом, состоит в том, чтобы сформировать из компонентов биб­лиотеку, на основе которой можно будет быстро и без особого труда конструировать приложения, реализующие специализированные решения для конкретных заказ­чиков. В любой библиотеке содержатся базовые компоненты (core components), относящиеся к клиентскому и серверному каркасам; предметно-ориентированные компоненты (domain-specific components), отражающие специфику конкрет­ной предметной области (например, сопровождения, восстановления или пере­строения); и компоненты общих возмоясностей (generalized capability components; другое название — вспомогательные компоненты (utility components)), с помощью которых производится окончательная комплектация функциональности прило­жений (например, реализация авторизации и управление пользователями).

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

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

Проектирование компонентов

Согласно стратегии проектирования компонентов, интерфейсы прикладного про­граммирования и поведение компонентов должны при малейшей возможности разрабатываться на основе стандартов проектирования. К примеру, рассматрива­емый чуть позже компонент технологического управления являет собой конкре­тизацию спецификации, составленной группой по технологическому управлению (Workflow Management Coalition), которая определяет функциональность и по­ведение при организации технологических процессов. Такая стратегия проекти­рования позволяет Inmedius заменять собственные компоненты компонентами любых других производителей и придерживаться тех же, что и они, специфика­ций возможностей. Она способствует расширению библиотеки компонентов Inmedius.

Разделение возможностей

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

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

Пакетирование компонентов

Все без исключения приложения в рамках Luther обращаются к среде J2EE и ее службам. Учитывая это ограничение, компоненты в данной среде можно пакети­ровать в виде элементов EJB, компонентов Java beans, отдельных библиотек классов Java, апплетов, сервлетов или произвольного сочетания перечисленных элемен­тов. Другими словами, компонент, не являясь синонимом EJB, гем не менее до­пускает разные варианты пакетирования.

Выбор стратегии пакетирования конкретной возможности обусловливается набором применяемых служб J2EE и решениями, уравновешивающими ряд зна­чимых факторов (частоты межобъектного взаимодействия, местонахождения объектных экземпляров, а также необходимости применения разного рода служб J2EE — в частности, службы транзакций и службы устойчивости состояния объ­екта в продолжение нескольких пользовательских сеансов). К примеру, обмен данными с элементами EJB осуществляется путем удаленного вызова методов (RMI) — довольно тяжеловесного механизма взаимодействия. Некоторые контейнеры J2EE допускают оптимизацию обмена данными с элементами EJB (ко­торый в таком случае производится путем локального вызова методов); однако делается это лишь в том случае, если обмен данными происходит в рамках одной виртуальной машины Java (Java Virtual Machine, JVM). Тем не менее, поскольку оптимизация не входит в число требований к контейнерам J2EE, обмен данными между элементами EJB всегда связан с риском серьезного увеличения издержек, в связи с чем к этому вопросу следует относиться с осторожностью — если, ко­нечно, вас заботит производительность. В качестве альтернативного решения можно создать библиотеку клaccoв Java, которая позволяет избежать удаленного вызова методов, а следовательно, и связанных с этим механизмом издержек. Впро­чем, в таком случае компонентам приходится брать на себя дополнительные обя­занности, которые обычно выполняются контейнерами, — в частности, связан­ные с созданием и удалением экземпляров компонентов.

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

Как мы говорили в главе 16, модель EJB поддерживает несколько типов beans: beans-сущности (entity beans), сеансовые beans (session beans) и сеансовые beans без состояния (stateless session beans). Эти типы beans ориентированы на разные формы бизнес-логики и, соответственно, по-разному обрабатываются контейне­рами. К примеру, bean-сущность допускает самостоятельное управление устой­чивостью, которое осуществляется посредством поддерживаемых контейнером обратных вызовов (так называемая устойчивость под управлением beans, или самоуправляемая устойчивость); кроме того, эти задачи может вынолнять сам контейнер (так называемое контейнерное управление устойчивостью). В любом случае, эти операции связаны со значительными непроизводительными издерж­ками, которые ограничивают практическое применение beans-сущностей долго­временными бизнес-объектами, характеризующимися крупноблочным доступом к данным.

Что делает контейнер J2EE?

Приложения выказывают потребность в самых разных возможностях — напри­мер, в поддержке транзакций, безопасности и выравнивании нагрузки. Эги воз­можности очень сложны (многие корпорации даже организуют специальные под­разделения, предназначенные исключительно для их обеспечения) и находятся за рамками любого конкретного приложения или прикладной области. Один из основных мотивов, которым руководствовалась компания Inmedius, принимая решение о создании архитектуры Luther на основе J2EE, состоял в том, что по­добные характеристики реализованы в коммерческих общедоступных совмести­мых cJ2EE контейнерах, и, следовательно, Inmedius не пришлось реализовывать их самостоятельно.

Многие из этих возможностей можно конфигурировать для конкретного эле­мента EJB в период размещения приложения. Есть и другая альтернатива — они могут присутствовать в контейнерах J2EE и носить прозрачный характер. В лю­бом случае, разработчикам EJB не приходится встраивать вызовы к ним непо­средственно в код; следовательно, их можно без труда сконфигурировать с уче­том потребностей любого конкретного заказчика. Тем самым упрощается процесс создания компонентов EJB, независимых от конкретного приложения, и гаранти­руется их исполнение в рамках любых совместимых с J2EE контейнеров.

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

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

  • Наконец, EJB-контейнер обеспечивает прозрачное выравнивание нагруз­ки. Создание и управление экземплярами EJB осуществляется контейне­ром в период исполнения — при необходимости они создаются, активиру­ются, пассивируются и удаляются. Если обращений к данному элементу EJB давно не поступало, его можно пассивировать — при этом его данные сохраняются а постоянном устройстве хранения, а экземпляр удаляется из памяти. Таким способом контейнер фактически выравнивает нагрузку в масштабе всех экземпляров в контейнере, регулирует потребление ресур­сов и оптимизирует производительность системы.

Что делает разработчик компонентов?

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

Кроме того, разработчик компонента составляет определение типов данных, выставляемых напоказ клиентам через интерфейс прикладного программирова­ния. Они реализуются как дополнительные классы и во многих случаях прини­мают форму объектов значения (value objects), которые посредством интерфейса прикладного программирования передаются элементу EJB и извлекаются из него.

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

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

Логическое обоснование проекта

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

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

  • размер и сложность комплексного технологического управления выходили за рамки имевшихся у компании ресурсов;

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

  • значительно более комплексные решения были уже созданы другими ком­паниями.

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

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

Группой по технологическому управлению (Workflow Management Coalition) был разработан ряд спецификаций функций и поведения, связанных с техноло­гическим управлением, который впоследствии был признан сообществом. При построении компонентов архитекторы Inmedius исходили из этих спецификаций, однако реализовывали только ту функциональность, которая была необходима для разрабатываемых приложений.

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

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

Рис. 17.7. Диаграмма классов компонента технологического управления

Одна из проблем, которую Inmedius предстояло решить, была связана с па­раллелизмом. Есть ли необходимость в том, чтобы модель технологического уп­равления могли модифицировать несколько пользователей одновременно? Сле­дует ли разрешать пользователю модифицировать модель технологического управления при наличии ее активных экземпляров для периода прогона? Может ли пользователь запускать новый технологический процесс, если его модель в дан­ный момент модифицируется? Учитывая реализацию, а также отношения между моделью и ее экземплярами периода прогона, было бы весьма проблематично ответить утвердительно на любой из этих вопросов. Следовательно, в области решений перечисленные ситуации нужно запретить.

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

Пакетирование

Компонент технологического управления пакетируется в двух элементах EJB: u сеансовом bean без состояния, предназначенном для управления экземплярами модели технологического управления, и bean-сущности, предназначенной для управления самой моделью (рис. 17.8). Это решение о пакетировании компонен­та обусловливается исключительно характеристиками различных типов EJB,

Рис. 17.8. Диаграмма пакетов компонента технологического управления

Абстракции, реализуемые в приложении сущностными EJB, выражают сов­местно используемые ресурсы, в рамках которых данные устойчивого объекта доступны многочисленным компонентам и пользователям. Модель технологи­ческого управления представляет единственный ресурс подобного рода, а имен­но процесс, допускающий многократную конкретизацию. Любой пользователь приложений Inmedius, независимо от своего местоположения, может запускать новые процессы, основанные на упомянутой модели технологического управле­ния, и участвовать в их действиях.

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

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

С тем, как пакетировать отдельные объекты в рамках модели технологическо­го управления, было связано еще одно компромиссное решение. Следует ли их пакетировать в виде сущностных EJB или в виде Java-клaccoв, пакетированных в другой структуре (например, в библиотеке)? Поскольку эти объекты взаимо­действуют и зависят друг от друга, при их пакетировании в виде сущностных EJB нужно было бы постоянно обнаруживать местонахождение и сохранять мно­гочисленные EJB-дескрипторы приложения, а следовательно, вводить дополни­тельные издержки. Кроме того, как мы помним, вызов любого метода в EJB про­изводится удаленно (в виде RMI), а значит, также связан с непроизводительными издержками. Большинство контейнеров J2EE способны определять, относится ли вызываемый метод к той же виртуальной машине Java, к которой принадле­жит вызывающая сторона, и, таким образом, оптимизировать его до локального вызова, но все-таки это делают далеко не все. Исходя из этих соображений было принято следующее проектное решение. Крупные абстракции (такие, как модель технологического управления) в приложении предполагалось выразить в виде объектных EJB, а относительно мелкие — реализовать в сущностных EJB в виде библиотеки классов. Все эти операции были направлены на снижение допол­нительных издержек, связанных с тяжеловесными отношениями между сущно­стными EJB.

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

Эта проблема стала очевидной, когда пришло время корректировать бизнес- логику, — так, чтобы ключ выдавался только в отсутствие активных экземпляров технологического управления периода прогона. Методы, предоставлявшие ин­формацию об экземплярах технологического управления в период прогона, опре­делялись в сеансовом элементе EJB с запоминанием состояния — объекте, взаи­модействовавшем с сущностным EJB. Решение о передаче ссылки на сеансовый EJB с запоминанием состояния сущностному EJB оказалось неоптимальным — в первую очередь, по той причине, что в таком случае сущностный EJB был бы привязан к среде (а следовательно, возможность повторного использования ис­ключалась); во-вторых, потому что сущностный EJB обращался бы к сеансовому EJB с запоминанием состояния только посредством удаленных вызовов методов.

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

Было найдено следующее решение. Логика (регулирующая предоставление ключа для изменения модели технологического процесса) помещалась в сеансо­вый EJB без состояния. Сущностный EJB в таком случае знает, как извлекать ключи из базы данных и помещать их в нее. При получении запроса на предоста­вление ключа сеансовый EJB без состояния определяет возможность его предо­ставления и, если таковая существует, инструктирует сущностный EJB относи­тельно блокировки модели технологического управления. Такое решение сохраняет целостность реализованных в объектах абстракций и устраняет излишние взаи­мосвязи между элементами EJB.

Распределенные и обособленные операции

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

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

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

Следствия применения J2EE

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

Индивидуальные проектные решения и решения, обусловленные спецификой J2EE

В ходе проектирования системы в исполняемой cpeде J2EE одни решения проекти­ровщик принимает самостоятельно, а другие — исходя из правил и структуры J2EE. К примеру, J2EE устанавливает местоположение сервлетов JSР и EJB в составе кон­тейнера: сервлеты и JSP находятся в веб-звене, а элементы EJB — в EJB-звене.

В то же время архитектура J2EE в некоторых случаях допускает принятие гибких проектных решений — к примеру, в том, что касается реализации безопас­ности (декларативной и программной), поддержки транзакций (декларативной и программной) и доступа к данным (с контейнерным управлением и с самоуп­равлением bean).

В процессе проектирования компонента проектировщик обладает неограни­ченными возможностями применения сервлетов, JSP и EJB. В такой ситуации следует избегать опрометчивых решений. К примеру, один из компонентов ком­пании Inmedius допускает сотрудничество двух и более пользователей. Посколь­ку этот компонент выражает бизнес-логику, допускающую многократное приме­нение, согласно правилам отбора компонентов его следует упаковывать в виде EJB. Углубленный анализ доказывает, что это проектное решение является не- оптимальным. Как показано на рис. 16.2, при отображении проектного решения компонента на четыре логических звена, предусмотренные J2EE, необходимо принимать во внимание побочные факторы.

Проблемы многозвенности в J2EE

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

Еще одна проблема связана с транзакциями, которые управляются либо про­граммно, либо декларативно. Очевидно, управлять транзакциями декларативно в некоторых отношениях проще — в коде отсутствуют операторы начала и завер­шения транзакции. С другой стороны, разработчики должны принимать во вни­мание предполагаемый механизм применения сущности J2EE. Согласно простей­шему решению, транзакции требуются во всех методах. К сожалению, если насущная необходимость в применении транзакций отсутствует, появляются лиш­ние издержки. Иногда дескриптор размещения предписывает поддержку транз­акций даже в том случае, если методы сущности J2EE их не предусматривают. Если контейнер — второй участник транзакции — обратится к такой сущности J2EE, созданная им транзакция аварийно закроется. Декларирование дескрипто­ром размещения поддержки транзакции в конкретном методе представляется более оптимальным решением. Особое внимание следует уделять анализу компонента на предмет выявления аспектов, корректность функционирования которых на­прямую зависит от поддержки транзакций. Принятые решения необходимо при­вести в соответствие с декларативными и программными механизмами, преду­смотренными в архитектуре J2EE.