Boroda aka Hamster (fantaseour) wrote,
Boroda aka Hamster
fantaseour

Открытая архитектура фреймворка

Разговоры о разных фреймворках, изобретателях велосипеда идут своим чередом, а новые фреймворки продолжают расти, как грибы, что в общем само по себе неплохо.

Навеянное выдиранием автолоада и миграций из симфони и разглядыванием Zend FW на предмет выдирания раутера и ezComponents на предмет кэширования, почты, картинок идр.

Причина господства принципа "своя рубашка ближе к телу", в результате которого каждый пишет фреймворк для себя сам в том, что фреймворк диктует взгляд автора на разработку программистам, которые будут этим фреймворком пользоваться. А это все равно, как если какой-то Вася будет рассказывать, как мне в компутера папки располагать и какие программы ставить. Я Васю-то послушаю, но сделаю все-равно по-своему.

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

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

Рассмотрим компоненты современного MVC фреймворка. Исключим пока из рассмотрения i18n и i10n.

  • Фронт-контроллер -- главный диспетчер приложения, его нет смысла брать откуда-то -- по-любому придется писать свой.
  • Цепочка входных и выходных фильтров. Входной фильтр проверяет какие-то условия, добавляет переменные в основной пул переменных приложения, может давать какие-то команды БД, например set names для MySQL, может решить, что произошла ошибка и переопределить обрабатывающий модуль и действие. Выходной фильтр, обычно берет результат работы представления и добавляет некоторый контент. Например макет может быть реализован в виде одного или нескольких выходных фильтров.
  • Раутер -- библиотека, которая анализирует URL и на выходе выдает какой класс (модуль) и каким методом должен обработать данное событие и набор параметров.
  • Обратный раутер, модуль который формирует URL, на основе названия модуля, метода и параметров. Раутеров может быть несколько, например отдельно для фронтенда и для бэкэнда.
  • Класс базового контроллера, который умеет вызвать представление и передать туда параметры, или выдать редирект и т.д.
  • DBAL -- абстракция от конкретных методов работы с БД. На сегодняшний день можно договориться использовать PDO
  • ORM -- набор классов для организации работы с объектами.
  • Генератор классов для ORM и шаблонов на основе схемы данных
  • Шаблонный движок для уровня представления. -- Тут тоже каждый любит писать под себя, тем более, что PHP сам по себе неплохой шаблонный движок.
Вспомогательные инструменты:
  • установщик
  • инструмент типа make -- скрипт, проигрывающий сценарий. Удобен для развертывания, сброса кэша, запуска генератора и т.д.
  • инструмент для миграций
  • инструмент для модульных и функциональных тестов
  • инструмент для установки пакетов

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

Во-первых нужно частично отказаться от принципа DRY (Don't repeat yourself) -- из-за него не хочется держать в одной системе рядом два шаблонизатора, ORM, DBAL, хочется чтобы все "по уму" т.е . унифицировано.

Конечно полный набор зенд или ez довольно увесист, но его можно подрезать до приемлемого состояния. Если отказаться от этого момента, то интегрировать будет значительно легче. Главное подходить с чувством меры и не дать превратиться своей системе в лоскутное одеяло.

Во-вторых нужно иметь всего несколько договоренностей.

1. Основное приложение должно давать легкий доступ к основным переменным конфигурации. Например так:

$context=generalApplication::getContext();
$dbName=$context->getDBName();

2. Использовать PDO как DBAL -- при желании можно этого не делать, и разрешить встраиваемым модулям использовать тот DBAL, который им нравится, забирая из основного приложения параметры подключения к БД. Если использовать PDO, то главное приложение должно давать доступ к объекту БД через контекст или диспетчер соединений.

3. Подключаемое приложение должно иметь четко задокументированное разделение:

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

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

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

г) Должны быть документированы зависимости от библиотек 3-х сторон.

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

Пусть я хочу написать независимый модуль для построения файлов шаблона и классов ORM. Назовем его Carpenter (плотник).

Функциональность модуля:

  1. читать схему данных через класс-драйвер, т.к. схемы в разных фреймворках разные
  2. иметь для каждого файла результата класс, который получит данные от анализатора схемы и воспользовавшись одним или несколькими файлами шаблона выдаст результат. Положит этот результат в соответствии с конфигурацией в нужную папку
  3. иметь класс, который внесет в БД изменения (создаст таблицу или поменяет),
  4. класс, который допишет в текущую миграцию изменения

В результате у нас получится следующее расположение файлов (template-engine -- тот шаблонный движок, которым пользуется наш модуль):

/config/carpenter
                directories_path.inc.php
                template_const.inc.php

/vendors/template-engine
/vendors/carpenter/core
                ......................
/vendors/carpenter/bridge
               config.inc.php (файл, содержащий параметры
                               подключения к главному приложению)
               /templates
               /scheme_parser
               /generation_tasks

Такие модули писать труднее, чем писать под определенную структуру, плюс имеется некоторая лишняя функциональность ради гибкости.

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

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

По такому пути пошли EZ, когда выделили ezComponents, похожим образом устроен Zend Framework. Вот только лучше было бы раздробить оба фреймворка на отдельные части, но впрочем, они и так неплохо вычленяются.

Tags: development
Subscribe

  • Так. Чуть не бросил дневник :)

    Ну вот, хотел не бросать и опять сюда не пишу :( Потому, что в будние дни сил нет писать, а в выходные вот то у меня ДР, то у пасынка. То просто…

  • 46

    Дня рожденья пост. Ну ничего, мы еще позажигаем :)

  • Завтра в офис

    Завтра выхожу на работу в офис. Будет, как первый день, поскольку у меня места рабочего нет пока -- ноутбук есть, а места нет. Выходящие либо сдают…

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 4 comments