Search

Rss Posts

Rss Comments

Login

 

Часть 2: Сохранение состояния на стороне клиента

Сен 20

Автор: Steven Webster

В части 1 этой публикации, я познакомил вас с Cairngorm – компактной программной архитектурой, которая упрощает решение многих сложных повторяющихся задач в процессе создания насыщенных Интернет приложений, которые называют RIA.
В этой части я опишу задачи, которые возникают в процессе разработки RIA, а в частности как хранить состояние на стороне клиента. Я поясню это на примере создания интренет-магазина, который мы будем называть "Магазин Cairngorm". Вы изучите два фундаментальных паттерна архитектуры Cairngorm: паттерн Value Object и паттерн Model Locator. Под конец этой статьи вам будет понятно, насколько прозрачным можно сделать Flex-приложение, используя эти два паттерна.

ВВЕДЕНИЕ В "МАГАЗИН CAIRNGORM"

Flex Интернет-магазин демонстрирует возможности Flex-фреймворка. Здесь хорошо видно как можно использовать различные контейнеры для разметки, навигационные контейнеры, элементы управления, эффекты, связывание данных, менеджер Drag-and-Drop, валидатор форм, и менеджер истории. Кроме того, Flex магазин следует компонентной модели построения приложения во Flex, показывая каким образом можно создать ряд независимых компонентов и связать их воедино в событийной архитектуре. Flex магазин – замечательный способ познакомиться с декларативной разметкой используя MXML и бизнес логикой реализованной на ActionScript.

Рис. 1. Магазин Cairngorm
Рис. 1. Магазин Cairngorm

Я выбрал хорошо всем знакомую идею Интернет-магазина и реализовал ее как RIA уровня предприятия – приложение которое производительно, масштабируемо, и технически сопровождаемо – с помощью Cairngorm.

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

МАГАЗИН CAIRNGORM: ЧЕТЫРЕ ПРОБЛЕМЫ

Вместо академических рассуждений на тему паттернов проектирования, которые мы заложили в Cairngorm, я объясню самые важные проблемы, возникающие во время разработки RIA, и как можно решить их с помощью Cairngorm. Описывая сам процесс разработки, я попутно буду объяснять паттерны, из которых состоит сам Cairngorm.
Хороший технический архитектор сначала видит разработку приложения как решение бизнес проблемы, потом как систему, которая реализует это решение, потом как техническую архитектуру в этой системе, и уже в конце, как набор классов той архитектуры.
Такой метод разработки, каким предоставляет его Cairngorm, обеспечивает большую ясность реализации, нежели просто нырять в код.
На самом высоком уровне абстракции, есть всего четыре проблемы, с которыми сталкивалась группа Adobe Consulting, толи, создавая, ипотечные калькуляторы, системы пенсионных платежей, Интернет-банкинга, электронных платежей состоящих из одной странницы, полновесных систем электронной коммерции, или же интерактивных карт. Эти проблемы это:
- сохранение состояния на стороне клиента
- разработка представления данных
- реализация характерных функций
- вызов серверных служб
Для Магазина Cairngorm предъявляются те же требования и возникают те же проблемы.
Клиентская часть приложения показывает товар покупателю, корзина покупателя хранит все приобретенные товары, и пользователь должен пройти несколько стадий во время процесса оплаты. На протяжении всего это процесса, ваше приложении должно сохранять состояние на стороне клиента.
Отдельно взятое окно такого приложения имеет много разных элементов. Оно содержит и графический материал, и список свойств товара, и детальное описание; в корзину покупателя можно добавить разные товары; и серию форм, которые должен заполнить пользователь для оформления заказа. Все это касается разработки представления данных – View.
Также есть перечень особенностей такого рода приложения. Клиент должен иметь возможность выполнить следующее:
- просмотреть все продукты и получить детальное описание выбранного
- добавить или удалить из корзины продукт
- купить продукт в своей корзине
- пройти процесс оформления заказа
Эти свойства должны быть реализованными вами.
И последнее это то, что все необходимые данные ваше приложение получает из базы данных. И более того, при оформлении заказа, может понадобиться сохранения заказа в базе данных или же отправить их, скажем, в SAP. Таким образом, ваше приложение должно быть интегрировано с серверной частью.
Как вы можете видеть, наш Магазин Cairngorm – несмотря на свою уникальность в сфере бизнеса, работой с продукцией, поведением и свойствами – выглядит точно таким же, как и любое другое RIA, если мы рассматриваем его через призму четырех вышеозначенных проблем разработки.
В этой главе я буду касаться только первой из четырех проблем: сохранение состояния на стороне клиента.

ХРАНЕНИЕ СОСТОЯНИЯ НА СТОРОНЕ КЛИЕНТА

Главное отличие RIA от традиционных вэб-приложений это то, что клиент хранит свое состоние.
Разработчикам вэб-приложений очень хорошо знакома идея запрос-ответ – серфинга без сохранения состояния. Поэтому им приходится изобретать различные приемы для поддержки состояния клиента. Либо вы постоянно передаете одни и те же данные в HTTP запросе в процессе смены страниц, или вы используете URL-кодирование, или Куки чтоб сохранить небольшое количество данных на стороне клиента, или вы используете абстракции вроде J2EE сессий – все это механизмы сохранения состояния на стороне сервера и делание их доступными для клиента.
Однако с RIA разработчики освобождаются от кандалов HTTP запрос-ответ модели. Больше не надо использовать какие либо механизмы для сохранения состояния клиента – теперь он изначально сам хранит свое состояние. Если вы когда-либо создавали десктоп приложения или RIA, скажем, с помощью Swing или AWT, то все вышесказанное покажется вам известным – так оно и есть.

