Sway Solstice

Материал из YourcmcWiki
Версия от 16:36, 23 августа 2009; VitaliyFilippov (обсуждение | вклад) (Новая: Sway Solstice - название Новой Платформы для веб-приложений, выросшей из Vitaphoto. == Цель == Цель — добиться: ...)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

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

Цель

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

  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 ликвидировать в задницу, в библиотечных модулях все вызовы к БД оборачивать в функции**