Проблема модульной веб-разработки — различия между версиями

Материал из YourcmcWiki
Перейти к: навигация, поиск
 
(не показано 6 промежуточных версий этого же участника)
Строка 15: Строка 15:
 
Пусть наше приложение состоит из различных модулей, которые реализованы реюзабельными, то есть фактически '''модули не знают состав веб-приложения, в котором исполняются''', и из некоторого «диспетчера», который знает, какие страницы из каких модулей «составляются». Модули производят некоторую обработку и возвращают некоторые данные, попадающие в шаблонизатор. Шаблонизатор же на основе этих данных с помощью простейших (''только'' простейших) операций генерирует страницу. В целом можно считать, что каждой странице соответствует один шаблон, опционально включающий в себя другие шаблоны.
 
Пусть наше приложение состоит из различных модулей, которые реализованы реюзабельными, то есть фактически '''модули не знают состав веб-приложения, в котором исполняются''', и из некоторого «диспетчера», который знает, какие страницы из каких модулей «составляются». Модули производят некоторую обработку и возвращают некоторые данные, попадающие в шаблонизатор. Шаблонизатор же на основе этих данных с помощью простейших (''только'' простейших) операций генерирует страницу. В целом можно считать, что каждой странице соответствует один шаблон, опционально включающий в себя другие шаблоны.
  