РАЗНИЦА МЕЖДУ СОСТОЯНИЕМ И МОДЕЛЬЮ В MVC

Многие разработчики знакомы с концепцией MVC (Модель-Вид-Контроллер) и, пожалуй, удивляются, при чем здесь Состояние. Все очень просто: состояние это и есть модель. Но на сколько это очевидно, это также порождает ряд других проблем с описанием модели в RIA.
Самая первая из них это то, что очень сложно расчленить состояние вашего приложения на строки, числа, булевы, и на прочие примитивные объекты. Здесь я не хочу вдаваться в обсуждение лучших практик объектно-ориентированного программирования. Хотя бы потому, что для понимания данного материала вы уже должны их знать.
Тем не менее, я решительно утверждаю, что те данные, которые содержит клиент – есть Состояние или Модель, или любой другой термин, имеющий семантическое значение. Что значит "семантическое значение" в данном контексте? Ну, например, если вы продаете рыболовные приманки, то ваша объектная модель будет включать «муха», «мотыль», «блесна». Если вы продаете ипотечные кредиты, то ваша объектная модель будет включать «продукт», «процентная ставка», «рефинансирование», «условия». Если вы продаете географические карты, то ваша объектная модель будет включать «маршрут», «координаты», «достопримечательности», «заправки».

СИНХРОНИЗАЦИЯ СОСТОЯНИЙ КЛИЕНТА И СЕРВЕРА

Есть одна проблема, связанная с RIA, уникальная для клиента хранящего свое состояние: состояние клиента обычно отображает состояние на другом конце линии – сервера. Давайте немного детальней поговорим об этом.
При разработке серверного приложения, одним из ключевых моментов есть то, что состояние хранится между двумя уровнями программной модели: между бизнес-уровнем и уровнем интеграции.
Уровень интеграции обычно включает в себя базы данных, мэйнфреймы, очереди сообщений, системы ERP (система управления предприятием – прим. перев.), CRM системы (системы управления продажами – прим. перев.) и другие информационные системы предприятия, которые хранят данные и управляют процессами характерными для конкретной проблемной области.
Все эти системы, при разработке серверного ПО, собираются воедино и предоставляются для доступа пользователю через промежуточный уровень, который называют «бизнес-уровень». Есть целое множество решений, призванных решить проблемы хранения состояния между двумя этими уровнями. Прежде всего, это из-за того, что представление данных на двух этих уровнях, может кардинально отличаться. Для примера, понятия сущности, отношения, видов, запросов, которые характерны для баз данных, должны быть отображены из модели базы данных на объектные модели данных приложений бизнес-уровня. Для этих задач могут использоваться такие технологии как Enterprise JavaBeans, Hibernate (8), ADO.NET.
Независимо от выбранного решения, разработчик несет большую ответственность за обеспечение целостности данных при передаче их между этими уровнями. Как только вы начинаете хранить одни и те же данные в двух разных местах, появляется опасность изменения данных в одном месте, которые не отобразились в другом, или же одни данные перезаписываются другими. Также разработчик должен заботится о параллельных процессах, блокировках, транзакциях, откатах и других средствах, гарантирующих то, что модель данных целостная в разных участках архитектуры.
Поскольку вы RIA разработчик, вы абстрагированы от сложностей взаимоотношений бизнес уровня и уровня интеграции. Вас больше беспокоит то, как обеспечить целостность данных в бизнес и презентационном уровнях.
Самое простое для вас в этом случае, это согласовать модель данных на клиенте и на сервере, это уже сократит ваши усилия для синхронизации данных.

ВВЕДЕНИЕ В ПАТТЕРНЫ VALUE OBJECT И DATA TRANSFER OBJECT

Всякий раз, когда вам нужно представить значение какой-то сущности в приложении, вы создадите класс, представляющий эту сущность. Например, в Магазине Cairngorm есть сущность представляющая продукт. Каждый продукт имеет множество атрибутов: имя, описание, цена, картинка, иконка.
Этот объект-значение (value object) играет двойную роль в RIA приложении. Кроме того, что он хранит значение на клиенте, он также может быть полезной структурой с помощью, которой вы можете обмениваться данными между различными уровнями приложения. Например, возможна такая ситуация, когда SQL-запрос к базе данных возвращает некий результат, который конвертируется в массив подобных объектов-значений.
Передавая такие объекты-значения между различными уровнями приложения, вы тем самым изолируете каждый уровень от внутренней логики работы его соседних уровней. Таким образом, промежуточному программному слою не будет нужды волноваться, где именно был создан полученный объект-значение: из SQL-запроса, хранимой процедуры или вызова вэб-службы. Повторно используя такие объекты-значения, вы расчленяете архитектуру приложения, передавая данные между уровнями как объекты со значением проблемной области («Продукт», «Рыба», «Карта»), нежели их техническими значениями («Запись», «Результат», «Группа данных»). Все это привело к именованию этого паттерна как Value Object (объект-значение), вместо Data Transfer Object (DTO, объект передачи данных).
Мы придумали Cairngorm еще до того, как термин DTO широко распространился, поэтому я называю бизнес сущности Value Object или просто VO.
Для примера, рассмотрите VO из Магазина Cairngorm (он располагается в org/nevis/cairngorm/samples/store/vo):

class org.nevis.cairngorm.samples.store.vo.ProductVO implements ValueObject, Comparable
{
	public static var registered:Boolean = Object.registerClass( "org.nevis.cairngorm.samples.store.vo.ProductVO", ProductVO );

	public var id : Number;
	public var name : String;
	public var description : String;
	public var price : Number;
	public var image : String;
	public var thumbnail : String;
}

Конечно же, это не космические технологии. ProductVO есть не что иное, как набор атрибутов, которые описывают класс Product как продукт. Всякий раз, когда вы будете сохранять состояние на клиенте о продуктах, храните их в экземплярах класса ProductVO. Если приложение должно знать какой сейчас «продукт выбран», сохраняйте эту информацию в экземпляре ProductVO. Если приложение должно хранить список продуктов в корзине покупателя, сохраняйте эту информацию на клиенте в массиве экземпляров ProductVO.
Более того, если вы получаете от сервера список продуктов, или передаете продукты назад на сервер, передавайте их как объекты-значения. Кто-то может сказать, что здесь мы используем DTO. Это есть одно и тоже – помните это.

СОХРАНЕНИЕ ЦЕЛОСТНОСТИ МОДЕЛИ ДАННЫХ МЕЖДУ FLEX И JAVA

Серверное ПО, обычно представляет собой хорошо разработанную объектную модель. При использовании J2EE, скорее всего на сервере уже имеется Java модуль (package) объекта-значения, представляющий собой именно тот объект, который нужен клиенту.
В этом случае, сервер проделывает для Flex-приложения большую работу. Если вы хотите передать ActionScript объект-значение для Java приложения, Flex может автоматически создать эквивалент Java-объекта. Аналогично, когда Java приложения возвращает объект-значение клиенту, Flex конвертирует его в эквивалент объекта ActionScript.
И даже более, если объект не просто один объект, а составной граф из объектов, Flex выполнит всю работу по преобразованию в нужный объект, и даже сохранит связи между объектами. Таким образом, когда у вас есть объект ShopingCartVO, содержащий список ProductVO, а каждый ProductVO содержит список объектов AddressVO (адрес доставки и адрес для счета-факутры), и возможно объект DiscountVO, Flex обеспечит целостность объектов при передаче между RIA приложением и серверным ПО.
Для того чтобы обеспечить отображение (мапинг) серверных и клиентских объектов, нужно дать некую подсказку для Flex о существовании связи между объектами. В Cairngorm для этого нужно указать в каждом экземпляре объекта-значения, следующее:

public static var registered:Boolean = Object.registerClass( "org.nevis.cairngorm.samples.store.vo.ProductVO", ProductVO );

Это гарантирует то, что класс ProductVO на клиенте отображается на Java класс ProductVO.java, который находится в пакете org.nevis.cairngorm.samples.store.vo.ProductVO на сервере.

Использование XDoclet2 для ActionScript

XDoclet2 – это генератор кода ActionScript, написанный на Java. Джо Берковец из Allurent создал это проект с открытым исходным кодом, который создает ActionScript классы для VO из Java-аналогов. Вы можете больше узнать об этом проекте, а также скачать исходный код из SourceForge по адресу www.allurent.com/joeb/xdoclet2.

Резюмируя, Value Object обеспечивает:
- Использование лучшего подхода к программированию, представляя данные на клиенте в понятных терминах для данной предметной области
- Поддержка целостной модели данных между клиентом и сервером
- Использование возможностей Flex для транслирования объектов-значений между Java и ActionScript

Но получение данных клиентом от сервера, это только часть проблемы. А что вы будете делать с клиентскими данными и где вы будете их хранить, чтобы решить проблему полностью?

СВЯЗЫВАНИЕ МОДЕЛИ И ВИДА ВОЕДИНО

Смысл данных на презентационном уровне в n-уровневом приложении – это их отображение. А смысл R в слове RIA – это отображение этих данных насыщенным и разнообразным способом.
Связывание данных во Flex’e, одно из скромно умалчиваемых его особенностей. Связывание данных позволяет взаимодействовать двум объектам как источник и назначение. Изменение в объекте-источнике, сразу отображается в объекте-приемнике. Если объектом-приемником является визуальный компонент, а объектом-источником данные клиентского приложения, вы получаете мощное средство отображения состояния клиентского приложения пользователю в масштабе реального времени. Таким образом, вид клиентского приложения всегда останется актуальным, модель (состояние клиента) будет оповещать вид (пользовательский интерфейс), если вы свяжете модель и вид вместе.
В Adobe Consulting мы наблюдали за командами разработчиков процессом, создающими решения для обновления пользовательского интерфейса, когда подлежащая модель изменялась. Более того, эти разработчики легко попадали в путаницу, если эти данные отображались в разных местах и разным способом. Скажем, у вас есть последовательность чисел, которая была обновлена новыми данными из сервера. В зависимости от места в приложении, их надо показать либо в таблице или графиком, или в каком-то резюмированном виде согласно бизнес логике. Но если в результате рефакторинга, вы вынесете эти данные в модель, и используете механизм связывания, вы устраните много сложностей для процесса взаимодействия в RIA.
Более того, мы заметили, что каждый разработчик хранит нужные ему данные для своей части программы, в своем участке кода. Соответственно, если эти данные нужны другому разработчику в другой части приложения, ему придется заботиться, чтоб эти данные теперь отразились еще и в другом месте.
Часто мы видели, что программисты обращается к данным через длинную цепочку ссылок на компоненту, например: mx.core.Application.application.storeView.textualList.productGrid. Такой подход является невероятно хрупким – добавление или удаление компонента (storeView, textualList) потребует от разработчика обновления ссылок на productGrid.
Еще одним вариантом может быть передача данных от одного MXML-компонента к другому. Если рассматривать MXML компоненты как деревья, а данные будут их листьями, то некоторые листья будут нужны на разных деревьях. Единственное решение здесь, это найти общую точку ответвления для этих листьев, чтобы данные можно было передавать в виде:

<myView:MyComponent data="{this.data}" />

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

ВВЕДЕНИЕ В ПАТТЕРН MODEL LOCATOR

Видя, как разработчики постоянно попадают в эту ловушку, команда Adobe Consulting осознала, что паттерн Model Locator является правильным решением для Flex программистов. Паттерн Model Locator уникален, поскольку он не заимствован из каталога паттернов J2EE. Мы создали его специально для Flex приложений. Нашей целью было создать единственное место, где будет хранится состояние Flex приложения и где View-компоненты должны находить данные, которые им нужно отобразить.
Наш паттерн Model Locator предполагает использование связывание данных (data binding), так что визуальные компоненты напрямую привязаны к состоянию клиента, которое хранится в одном экземпляре класса ModelLocator. Таким образом, как только модель изменятся в классе ModelLocator, все view-компоненты, привязанные к модели, получают уведомления (через внутренний механизм Flex Data Binding) и перерисовывают новые данные клиента.
Cairngorm предоставляет маркерный интерфейс для паттерна Model Locator и в Магазине Cairngorm мы имеем единственный класс, который описывает это интерфейс: org.nevis.cairngorm.samples.store.model.ModelLocator.
Рассмотрим несколько моментов использования класса ModelLocator. В Магазине Cairngorm есть понятие «выбранный продукт». Это предмет, который выбрал пользователь. Для этого наше приложение хранит в модели указатель на экземпляр класса ProductVO в атрибуте selctedItem, при этом панель ProductDetails использует его для отображения информации об этом продукте, а также он используется при добавлении продукта в корзину, когда пользователь нажимает кнопку «Add to Cart».
Вот так это объявлено в классе ModelLocator:

public static var selectedItem : ProductVO;

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

public static var products : Array; // содержит объекты ProductVO

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

public static var workflowState : Number;
//------------------------------------------------------------
public static var VIEWING_PRODUCTS_IN_THUMBNAILS : Number = 1;
public static var VIEWING_PRODUCTS_IN_GRID : Number = 2;
public static var VIEWING_CHECKOUT : Number = 3;

И наконец у нас есть компонента ShoppingCart, заключающая в себе необходимый функционал по добавлению и удалению продуктов в/из списка товаров для покупки клиентом. Этот объект хранится в атрибуте shoppingCart в ModelLocator и инициализируется в методе initialize().
Делая все атрибуты статическими в паттерне Model Locator вы получаете простую реализацию синглтона. Таким образом, к примеру, вы можете быть уверенным в том, что есть только одна инстанция ShoppingCart для одного клиента.
Единственный экземпляр ModelLocator инициализируется при старте главного приложения. В файле Main.mxml (точка входа в Магазин Cairngorm) у нас есть обработчик события creationComplete для Application:

<mx:Script>
<![CDATA[

    import org.nevis.cairngorm.samples.store.model.ModelLocator;  

    private function onCreationComplete() : Void
    {
        ModelLocator.initialise();
    }

]]>
</mx:Script>

Этот участок гарантирует, что все состояние клиента (например, его корзина) будет проинициализировано при старте приложения.
Дальше мы остановимся на ModelLocator поподробней. Но чтобы возбудить ваш интерес, скажу, что создавая свои компоненты, которые полагаются на данные на клиенте, вы не изобретаете запутанные способы, как достать эти данные, а просто привязываете эти компоненты к состоянию клиента через синглтон ModelLocator, в любой точке вашего приложения.
В качестве примера у нас есть компонента SideArea.mxml, содержащая компоненты ProductDetails и ShoppingCart. Как вы увидите в третьей части, ProductDetails требует выбранного продукта, чтобы отобразить его имя, описание, цену и картинку. Поскольку выбранный продукт сохраняется в ModelLocator в атрибуте selectedItem как экземпляр ProductVO, вы можете передать его в компоненту ProductDetails следующим образом:

<details:ProductDetails
        id="productDetailsComp"
        width="100%" height="325"
        currencyFormatter="{ ModelLocator.currencyFormatter }"
        selectedItem="{ ModelLocator.selectedItem }"
        addProduct="addProductToShoppingCart( event )" />

Выделенная линия показывает, что в классе ProductDeatils есть атрибут по имени selectedItem, которые является экземпляром ProductVO. Мы только что использовали связывание данных (механизм фигурных скобок), чтобы гарантировать обновление ProductDetails как только изменяется значение selectedItem в ModelLocator. Я расскажу об этом механизме больше в третьей части.

ЧТО ДАЛЬШЕ

