Pull to refresh

«Совершенный Ajax» – новый подход к построению настоящих клиент-серверных web-приложений

Reading time 11 min
Views 10K
«Совершенный Ajax» — новый подход к построению web-приложений, при котором web-сервер не генерирует ни строчки HTML-кода и взаимодействует с внешним миром только посредством web-служб; а клиентский интерфейс реализуется только на основе клиентских HTML, CSS, JavaScript.

Статья состоит из двух частей. В первой части — более живой и провокационной я постараюсь заинтересовать проблемой, рассказать о технологии «Совершенный Ajax» и показать ее применение на примере нашего проекта «Система Интерактивного Тестирования Знаний “Синтез”» (который имеет ряд интересных особенностей, таких, как использование серверного JavaScript на платформе Mozilla Rhino, прототипно-ориентированная ORM и поддержка SPARQL — языка запросов к Semantic Web).

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

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



Попробуйте угадать: к какой архитектуре относятся web-приложения?

К клиент-серверной говорите? Я ожидал, что Вы так ответите :-)

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

  • Клиент — отвечает за взаимодействие с пользователем [1].

Реализация бизнес-логики на сервере и взаимодействие с пользователем на клиенте четко разделены.

Преимущества клиент-серверной архитектуры очевидны; мы их все знаем:
  1. Бизнес-логика не смешивается с пользовательским интерфейсом.
  2. Можно реализовать несколько клиентов с разными пользовательскими интерфейсами: интерфейс командной строки, оконный Windows-интерфейс, Flash, web-интерфейс, мобильный интерфейс и т.д.
  3. Клиентский компьютер не требователен к ресурсам;
  4. И т.д.


Но, относятся ли web-приложения к клиент-серверной архитектуре? Web-сервер

Действительно, в web-приложениях есть сервер, отвечающий за бизнес логику приложения.

Но! За реализацию интерфейса отвечает не клиент, а тоже сервер. На сервере происходит обработка клиентской формы. Сервер генерирует HTML-код пользовательского интерфейса.

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

Замечание:

Здесь, правда, есть одна тонкость. Следует различать два понятия: web-приложения и систему «браузер — web-сервер». Web-приложения работают поверх браузера и web-сервера, так же как Java-приложения работают внутри JVM, приложения на .Net работают внутри .Net Framework, а протокол HTTP работает поверх TCP/IP.

Система «браузер — web-сервер» действительно имеет клиент-серверную архитектуру: web-сервер принимает и обрабатывает запросы, а браузер визуализирует результат.

Однако, здесь мы говорим не о системе «браузер — web-сервер», а о работающих внутри нее web-приложениях.


Вряд ли такой подход можно назвать полноценной клиент-серверной архитектурой. Он имеет много недостатков:
  1. Смешивание бизнес-логики и пользовательского интерфейса;
  2. Сложно реализовать несколько пользовательских интерфейсов;
  3. Сторонни программы не могут обращаться к серверу (если не написан специальный api);
  4. Большая часть нагрузки по обработке интерфейса ложится на сервер.
  5. И т.д.


Мейнфрейм Впрочем, мы знаем в истории пример подобной архитектуры. В 70-годы были распространены мейнфреймы. Мейнфрейм — такой огромный железный сундук (сервер), к которому подключались рабочие станции (клиенты). Причем, рабочая станция представляла собой просто монитор с клавиатурой. И любые действия клиента на рабочей станции обрабатывалось на сервере, порой даже такие как обработка нажатия на клавишу и обрисовка экрана [2]. Ну, мы знаем, насколько популярны мейнфреймы сегодня…

Конечно, в современных web-приложениях часть интерфейсной логики реализуется на клиенте с помощью JavaScript. Ajax Часть данных загружается с помощью Ajax и визуализируется именно на клиенте.

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

Так вот, я предлагаю подход «Совершенный Ajax», который призывает развить идею Ajax до логического конца и полностью отказаться от использования сервера для реализации пользовательского интерфейса web-приложений.

Подход «Совершенный Ajax» построен на следующих принципах:
  • Web-сервер:
    • Реализует только бизнес-логику приложения и не генерирует ни строчки HTML-кода;

    • Взаимодействует с клиентом посредством web-служб: принимает текстовые запросы и возвращает только данные;
  • Пользовательский web-интерфейс:
    • Реализуется только на основе клиентских HTML, CSS, JavaScript.

    • Взаимодействует с web-сервером посредством объектно-ориентированной библиотеки-обертки над web службами;

    • Используется исключительно семантическая верстка.

      Элементы управления (вкладки, меню, деревья) описываются высокоуровневыми HTML-конструкциями.

    • Библиотека контролов придает HTML-конструкциям внешний вид и функциональность соответствующего элемента управления, просто навешивая нужные стили и обработчики событий, не меняя при этом HTML-код элемента.
  • Любой сторонний разработчик может реализовать свою версию пользовательского интерфейса, причем не только на HTML, но и на Flash, Windows, Mac и т.д.


«Совершенный Ajax» в нашем проекте


Опишу эту архитектуру на примере нашего проекта «Система Интерактивного Тестирования Знаний “Синтез”».

Сервер


В концепции «Севершенный Ajax» сервер должен удовлетворять одному-единственному условию: не генерировать ни строчки HTML-кода и осуществлять связь с внешним миром посредством web-служб. Во всем остальном его реализация ничем не ограничена.

Здесь я опишу структуру сервера в нашем проекте, т.к. она имеет ряд интересных особенностей: использование серверного JavaScript на платформе Mozilla Rhino, прототипно-ориентированная ORM и возможность использования SPARQL — языка запросов к Semantic Web.

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


Архитектура сервера
  • СУБД — хранит данные.

  • Прототипное объектно-ориентированное ядро бизнес-логики — реализует объект- ную модель и функциональность приложения.

  • ORM — связывает базу данных с прототипным ядром бизнес логики.

  • Web-сервер — открывает функции программы для внешнего мира посредством web-служб.

СУБД
СУБД
  • Все данные хранятся в обычной реляционной базе данных.

  • Причем, используется только «чистый» SQL, без надстроек конкретных СУБД: хранимых процедур и т.д. Это делает базу данных независимой от той или иной СУБД.

  • Связь базы данных с объектным ядром бизнес-логики приложения осуществляется через прототипно-ориентированную ORM.

Объектное ядро бизнес-логики
Ядро бизнес-логики
  • Вся объектная модель приложения и его бизнес-логика заключена в прототипно-ориентированном ядре.

  • Ядро написано на серверном JavaScript, на базе платформы Mozilla Rhino.

  • Несмотря на недооцененность многими разработчиками, JavaScript — удивительно мощный, гибкий и красивый язык, превосходящий в ряде случаев по гибкости и функциональным возможностям таких монстров, как Java или C#. И мы используем по максимуму его возможности, такие как прототипно-ориентированное ООП, объекты-как-хеши, функциональное программирование, замыкания и т.д.

  • Также, прототипно-ориентированная парадигма JavaScript позволяет гораздо более гибко работать с базой данных через ORM.

  • Mozilla Rhino компилирует JavaScript в байт-код JVM.

    Благодаря этому, наш серверный JavaScript не становится «вещью в себе», а может использовать все обилие наработок мира Java.

  • Вообще, серверный JavaScript на основе Mozilla Rhino — это отдельная большая тема, и я постараюсь написать ряд статей по этому вопросу.

Прототипно-ориентированная ORM
ORM
  • ORM служит для связи реляционной БД с прототипным объектно-ориентированным ядром бизнес-логики.

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

  • Использование ORM для прототипно-ориентированных языков — это мега круто!

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

  • Прототипная парадигма ORM позволяет удивительно гибко работать с данными.

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

    В частности, это дает возможность обращаться к БД на SPARQL — языке запросов Semantic Web.

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

  • Прототипно-ориентированная ORM — также отдельная большая тема, и я постараюсь посвятить ей ряд статей.

Web-сервер
Web-сервер
  • Web-сервер выполняет только одну-единственную задачу — связывает ядро бизнес-логики с внешним миром посредством web-служб.

  • При этом он не генерирует ни строчки HTML-кода.

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

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


Клиент


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

Однако, оно всегда имеет в комплекте «родной» web-интерфейс.

Здесь я опишу его структуру.


Архитектура клиента
  • Интерфейсное ядро — объектно-ориентированная библиотека, реализующая всю клиентскую логику и управляющая интерфейсом клиента.

  • Библиотека-обертка — объектно-ориентированная обертка над web-службами, осуществляющая связь клиентского интерфейса с сервером.

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

  • Библиотека контролов — придает HTML-конструкциям внешний вид и функциональность соответствующего контрола.

Интерфейсное ядро

Интерфейсное ядро Интерфейсное ядро — объектно-ориентированная JavaScript-библиотека, управляющая всем клиентским web-интерфейсом:
  • Реализует интерфейсную логику приложения.

  • Взаимодействует с объектной моделью приложения на web-сервере через библиотеку-обертку.

  • Взаимодействует с элементами управления (контролами) посредством библиотеки контролов.

  • Осуществляет встраивание клиентского интерфейса нашего программы в web-интерфейсы других приложений.

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

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

  • Управляет стилями интерфейса.

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

  • Управляет локализацией интерфейса.