Итак, на входе мы имеем HTTP-запрос некоторой страницы. Не суть, каким образом описывается её адрес — пусть это будет просто строка. Запрос попадает в диспетчер, который на основании адреса выясняет, к какому типу страницы относится запрос, и вызывает обработчик конкретного типа страницы. В простейшем случае данный обработчик — просто функция диспетчера, делающая в определённой последовательности вызовы к различным модулям и составляющая результирующий набор информации для передачи в шаблонизатор. А способы разбора адресов страниц, в общем случае, могут кардинально различаться: например, можно рассмотреть две крайности — наивный способ, распознающий имя скрипта и параметры запроса (''/script.php?key=value&key=value&key=value''), или же ссылки, состояющие из названия материала и даты создания, «как завещал великий W3C» (''/2009-07-05-modular-web-development.html'').
+
Итак, на входе мы имеем HTTP-запрос некоторой страницы. Не суть, каким образом описывается её адрес — пусть это будет просто строка. Запрос попадает в диспетчер, который на основании адреса выясняет, к какому типу страницы относится запрос, и вызывает обработчик конкретного типа страницы. В простейшем случае данный обработчик — просто функция диспетчера, делающая в определённой последовательности вызовы к различным модулям и составляющая результирующий набор информации для передачи в шаблонизатор. А способы разбора адресов страниц, в общем случае, могут кардинально различаться: например, можно рассмотреть две крайности — наивный способ, распознающий имя скрипта и параметры запроса (''/script.php?key=value&key=value&key=value''), или же ссылки, состояющие из названия материала и даты создания, «как завещал великий W3C» (''/2009-07-05-modular-web-development.html'') в статье «[http://www.w3.org/Provider/Style/URI Hypertext Style: Cool URIs don’t change]».
  
 
Тем временем модулям в процессе обработки страницы может захотеться (и обычно хочется) сослаться на другую страницу — например, модуль, отображающий список тем форума, вероятно, может изъявить желание сформировать ссылки на отдельные темы, а также на профили пользователей и т. п. И вот здесь-то мы и сталкиваемся с проблемой! Модуль не знает, из каких страниц состоит приложение, и даже не знает, как генерируются ссылки на те или страницы — и поэтому не может сослаться на другую страницу. То есть, обработка получается «односторонная».
 
Тем временем модулям в процессе обработки страницы может захотеться (и обычно хочется) сослаться на другую страницу — например, модуль, отображающий список тем форума, вероятно, может изъявить желание сформировать ссылки на отдельные темы, а также на профили пользователей и т. п. И вот здесь-то мы и сталкиваемся с проблемой! Модуль не знает, из каких страниц состоит приложение, и даже не знает, как генерируются ссылки на те или страницы — и поэтому не может сослаться на другую страницу. То есть, обработка получается «односторонная».
Строка 45: Строка 45:
 
Вероятно, в Новой Платформе данный подход таки и будет опробован, но вполне возможно, что приложение в итоге получится «адовое», а вовсе не удобное.
 
Вероятно, в Новой Платформе данный подход таки и будет опробован, но вполне возможно, что приложение в итоге получится «адовое», а вовсе не удобное.
  
== Идеи ==
+
[[Категория:Sway]]
 
+
[[Категория:Архив]]
А теперь опишем идеи, лежащие в основе Новой Платформы.
+
 
+
=== Старые, проверенные ===
+
 
+
Во-первых, доказавшие свою рациональность идеи из старой платформы:
+
 
+
Приложение состоит из модулей. Модули, модули, и ничего, кроме модулей.
+
 
+
Для вывода кода страниц используется [[VMX-Template|шаблонизатор]] своей разработки. Причём, он специально сделан максимально простым, дабы избежать анти-паттернов разработки, к которым подталкивает [[TemplateToolkit|Template::Toolkit]], а именно, к перемещению 50 % логики в шаблоны. Примеры того, где так происходит — Bugzilla, Vsem.ru. Используется шаблонизатор, созданный когда-то по мотивам шаблонизатора phpBB2, о чём напоминает синтаксис. Умеет буквально 5 вещей: циклы, IF’ы, INCLUDE (включение другого шаблона), подстановки выражений в код, присваивания. Данные в шаблон передаются просто Perl-хешем.
+
 
+
Конфигурация приложения представляет собой вложенный хеш, хранимый просто в виде Perl-кода.
+
 
+
=== Противоположности старым, нерациональным ===
+
 
+
Во-вторых, идеи, созданные «от противного» по отношению к старой платформе:
+
 
+
Модули теперь создаются по требованию, а не все сразу при старте приложения. Поэтому и modules_allow и modules_deny в конфигурации больше нет.
+
 
+
Обработчик приложения делает фактически только eval {} для отлова исключений и подключение директорий @INC. В старой платформе обработчик делал Много Чего, в результате появлялись жёсткие завязки на различные моменты. Теперь же платформа от них свободна, и вся функциональность, имевшая жёсткие завязки, теперь разнесена по модулям, и её можно как использовать, так и '''не''' использовать:
+
 
+
# Нет виртхостов (хотя они реализуемы) — идея размещения нескольких сайтов в одной базе данных показала свою несостоятельность;
+
# Нет завязки на вызов метода render() у модулей, то есть методы обработки можно создавать любые по желанию;
+
# Нет конфигурации «последовательностей модулей», то есть вызовы разных модулей можно комбинировать в коде как душе угодно;
+
# Нет хеша имён таблиц, сопоставляющего «реальные» таблицы «виртуальным»;
+
# Нет завязки на регулярные выражения в разборе URI, а точнее, нет вообще никакой завязки в разборе URI, как и самого стандартного разбора URI, кроме «страница?параметры»;
+
# Нет завязки на обязательное соединение с БД;
+
 
+
Стандартные библиотечные модули больше не предоставляют собой «готовых страниц» — каждый модуль теперь являет собой просто библиотеку функций, а функции, выводившие что-то в шаблон, теперь просто возвращают хеш, который можно подставлять, куда душе угодно.
+
 
+
Страница в ответе формируется теперь не из конкатенации вывода нескольких шаблонов (что, кстати, влекло довольно кривой обходной манёвр в шаблонизаторе для организации передачи значений из шаблона в шаблон), а из вывода одного шаблона, который, возможно, пожелает включить в себя какие-либо другие.
+
 
+
=== Новые ===
+
 
+
И в-третьих, новые идеи:
+
 
+
Все обращения к БД из библиотечных модулей теперь оборачиваются в функции и живут в Sway::db::, а рядом с ними лежат SQL дампы нужных им таблиц; аналогично обращениям к БД делаются абстракции других операций — иногда хранения (например сессий в кэше), иногда преобразования (например текста сообщений форума).
+
 
+
[[Версионирование схем баз данных]] с возможность генерации скрипта проноса или отмены обновлений.
+
 
+
Поддержка [[Funq]].
+
 
+
EmLog — простой интерфейс, этакий RSS с PUSH’ем для блогов, в качестве транспорта использующий Email. Для организации распределённых блог-сетей.
+
 
+
== Некоторые вопросы ==
+
 
+
Далее опишем некоторые вопросы, возникавшие в процессе разработки.
+
 
+
=== Установка обработчика в Apache ===
+
 
+
Требования:
+
 
+
* Должна обеспечиваться возможность работы нескольких экземпляров одного приложения в одном экземпляре веб-сервера и одном интерпретаторе (без PerlOptions +Parent);
+
* Установка обработчика должна быть максимальной простой, без извращений с вызовом Perl кода Sway::WWW->Apache2(..);
+
* Должно быть возможно чтобы пакеты-обработчики были разные, а не один на _все_ приложения. То есть чтобы приложение могло сделать свой обработчик.
+
 
+
Решение:
+
 
+
<pre>
+
PerlFlags -I/home/www/vitaphoto/lib              # задаётся путь к библиотекам
+
PerlSetVar SwayConfig /etc/sway/vitaphoto.conf    # задаётся конфигурационный файл
+
PerlResponseHandler Sway::WWW                    # и обработчик
+
</pre>
+
 
+
А Sway::WWW уже передаст запрос в нужный экземпляр приложения, который не обязательно будет экземпляром класса Sway::WWW.
+
 
+
=== Модули и компоненты? ===
+
 
+
Нужно ли идеологически разделять модули на **модули** и **компоненты** ? (первое — просто предоставляют какие-то функции, второе — представляют собой конкретную страницу).
+
 
+
* '''За''': Меньше помойка.
+
* '''Против''': Компонент одновременно может быть и модулем.
+
* '''За''': Компонент типа attach из старой версии Sway представляет собой некоторую //конкретную// функциональность.
+
* '''Против''': С другой стороны, почему бы не представить эту функциональность в виде функции вывода чего-то в шаблон?
+
* '''За''': Вероятно, нужно будет писать меньше кода в случае использования готового компонента.
+
* '''Против: Как быть с изменением организации страницы? Например, с добавлением других шаблонов?'''
+
 
+
Последний пункт является решающим. В рамках выбранной идеологии «готовых компонентов» существовать просто не может.
+
 
+
=== Форумная функциональность? ===
+
 
+
Какая функциональность в форумном движке является необходимой? По убывания необходимости:
+
 
+
* Форумы, темы, сообщения, BBкоды;
+
* Прикреплённые темы, темы с обратным отображением, иерархические темы, темы с автоматическим индексом в верхнем сообщении;
+
* Email и RSS подписки на новые сообщения, слежение за темами.
+
* Профили пользователей (icq, телефон, email, настройки, на форуме GTSR — к примеру, машина), личные сообщения.
+
* Скрытые форумы, привязка сообщений к разделам сайта;
+

Текущая версия на 15:43, 20 июня 2016

В данный момент я (VitaliyFilippov 16:33, 12 июля 2009 (UTC)) создаю некую Новую Платформу для веб-разработки. Идея её, как всегда, частично идёт «от противного» — несмотря на то, что Платформа, Выросшая Из Vitaphoto, вполне жизнеспособна, юзабельна и даже содержит некоторые разумные идеи, она всё-таки неидеальна в использовании.

Цель

Цель — добиться максимальных:

  1. модульности
  2. возможности повторного использования кода
  3. простоты и гибкости в использовании.

Проблема

Модульная веб-разработка имеет одну очень неприятную идеологическую проблему.

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

Итак, на входе мы имеем HTTP-запрос некоторой страницы. Не суть, каким образом описывается её адрес — пусть это будет просто строка. Запрос попадает в диспетчер, который на основании адреса выясняет, к какому типу страницы относится запрос, и вызывает обработчик конкретного типа страницы. В простейшем случае данный обработчик — просто функция диспетчера, делающая в определённой последовательности вызовы к различным модулям и составляющая результирующий набор информации для передачи в шаблонизатор. А способы разбора адресов страниц, в общем случае, могут кардинально различаться: например, можно рассмотреть две крайности — наивный способ, распознающий имя скрипта и параметры запроса (/script.php?key=value&key=value&key=value), или же ссылки, состояющие из названия материала и даты создания, «как завещал великий W3C» (/2009-07-05-modular-web-development.html) в статье «Hypertext Style: Cool URIs don’t change».

Тем временем модулям в процессе обработки страницы может захотеться (и обычно хочется) сослаться на другую страницу — например, модуль, отображающий список тем форума, вероятно, может изъявить желание сформировать ссылки на отдельные темы, а также на профили пользователей и т. п. И вот здесь-то мы и сталкиваемся с проблемой! Модуль не знает, из каких страниц состоит приложение, и даже не знает, как генерируются ссылки на те или страницы — и поэтому не может сослаться на другую страницу. То есть, обработка получается «односторонная».

[svg]

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

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

Но и здесь мы снова встречаем проблемы — во-первых, код усложняется, так как помимо уровня диспетчера, составляющего сами ссылки, появляется ещё и необходимость указывать все параметры в шаблонах. А во-вторых, наступает время вспомнить о том, что действие, осуществляемое модулем, не обязательно приводит к генерации HTML-страницы — ещё, например, существует такая вещь, как перенаправление. Шаблоны при этом не используются, а ссылки требуются.

Как решать данную проблему? Можно, например, запретить модулям делать перенаправления между страницами сайта кроме тех случаев, когда тип целевой страницы по-настоящему фиксирован — например, если это всегда перенаправление на страницу обработчика OpenID, а вместо редиректа возвращать определённые данные, по котором диспетчер сможет определить нужное действие. Можно даже возложить формирование перенаправлений на шаблонизатор, введя функции перенаправления, для их вызова из шаблонов.

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

Вероятно, в Новой Платформе данный подход таки и будет опробован, но вполне возможно, что приложение в итоге получится «адовое», а вовсе не удобное.