В этой статье я определил проблемы, которые возникают в насыщенных интернет-приложениях, независимо от проблемной области приложения. Я буду использовать их для того чтобы подробно описать модель разработки с Caringorm.
В частности, я выдвинул первую проблему как: хранение состояния на клиенте. Я также отметил взаимозаменяемость понятий «состояние», «модель», «данные клиента». RIA приложения позволяют вам освободится от парадигмы запрос-ответ для HTML веб-приложений. Они позволяют вам хранить данные на клиенте также как при работе с приложением. Отсюда вам будет понятна определенная ответственность за это состояние клиента.
В веб-приложениях ответственность за целостность и согласованность данных возлагается на сервер – между слоем интеграции и бизнес уровнем. Однако вы понимаете, что поскольку объект модели все равно уже есть на клиенте, вы можете использовать возможности Flex для отображения данных между ActionScript и Java, и хранить соответствующие друг-другу объекты как на сервере так и на клиенте. И даже без этого, представляя состояние клиента типизированными объектами с семантическим смыслом – нежели бездумными массивами строк, чисел и булевых – сильно улучшает читаемость кода программы и облегчает его поддержку.
Поэтому я включил в Cairngorm паттерн Value Object (VO, объект-значение), также известный в мире программистов как паттерн DTO (Data Transfer Object).
Имея осмысленный способ представления объектной модели клиента, будет гарантией того, что программистам будет понятно где хранить состояние клиента, как разделить данные клиента между различными компонентами (которые сами по себе могут иметь различный способ отображения данных), и как обеспечить вид клиента самыми последними данными его состояния.
В следствие этого, я представил паттерн Model Locator, впервые появившийся в Cairngorm, как решение того что состояние сохраняется в единственном классе, который доступен в любой точке Flex-приложения. Синглтон Model Locator гарантирует отсутствие дубликатов состояния клиента, дает большим командам разработчиков логичное место для хранения состояния приложения как объетов-значений, одновременно с этим использую мощный механизм связывания данных во Flex, чтобы гарантировать уведомление Вида когда Контроллер меняет Модель.
В третьей части я сосредоточу вас на Виде. Перед тем как подробно изучать фреймворк Cairngorm, я расскажу более подробно о том, как использовать Flex Data Binding с состоянием хранимым в ModelLocator.

Разработка Flex RIA с помощью микроархитектуры Cairngorm. Часть 1: Введение в Cairngorm

Авг 23

Автор: Steven Webster
Часть 1: Введение в Cairngorm

Этот цикл статей, состоящий из шести частей, посвящен Cairngorm – микроархитектуре с открытым исходным кодом и адресован Flex разработчикам. В нем я хочу объяснить внутреннюю суть Cairngorm, подход к проектированию на основе Cairngorm, а также описать те проекты, реализация которых на основе Cairngorm может быть наиболее успешной.
На примере Cairngorm Магазина я объясню подход Adobe Consulting к анализу, оценке и разработке насыщенных интернет-приложений (RIA) на основе Cairngorm. Я также объясню идеи, заложенные в Cairngorm и мы вместе с вами создадим с нуля Интернет-магазин.
В последней статье, я продемонстрирую одну из многих выгод, которую получают разработчики, основывая свои RIA приложения на Cairngorm, с помощью добавления новой функции в готовый Интернет-магазин.
Конечно же, Cairngorm это не единственный способ построения насыщенных Интернет приложений. Однако Adobe Consulting помог многочисленным заказчикам и партнерам успешно реализовать масштабные проекты на Flex, основываясь на уже имеющихся разработках заказчиков и информации изложенной в этой статье.
Это введение раскроет вам проблемную область Cairngorm, начиная с мотивации разработки на Cairngorm и его концепций до проектирования своего собственного приложения на этой, признанной многими авторитетами, и поддерживаемой микроархитектуре.
Вместо ковыряния в коде, первая часть вводит вас в проблемную область архитектуры Cairngorm и дает понимание ее основ. Я расскажу о фреймворках и объясню разницу между программными фреймворками и архитектурными. Потом я произведу обзор паттернов проектирования и подведу вас к пониманию микроархитектуры. В заключении я вкратце расскажу о необходимости Cairngorm, его начало и историю.
В частях 2-6 мы с вами будем разрабатывать клиентскую часть приложения для розничной торговли с помощью Flex и Cairngorm на основе существующей J2EE серверной инфраструктуры.

ЧТО ТАКОЕ ФРЕЙМВОРК

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

Программные фреймворки

