Построение Модульной Системы, Ориентированной На Плагины

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

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

С одной стороны, задача не представляет проблемы; достаточно предоставить разработчикам богатый API для работы с системой.

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

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



Ядро системы

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



Построение модульной системы, ориентированной на плагины

Ядро — это набор основных функций, которые помогают облегчить поток информации внутри системы.

Ядро координирует работу всей системы в целом.

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

Модули подключаются к ядру.

Модуль — это некий набор функций/методов, часть из которых являются публичными, т.е.

доступны пользователю для выполнения.

Не путать с общедоступными методами объектов.

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

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



Обработчики

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

Реализация нового модуля потребует проектирования и реализации с нуля.

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

Но система не стоит на месте, и по мере развития модуля совместимость будет серьёзно страдать.

Патчи могут просто перестать работать.

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

Здесь на помощь приходят процессоры.

Обработчик — это функция, которой можно передать управление во время выполнения кода.

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



Построение модульной системы, ориентированной на плагины

Это абстрактная диаграмма, а не код самой функции.

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

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

Обработчик onAfter будет выполнено после того, как тело нашей функции выполнит некоторую полезную работу.

Здесь я также добавил специальный блок под названием шаблонЭто .

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

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

Тело функции выберет необходимые данные и отправит их в систему шаблонов.

На самом деле все будет немного сложнее.



Построение модульной системы, ориентированной на плагины

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

Инструкции будут инструкциями по выполнению модуля новостей, а данные будут идентификатором новостей.

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

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

Что нам дают процессоры?

Позвольте мне привести вам простой пример.

Система может отображать список пользователей.

Вы создали модуль, в котором есть еще один список пользователей, которые являются VIP-посетителями вашей системы.

Вы хотели не только вывести список пользователей, но и показать, кто из них тоже VIP-посетитель.

Поэтому вам следует добавить onAfter -обработчик функции, формирующей список пользователей.

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

Вам просто нужно назначить VIP-знак людям из этого списка.

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

Теперь при вызове списка пользователей будет красоваться ваш новый шаблон.

На бумаге это выглядит красиво, но не всегда красиво реализуется.

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

Кто знает, что делать? Инициализировать все модули одновременно? Не очень эффективное решение.

Давайте немного изменим процедуру.



Построение модульной системы, ориентированной на плагины

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

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

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

Публичная функция просто вырождается в тело функции, т.е.

внутри нее нет другого кода, кроме работы с данными.

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



Построение модульной системы, ориентированной на плагины

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

Например, после выполнения а.

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

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

б1 , что добавит к данные1 также данные2 , но эта функция не может изменить шаблон.

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

И так до бесконечности.

Это уже намного лучше и гибче.

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

Приятного программирования! УПД.

Работайте над ошибками.

Теги: #модуль #ядро #схема #плагин #архитектура системы #Ненормальное программирование

Вместе с данным постом часто просматривают: