Sway Solstice

Версия от 16:36, 23 августа 2009; VitaliyFilippov (обсуждение | вклад)

Sway Solstice — название Новой Платформы для веб-приложений, выросшей из Vitaphoto.

Do you want to try some new features? By joining the beta, you will get access to experimental features, at the risk of encountering bugs and issues.

Ок Нет, спасибо

Цель

Цель — добиться:

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

Идеи

Реализованные:

  • Модули, модули, модули, и ничего, кроме модулей. Никаких жёстких завязок на соединение с БД или разбор URL в самом Sway.
  • Конфигурация приложения представляет собой вложенный хеш, хранимый просто в виде Perl-кода. Система загрузки конфигурации позволяет объединять несколько файлов для поддержки стандартных конфигураций.
  • Каждый модуль в рамках одного веб-приложения создаётся в одном экземпляре. Модули создаются по требованию — при первом обращении. Межмодульное взаимодействие тривиально — $www->name через AUTOLOAD даёт экземпляр модуля name. Если модуль name захочет, он даже сможет переопределить то, что возвращается AUTOLOAD с его именем — это удобно для модулей, в которых только 1 функция.
  • Использование AutoImport, чтобы не писать в начале каждой функции длинные серии объявлений переменных $self->www->config и т. п.
  • Нет никаких RenderRec (в прошлой версии «запрос»), и уж конечно он не является точкой сбора огромного числа функциональности.
  • Нет виртхостов, нет пресловутого «config=?» — идея нескольких виртхостов в одной базе себя не оправдала.
  • Нет завязки на вызов метода render() у модулей, то есть методы обработки можно создавать любые по желанию.
  • Нет жёстких завязок на последовательности выполнения (например сначала этот модуль, потом этот, потом тот), а есть функции модулей — вызывай, как хочешь.
  • Нет хеша $t имён таблиц, сопоставляющего «реальные» таблицы «виртуальным», задуманного на случай сожительства двух приложений в одной БД ($config->{t}) — идея ущербная.
  • Нет завязки на регулярные выражения в разборе URI, а точнее, нет вообще никакой завязки в разборе URI, как и самого стандартного разбора URI, кроме «страница?параметры».
  • Обёрнутые в функции обращения к БД из модулей. Живут они в Sway::db::, а рядом с ними лежат SQL дампы нужных таблиц.
  • Новая версия Template|Шаблонизатора VMX::Template
    “Template|Шаблонизатора VMX::Template” не может быть использован как заголовок статьи на данном сайте.
     — упрощённая, аккуратная, почищенная, ещё более быстрая.
    Шаблонизатор специально сделан максимально простым, дабы избежать анти-паттернов разработки, к которым подталкивает Template::Toolkit, а именно, к перемещению 50 % логики приложения в шаблоны. Примеры того, где так происходит — Bugzilla, Vsem.ru.
    VMX-Template создан когда-то по мотивам шаблонизатора phpBB2, самого созданного по мотивам шаблонизатора phplib, о чём напоминает его синтаксис. Умеет он буквально 5 вещей: циклы, IF’ы, INCLUDE (включение другого шаблона), подстановки выражений в код, присваивания. Данные в шаблон передаются просто Perl-хешем, без промежуточных уровней вроде assign_vars() и assign_block_vars() (phpBB2), Template::Stash (TT). Код шаблонакомпилируется сначала в Perl-код и кэшируется на диске, а потом компилируется интерпретатором и кэшируется в памяти.
  • Поддержка Funq. Штука получилась интересная, хотя и не факт, что распространится.

Примеры:

  • Диспетчер URI, сопоставляющий ссылки страницам — отдельный модуль, который, увы, пишется отдельно, хотя есть стандартные.
  • БД и кэш — тоже отдельные модули. Хочешь — используй, хочешь — нет. Хочешь — пиши свои.
  • Например каждый метод авторизации — функция модуля auth.
  • Например, нет функции вывода в шаблон треда комментариев, а есть функция, возвращающая его в виде хеша, передавай в шаблон, как хочешь.

Планируемые:

Обработчик приложения делает фактически только eval {} для отлова исключений и подключение директорий @INC. В старой платформе обработчик делал Много Чего, в результате появлялись жёсткие завязки на различные моменты. Теперь же платформа от них свободна, и вся функциональность, имевшая жёсткие завязки, теперь разнесена по модулям, и её можно как использовать, так и не использовать:

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

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

Некоторые раздумья

Вопросы, возникавшие в процессе разработки.

Установка обработчика в Apache