Flex есть яркий пример программного фреймворка. Действительно, продукт Flex 2.0 имеет все отличительные качества программного фреймоворка (который Adobe внутри называет «app model») в своей архитектуре. Фреймворк Flex 2.0 предоставляет большой набор классов с высокоуровневой функциональностью, которые разработчик может использовать в собственном проекте. Например, Flex 2.0 предоставляет API для работы с Collections Data (сложные типы данных, состоящие из других типов - прим. перев.), которые дают возможность управлять коллекциями данных. Разработчик может собирать необходимые данные в единый объект, который будет характеризовать его приложение. И конечно же Flex, как и любой другой программный фреймворк, предоставляет возможность управления историей, управление разметкой проекта, управление видом курсора, перехват исключений, возможность интернационализации, журналирования и тому подобное.
Если фреймворк предоставляет библиотеки высокоуровневых классов с большой степенью гибкости их использования, или когда фреймворк предоставляет сервис уровня приложения, и может использоваться в различных проектах – я называю такой фреймворк «программным».
Еще один хороший пример программного Фреймворка это фреймворк FAST, который Adobe Consulting довольно успешно использует в проектах своих клиентов и партнеров. Фреймворк FAST (см. статью Джона Беннетта «Быстрая разработка с помощью Flex Application Toolkit» http://www.adobe.com/devnet/flex/articles/fast_userguide.html) предоставляет программные службы для логирования и трассирования, расширенных пользовательскими данными библиотечных RPC классов в Flex 1.x.

Архитектурные Фреймворки

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

ИСПОЛЬЗОВАНИЕ ПАТТЕРНОВ ПРОЕКТИРОВАНИЯ

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

Привлекательность паттернов проектирования

А теперь внимание: когда разработчик сталкивается с паттерном проектирования, каталог реализаций этих паттернов оказывается очень мощным инструментом в решении поставленной инженерной проблемы. Еще чаще разработчик сталкивается с целым клубком задач и пытается изобрести новый паттерн. Здесь применима старая пословица «Если у тебя в руках молоток, то все кажется гвоздями». В этом случае вы услышите термин «перегрузка паттерна», что означает, что разработчик отказывается от разработанного класса и отказывается от сотрудничества, а пытается все впихнуть в Factory (Фабрика), Flyweight (Приспособленец), Observer (Наблюдатель), Decorator (Декоратор).
Однако правильное использование паттернов проектирования приносит большую выгоду. Паттерн проектирования не просто дает решение проблемы, а указывает направление реализации. Например, если вы видите в коде паттерн Singleton (Синглтон, Одиночка), вы сразу понимаете, что будет всего один экземпляр этого класса. Точно также, если вы видите паттерн Factory, вы понимаете, что существует некое множество других классов, созданием которых будет заниматься эта фабрика.
Поднимаясь по уровням технической архитектуры – с начального уровня детализации до высокоуровневой системы, скажем, вертолета – вы можете увидеть процесс разработки в виде повторяющегося процесса. Так же как Мандельброт (основатель фрактальной геометрии – прим. перев.), вы можете опознавать структуры более высокого порядка на основе описания более примитивных структур. Также и паттерны объединяются повторением, давая решение более высокого уровня для более сложных проблем.

Микроархитектура как объединение паттернов проектирования

Шаблон проектирования дает конкретное решение конкретной проблемы. Например: паттерн Синглтон дает нам уверенность в том, что будет всего один экземпляр этого класса. Набор паттернов, последовательно взаимодействующих друг с другом, дают решение более обширной задачи. Например: «Как мне получить жест пользователя и убедится что класс рабочего (паттерн Worker – прим. перев.) берет ответственность за исполнение»? Или: «Как мне сосредоточить бизнес логику, которая может использоваться в разных контекстах приложения на стороне клиента, даже если это вызывает различные службы на сервере»?
Когда вы начнете объединять шаблоны проектирования в системы более высокого порядка, пусть даже весьма примитивные по своему действию, вы будете называть это «микроархитектурой».
Теперь перейдем от абстрактных рассуждений о программных фреймворках, архитектурных фреймворках, паттернах проектирования и микроархитектурах к нашей теме. Когда Adobe Consulting говорит о фремворке Cairngorm, мы подразумеваем архитектурный фреймворк – отправную точку для технической архитектуры, достаточно абстрактную чтобы применять ее в различных проектах Flex RIA средней и большой сложности.
Более того, когда мы говорим о фреймворке Cairngorm, мы не имеем в виду какую-то монолитную архитектуру, которая ограничивает вашу свободу как разработчика ради решения технической проблемы. Скорее мы подразумеваем следующее:
- компактный программный фреймворк, который предусматривает некий целостный и последовательный подход к разработке Flex RIA
- использование небольшого количества необходимых паттернов, которые в процессе взаимодействия являются чем-то большим, нежели просто набором шаблонов
- микроархитектура для разработки RIA – отправная точка для технической архитектуры, предназначенной для решения задачи тем же успешным способом, который использовался неоднократно
И как вы увидите ниже, это все благодаря тому, что «мы стоим на плечах гигантов».

КРАТКАЯ ИСТОРИЯ CAIRNGORM

Софтверная консалтинговая компания iteration::two, которую я основал совместно с Алистером МакЛеодом, хорошо зарекомендовала себя в среде разработок программного обеспечения на основе J2EE и ее подходы к решению задач оказались подходящими для разработок RIA. Мы применили свои наработки для реализации RIA с помощью Flash, Flash Remoting и J2EE – в тот ранний период истории развития RIA, к которому мы так нежно и с ностальгией относимся, как C++ программисты относятся к программированию на ассемблере 6809.
Заимствуя часть шаблонов проектирования из библиотеки «Core J2EE Pattern Catalog» Sun Microsystems (http://java.sun.com/blueprints/corej2eepatterns/Patterns/index.html), мы первыми представили эти паттерны вниманию Flash сообщества в нашей книге «Reality J2EE: Architecting for Macromedia Flash MX» (Pearson Education, 2003). Совместно с выходом Flash MX 2004, мы описали эти паттерны в главе «ActionScript 2.0 Design Patterns for RIA Development» в «Macromedia Flash MX 2004 ActionScript 2.0 Dictionary» (Macromedia Press, 2003).
С развитием RIA технологии от дизайнерского подхода к разработке до декларативной программной модели Flex, большая часть идей применения этих паттернов осталась. Однако программная модель Flex дает нам более элегантный способ для воплощения этих паттернов. Более того, некоторые паттерны, имевшие большую ценность для Flash RIA разработчиков (например, паттерн ViewHelper), утратили свою значимость, и были нами заменены другими (например, ModelLocator), свойственными для Flex.
На форуме MAX 2004 мы заявили свое намерение о создании фреймворка Cairngorm, как проекта с открытым исходным кодом для Flex. Это решение нашло широкую поддержку в среде программистов.

ЧЕМУ ВАС УЧИТ CAIRNGORM

Микроархитектура Cairngorm предъявляет три основные требования, которые мы всего советуем нашим клиентам и партнерам как лучшую практику программирования:
- Обрабатывать пользовательские жесты на клиенте;
- Инкапсулировать бизнес логику и взаимодействие с сервером;
- Управлять состоянием приложения на клиенте и отображать это состояние в пользовательском интерфейсе.
Cairngorm реализует микроархитектуру (т.е. набор паттернов), которая последовательно решает эти повторяющиеся задачи проектирования.
После того, как вы прочтете этот цикл статей, вы научитесь следующему:
- Как паттерны Front Controller и Command реализуют микроархитектуру «Service to Worker», которая слушает пользовательские запросы и отвечает на них;
- Каким образом взаимодействуют паттерны Business Delegate и Service Locator, так что вы можете повторно использовать бизнес логику, а также инкапсулируют ее, позволяя разработчикам клиентской и серверной части легко связать взаимодействие приложений на сервере и клиенте, не зависимо от технической реализации серверных служб, будь то WebService, Enterprise JavaBeans, ColdFusion, или REST-архитектура использующая XML через HTTP;
- Как паттерн Value Object из J2EE сотрудничает с паттерном Model Locator, давая элегантное решение того, каким образом хранить состояние на клиенте, с насыщенным и анимированным пользовательским интерфейсом.

ТЕКУЩЕЕ СОСТОЯНИЕ CAIRNGORM

Текущая версия Cairngorm – 0.99 (на момент 2006 года; сейчас (2008) уже есть версия 2.2.1 для Flex 3 – прим. перев.). Он никогда не будет выпущен в версии 1.0, поскольку iteration::two была вовлечена в ряд поглощений, сначала со стороны Macromedia a потом и Adobe Systems. Более того, с выходом Flex 2.0, ActionScript 3.0, численных изменений в основе фреймворка Flex, множества новых потрясающих служб (включая Flex Data Services), и эволюцией самого Комитета Cairngorm (а сейчас он является частью основных консультантов и инженеров Adobe, и большим сообществом вокруг Adobe) – Adobe Consulting сфокусировалась назад выпуском комплексного релиза Cairngorm 2.0, который бы использовал всю мощь Flex 2.0.
Но, не смотря на это, ключевые концепции Cairngorm остаются теми же. Изменилась только реализация внутренних механизмов для использования новых свойств Flex 2.0, например, таких как Flex Data Services, Flex RPC Services. Для тех, кто уже работает с Flex 2.0 в Adobe Labs, мы регулярно выпускаем альфа релизы Cairngorm 2.0.
Замечание: в заключительной части этого цикла, я обсуждаю критерии принятия решения для использования Cairngorm. Мы ни в коем случае не убеждаем, кого бы то ни было в том, что Cairngorm это единственный способ построения RIA приложений. Мы даже не настаиваем на том, что это является лучшей практикой проектирования. И, конечно же, кто-либо может предлагать свои подходы, которые будут противоположны рекомендациям Cairngorm.
Все что мы требуем от вас, это сначала попытаться понять саму проблему, которую пытается решить Cairngorm, до того как начинать решать ее с помощью Cairngorm. Если вы только начинаете свое изучение Flex 2.0 для построения RIA приложений, я настоятельно рекомендую вам сначала освоить все то множество новых инструментов и техник этой технологии, прежде постижения сложных моментов связанных с Cairngorm.
Нельзя сказать, что Cairngorm очень сложный. Напротив, но вы должны уже уметь строить простые RIA приложения, которые не требуют каких-то специальных микроархитектур, для того чтобы вы смогли ощутить преимущества использования Cairngorm.
Прочтение вами частей 2-6 этого цикла позволит нам удостовериться, что и новички и опытные Flex программисты одинаково понимают проблемы создания RIA, которые решает Cairngorm. Мы хотим объяснить вам как можно доходчивее, и приведенные примеры кода элегантного решения с помощью Cairngorm, надеемся, помогут вам эфективно использовать Cairngorm для решения своих задач.

ЧТО ДАЛЬШЕ

Задачей этой статьи было ознакомить вас с микроархитектурой Cairngorm, объяснить двойственность понятия «фреймворк», зачем вам использовать фреймворк, истоки и будущее фреймворка Cairngorm.
Cairngorm это архитектурный фреймворк, предоставляющий готовую техническую архитектуру, на основе который возможно построение собственной, более сложной, проблемно-ориентированной архитектуры.
Основывая свое приложение на Cairngorm, вам не придется решать некоторые простые и фундаментальные задачи программирования. Например, как получить пользовательский жест, как получить ответ от сервера на запрос бизнес логики, и так чтоб это решение было элегантным и масштабируемым. Также вам не придется решать, как лучше управлять состоянием на клиенте в сложном и насыщенном приложении.
Я также немного рассказал об инженерной дисциплине программных шаблонов проектирования, и каким образом iteration::two заимствовало их из тех, что мы использовали как J2EE разработчики, которые также применимы для RIA. Обычно панорамный обзор программной архитектуры помогает понять разработчикам, какое взаимодействие паттернов заложено в его основу. Явление взаимодействия паттернов, обычно именуют микроархитектурой, каким и является фреймворк Cairngorm.
Когда я оказываю консалтинговые услуги, я часто говорю, что отличие теории от практики состоит в том, что теоретически, нет никакой разницы между теорией и практикой. В части 2, я отойду от рассуждений о шаблонах проектирования и микроархитектуре, а представлю Cairngorm с точки зрения четырех преимуществ, которые он предоставляет:
- хранение состояния на клиенте
- архитектура пользовательского интерфейса
- разработка только характерных черт приложения
- вызов серверных служб
Во второй части, будет практически показано, как мы используем Cairngorm в процессе создания приложения и какие проблемы он решает. Вы увидите целостный подход к созданию масштабируемого, сопровождаемого и безотказного насыщенного Интернет приложения с помощью Flex.

Нужен ли мне Cairngorm?

Авг 07

Несмотря на то, что мне хочется много сказать «за» и «против», в целом мой ответ НЕТ. Т.е. на вопрос «нужен ли мне Cairngorm, чтобы эффективно программировать на Flex?» можно утвердительно и смело ответить «Нет, не нужен». Вы действительно можете создавать эффективные, быстрые (как в разработке, так и в работе) приложения без использования Cairngorm.

Немного лирики

Уверен, что вы знаете, что такое Cairngorm, но, совершенства ради, хочу еще раз повторить всем известные факты. Да и повторение – мать учения.
Cairngorm – это фреймворк, реализующий паттерн MVC для Adobe Flex. При этом:
фреймворк – это программный каркас, паттерн – шаблон проектирования, MVC – паттерн Модель-Вид-Контроллер.
Те, кто уже напрограмировался в своей жизни, хорошо понимают термин фреймворк – каркас. Т.е. нечто, позволяющее на его основе строить свое собственное решение поставленной задачи. Но при этом фреймворки бывают разные по своей сути. На сколько мне известно терминов определяющих их виды не существует, возможно из-за ненадобности, но я бы хотел поделится своими мыслями по этому поводу, по тому как это может помочь скорейшему понимаю сути вопроса. И так, IMHO можно выделить как минимум два типа фреймворков: компонентные и концептуальные.
Отличным примером компонентного фреймворка может служить сам Adobe Flex. Flex – это большая библиотека классов, представляющих собой программные компоненты для визуального представления данных. При этом как их использовать, как их связывать между собой решаете полностью вы – разработчик. Вы решаете какие именно взять компоненты, какие нужно изменить под нужды вашей задачи, какие нужно будет написать заново, а так же вы определяете их взаимодействие – внутреннюю логику работы вашего приложения.
Примером концептуального фреймворка, конечно же, будет Cairngorm. Он не дает вам никаких новых компонентов для визуализации данных, он дает вам СТРУКТУРУ вашего приложения. Вы нанизываете на его каркас вашу бизнес логику, а он вам гарантирует что все заработает и будет работать как часики. В этом смысле Cairngorm ничего не дает вам, и даже более того – постоянно вас ограничивает.
Но сказать, что Cairngorm вообще ничего не дает, будет не справедливо. Он дает вам заранее известную структуру приложения (и не только известную вам, но и любому другому программисту, знакомому с Cairngorm), и заранее известную логику работы. Первое вам сильно облегчает жизнь, когда спустя некоторое время вам надо добавить новый функционал к вашей программе, или немного изменить поведение. Вы легко справитесь с этой задачей, поскольку вы постоянно работаете с Cairngorm и не просто помните, но знаете, что и где искать. Также не мало важно, что с этой задачей справиться и любой другой программист, хорошо знакомый с Cairngorm. Второе свойство вам несказанно поможет при отладке приложения, когда вы наткнулись на какой-либо сбой в программе, вы четко знаете к какому модулю предъявлять претензии, поскольку Cairngorm лишает вас возможности сделать что-либо двояким способом. Ну например, вы не можете выполнить запрос данных у сервера кроме как в команде (такой паттерн внутри Cairngorm).
Представьте теперь, что вы пришли на новую работу и в ваши обязанности входит поддержка старого приложения, которое написано на Cairngorm. Если вы хорошо знакомы с Cairngorm – это не составит особого труда. Или с другой стороны, вы – ведущий специалист, в ваши обязанности входит много чего и еще поддержка кучи старых проектов, но на Cairngorm. Все что вам нужно – это искать юных спецов со знанием Cairngorm. Короче все в шоколаде.

На счет вопроса «а зачем мне учить еще один фреймворк?»

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

Сумум бонум

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

А что если

Ясное дело, многих вновьподошедших мучит вопрос «а что лучше?». Ведь Cairngorm не единственный MVC паттерн для Flex. Есть же еще и PureMVC, который хорошо развивается как проект. Думаю, что каждый должен решить этот вопрос сам для себя, что лучше использовать. В конце концов, разница не большая, главное, что есть изначально определенная структура вашего приложения.
Лично мне известны две основные трудности Cairngorm: сложность и куча мелких файлов. Первое побеждается опытом, второе (опять же исходя из опыта) все же лучше чем пара очень больших файлов.
Насчет PureMVC, я знаю что у них есть оберточные функции для событий Flex. Полезность их сомнительна, хотя вред не доказан. Это связано с тем, что PureMVC изначально задумывался как MVC для любого языка. Но событийная модель встроена в сам Flash, поэтому строить свою систему событий кажется бессмысленным.
В Cairngorm тоже есть Cairngorm-события, но это не что иное, как правомерное использование событий Flash – когда программист создает свое собственное событие и упаковывает туда свои данные (payload), но распространением (propagation) его занимается сам Flash.
Это, конечно, тема большая, может быть, я напишу об этом отдельную заметку. Для меня основным фактором при выборе MVC фреймворка для Flex было то, что Cairngorm создавался специально для Flex.

Вот.