Библиотека обертка
Объектно-ориентированная библиотека-обертка над web-службами
  • Клиентская реализация (как родной web-интрфейс, так и интерфейсы сторонних производителей) взаимодействует с объектной моделью и бизнес-логикой на сервере посредством web-служб.

  • Однако, работать с web-службами напрямую неудобно: это лишает нас объектного подхода и понижает упровень абстракции.

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

    Пример:

    Нам надо получить объект Морковкин Вася и сделать его учеником 3 «А» класса.

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

    //Получаем с сервера объект Морковкин Вася<br> var objStudent1 = Sintez.getStudent ("this.firstName = 'Вася' and this.secondName = 'Морковкин'");<br> //Получаем объект 3 "А" класс<br> var objClass1  = Sintez.getClass ("this.getClassNuber() = 3 and this.liter = 'А'");<br> //Делаем Васю учеником этого класса<br> objClass1.addStudent (objStudent1);<br>

    А уже библиотека-обертка кодирует вызов методов объектов как команды web-служб, пакует объекты перед отправкой их на сервер и распаковывает после получения.

  • Для того, чтобы свою версию интерфейса мог реализовать любой сторонний производитель на любой платформе, мы выпускаем библиотеки-обертки не только для web-интерфейса на JavaScript, но и для других распространенных технологий: .Net, Java, Delphi, Flash и др.

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

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

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

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

Семантическая верстка
Семантическая верстка
  • Весь пользовательский интерфейс реализуется на основе чистых xHTML, CSS и JS.

    Несмотря на сильную недооцененность разработчиками, xHTML/CSS/JS является очень мощной и гибкой технологией построения интерфейсов.

  • Использование семантической верстки является высокоуровневым программированием; а несемантическая мешанина тегов – низкоуровневым.

    И если при старом подходе, когда HTML-код генерировался сервером, мы, несмотря на все уродство, могли себе позволить низкоуровневый несемантический подход;

    то при подходе «Совершенный Ajax» мы просто обязаны использовать высокоуровневую семантическую верстку!

  • Элементы управления (деревья, меню, вкладки и т.д.) описываются обычными высокоуровневыми HTML-конструкциями.

    Например, меню или дерево описывается как обычный список, а вкладки, как набор div’ов.

  • А уже библиотека контролов делает из этих HTML конструкций элементы управления.

Библиотека контролов
Библиотека контролов
  • Библиотека контролов придает HTML-конструкциям внешний вид и функциональность соответствующего элемента управления.

  • При этом HTML-код элемента не меняется, а на него просто навешивая нужные стили и обработчики событий.
  • Для превращения HTML-конструкции в элемент управления, надо просто вызвать соответствующий JS-объект библиотеки контролов.

    Работа с контролом происходит через вызов методов объекта.

    Поскольку контролы не меняют код своей HTML-конструкции, элемент управления может быть «на лету» превращен в другой элемент простой заменой JS и CSS-классов.

    Пример:

    Дерево описывается не мешаниной тегов, а единой высокоуровневой HTML-кострукцией: вложенным списком.

    <ul id = "ulTree1"><br>  <li><br>   Элемент 1<br>   <ul><br>    <li><br>     Элемент 1-1<br>    </li><br>    <li><br>     Элемент 1-2<br>    </li><br>   </ul><br>  </li><br>  <li><br>   <!--...--><br>  </li><br> </ul><br>

    Для придания списку внешего вида и функциональности дерева, создается JS-объект Controls.Tree. Работа с деревом происходит через вызовы методов объекта.

    //Создаем дерево<br> var objTree1 = new Controls.Tree ($("ulTree1"));<br> //Выделяем все узлы дерева, вызывая метод selectAll () созданного объекта<br> objTree1.selectAll ();<br>

    В любой момент мы можем превратить дерево в меню, просто создав объект Controls.Menu:

    //Превращаем дерево в меню<br> var objMenu1 = new Controls.Menu ($("ulTree1"));<br>


  • В скором времени я собираюсь опубликовать статью на эту тему: «HTML — самый недооцененный язык построения интерфейсов в мире (СНЯПИМ)».

Подробности технической реализации подхода «Совершенный Ajax» — во второй части.


Примечания

  1. Речь идет о клиент-серверных приложениях с конечным пользователем. В клиент-серверных приложениях вроде «клиент — сервер базы данных», пользовательский интерфейс, разумеется, отсутствует.
  2. Позже, у мейнфреймов появились так называемые «умные клиенты», которые обладали собственным процессором и памятью, а наиболее продвинутые могли даже проверить форму перед отпракой на сервер. Это очень напоминает нынешнюю робкую попытку передать часть интерфейсной логики web-приложения на клиент с помощью Ajax.

См. также


На Хабре есть статьи со схожими идеями, например «Ajax-машина» и недавняя «Hivext: Платформа веб сервисов».
Tags:
Hubs:
+80
Comments 152
Comments Comments 152

Articles