Требования:

  • Должна обеспечиваться возможность работы нескольких экземпляров одного приложения в одном экземпляре веб-сервера и одном интерпретаторе (без PerlOptions +Parent);
  • Установка обработчика должна быть максимальной простой, без извращений с вызовом Perl кода Sway::WWW->Apache2(..);
  • Должно быть возможно чтобы пакеты-обработчики были разные, а не один на _все_ приложения. То есть чтобы приложение могло сделать свой обработчик.

Решение:

PerlFlags -I/home/www/vitaphoto/lib               # задаётся путь к библиотекам
PerlSetVar SwayConfig /etc/sway/vitaphoto.conf    # задаётся конфигурационный файл
PerlResponseHandler Sway::WWW                     # и обработчик

А Sway::WWW уже передаст запрос в нужный экземпляр приложения, который не обязательно будет экземпляром класса Sway::WWW.

Модули и компоненты?

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

  • За: Меньше помойка.
  • Против: Компонент одновременно может быть и модулем.
  • За: Компонент типа attach из старой версии Sway представляет собой некоторую //конкретную// функциональность.
  • Против: С другой стороны, почему бы не представить эту функциональность в виде функции вывода чего-то в шаблон?
  • За: Вероятно, нужно будет писать меньше кода в случае использования готового компонента.
  • Против: Как быть с изменением организации страницы? Например, с добавлением других шаблонов?

Последний пункт является решающим. В рамках выбранной идеологии «готовых компонентов» существовать просто не может.

Форумная функциональность?

Какая функциональность в форумном движке является необходимой? По убывания необходимости:

  • Форумы, темы, сообщения, BBкоды;
  • Прикреплённые темы, темы с обратным отображением, иерархические темы, темы с автоматическим индексом в верхнем сообщении;
  • Email и RSS подписки на новые сообщения, слежение за темами.
  • Профили пользователей (icq, телефон, email, настройки, на форуме GTSR — к примеру, машина), личные сообщения.
  • Скрытые форумы, привязка сообщений к разделам сайта;

А лучше — никакая, а просто взять готовый форумный движок.

Как быть с генерацией и разбором URI?

Общая идеология веб-приложения, на самом деле, весьма нетривиальная штука.

Должна присутствовать возможность реализации различных диспетчеров URI, то есть разных методов разбора. Например, наиболее простой — /компонент/?key=value&key=value. Другой пример — когда у каждого документа есть фиксированный URI, вообще никак не связанный с его ID и т. п., а связанный только с названием и моментом создания, «как завещал великий W3C».

А разные методы разбора провоцируют разные методы генерации.

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

А кроме того, все модули создаются по требованию, поэтому «заранее» выставлять настройки своих стандартных URI не могут.

На входе мы имеем некоторый **адрес страницы**, то есть практически набор неких параметров.

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

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

Фактически должно существовать некое «обратное преобразование» для каждого компонента, позволяющее компоненту получить тот адрес, по которому появится нужная функциональность. КАК???

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

Можно делать как и раньше — дёргать из кода функцию uri(«ТИП», {параметры}). Но что, если в дальнейшем понадобится использовать разные типы в вызовах одного компонента? Тоже проблема.

Однако ближе к «телу» лежит всё-таки идея генерации URI из шаблонов, так как именно шаблоны действительно ЗНАЮТ, какой тип страницы собой представляют.

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

Но тут возникает новая проблема! Что делать с различными редиректами из кода? Ссылки нужны, а шаблонов-то нет — ЧТО ДЕЛАТЬ???

С редиректами из кода ещё можно побороться — от них можно отказаться :) оставив только для специальных случаев, вроде редиректов на безопасные УРЛы и т. п. То есть в случае «чего» компонент чтобы не редирект давал, а некие данные в хеше результата возвращал. Это, в целом, даже идеологически неплохо.

И ещё один кейс — это к примеру JSON-ответы: «нормальных» шаблонов нет, URI нужны. ЧТО ДЕЛАТЬ??? Можно конечно на этот случай как раз оставить дёрганье фиксированного uri(ЧЕГО_ТО).

Как быть с хешем переименований таблиц $t ?

Вероятно, его нужно ликвидировать, так как в большинстве случаев он бессмыслен…

С другой стороны, а если произойдёт та ситуация, ради которой он задуман — допустим будем ставиться в одну базу с чем-нибудь другим и будут конфликты имён таблиц?

Может быть, использовать Funq?

Кстати, для полной абстракции от БД нужно все вызовы SQL оборачивать в функции.

    • Вывод: хеш $t ликвидировать в задницу, в библиотечных модулях все вызовы к БД оборачивать в функции**