Методы проектирования модульных систем
09.10.2010 технологии тормозные идеи
Последнее время много думаю про модульность в будущем Daos 2.0, и в идеале я хочу, чтобы была возможность любому программисту написать любой модуль, который добавлял бы функциональность в любом месте системы. Под любым программистом я подразумеваю и себя в том числе, основного разработчика системы. Если указанные выше условия выполнимы, тогда расширение системы становится очень простой задачей — написал дополнительный модуль, вот тебе и новый функционал.
Предварительно у меня вырисовывается такой алгоритм: в коде, который взаимодействует с пользователем, изначально вызывается метод проверки наличия модулей. Если модули есть, метод вставляет их код в нужные места основной ветки. Вот это и есть самое сложное и, откровенно говоря, сомнительное решение. Как вставляет и как выбирает это место? Мне пока видится это так: в коде модуля определяется, перед (или после) какого места в основном коде этот модуль должен вставляться. А потом уже обработчик-проверяльщик берёт основной код, вставляет модули? и после всё это дело выполняет (через eval, например).
Есть в этом что-то нехорошее, но зато подобный подход даёт широчайшую свободу — модулями можно сделать действительно вообще любой функционал. Но за всё нужно платить. Основные возможные проблемы: несовместимость модулей, проблема определения последовательности включения модулей (если несколько модулей претендуют на одно место), превращение проекта в кашу, если модулей много и написаны они разными людьми, которые плевать хотели на любые соглашения.
Позже написал про альтернативу. Остальные, надеюсь, интересные и полезные мнения выскажут комментаторы.
Альтернативный подход
Так делают чаще всего в CMS и других системах. Модули (ещё их часто называют плагинами) могут быть встроены только в чётко определённых местах и сконструированы в 100% соответствии с определёнными API. Например, так могли быть организованы модули оплаты в интернет-магазине. Под каждый биллинг добавляется свой модуль, который реализует общий интерфейс и детали реализации конкретного биллинга.
Но свободы при этом гораздо меньше, не всё сделаешь таким способом.
Ну, что думаете? Как правильно?
Комментирование этой статьи закрыто.
« LiqPay не даст вам заплатить $1 с карточки! $0,99 или $1,01 можно. Доллар? Не-не-не... PHP: интерфейсы и абстрактные классы »
>Мне пока видится это так: в коде модуля определяется, перед (или после) какого места в основном коде этот модуль должен вставляться.
И как ты cебе это представляешь? Будешь указывать кусок кода?
Единственное правильно решение, на мой взгляд, – это использование системы хуков и событий, как в любой другой cms.
>берёт основной код, вставляет модули
>через eval
Реализация с помощью call_user_func_array будет выглядеть более изящно
Не кусок, а небольшой кусочек. Вызов конкретной функции, например.
Про хуки и события можно подробнее, только кратко, со своим опытом?
И расскажи, пожалуйста, почему считаешь это единственно правильным решением.
>Не кусок, а небольшой кусочек.
А если ты обновишь Daos, а там окажется ещё один точно такой же кусочек кода?
Если же в файл в определённые места вставлены идентификаторы, то при привязке своей функции к данному идентификатору, функция будет связана только с ним, и в дальнейшем никаких проблем возникнуть не должно.
Например как это реализовано в wordpress
В конце формы добавления категории есть функция
do_action(‘add_tag_form’, $taxonomy);
если я хочу добавить новое поле в данную форму мне не нужно лезть в исходник, достаточно в файле с функциями темы или в плагине написать
add_action(‘add_tag_form’, ‘my_function’);
function my_function(){
echo ‘<input type=«text»>’;
}
Плюс я могу в функцию add_action добавить 3-й параметр, указывающий на очередность выполнения данной функции.
Фильтры:
Если мне надо удалить из комментариев мат, то мне также достаточно добавить фильтр, который будет пропускать через себя контент перед выводом его на экран
add_filter(‘comment_text’, ‘my_filter’);
function my_filter($content){
$content = str_replace(‘сцуко’, ‘цензура’, $content);
return $content;
}
Такая вероятность есть, действительно, но она очень маленькая и совсем исчезнет, если разработчик модуля озаботится более специфичным определением места вставки. Насколько я понимаю, 100% способа защиты модулей от изменений исходного проекта всё равно быть не может. В TextPattern, например, много плагинов, которые работают только со старыми версиями.
Твой пример с WordPress показывает ограниченность его подхода. Обязательно нужно определять возможности, которые есть у плагинописателей: вот в частности ты можешь написать фильтр для форм. Перекрывает ли это все потенциальные возможности, в которых может возникнуть желание внести изменения?
>Твой пример с WordPress показывает ограниченность его подхода.
А может и не нужна никому эта свобода.
Ты заранее определяешь в каких местах можно вставить свой код, ну а кодеру, пишущему плагин не придётся напрягаться на тему «какой бы кусочек кода выбрать, чтобы вставить после него свой код»
Буду думать ещё. Есть плюсы и минусы у обоих подходов.
Нерабочие плагины — от недостаточно абстрактного дизайна API. Хз даже, плохо это или хорошо. Чем меньше свобод, фич — тем легче абстрагировать. Например, у того же Гугела, код вставки карт, видео и т. п. на страницу — это ведь тоже простой API. Но там ничего нельзя. А где можно — уже да, идут несовместимости. Например, в Google Maps API v.3 полностью перекорчевали всю ООП-модель.
Конечно, хочется дать конструктор, чтобы что хотели — то и делали. Но кто его поддерживать будет потом? Любой пук — и тебя матерят уже толпы.
Вообще — неужто в таком небольшом инструменте нужно бешеные теоретические возможности? Можешь 3 примера совершенно разных плагинов привести?
Тормоз, попробуй в качестве примера поизучать, как устроены современные фреймворки. Самое главное на данном этапе – соблюсти баланс между гибкостью и простотой.
Samlowry, запросто могу привести три примера для «такого небольшого инструмента»: 1) Геотаргетинг, 2) поддержка баннеров, 3) вывод нескольких строк в одном блоке.
Alek$, как раз сейчас читаю руководство по CakePHP, его порекомендовали как раз в качестве примера организации MVC. Довольно простым языком написано.
CakePHP на мой взгляд не самый удачный вариант для этого, поскольку использует возможности ООП на уровне всего лишь PHP4.
Я бы порекомендовал Kohana или мой любиный Yii. С другой стороны, на базовом этапе все эти тонкости не особо влияют.
Ну мне как раз пока базовые понятия и надо вкурить. Фреймворки серьезно изучать вряд ли буду, жаль время. Я всё равно не планирую ими пользоваться.
>Alek$, как раз сейчас читаю руководство по CakePHP, его порекомендовали как раз в качестве примера организации MVC. Довольно простым языком написано.
Того, кто посоветовал, убил бы… Изучай Kohana 3 – вот где идеальная площадка для начала изучения ООП+MVC… Yii намного сложнее – очень много различных соглашений и ограничений. Кохана в разы проще и понятнее…
Видишь ли, там именно текст, причем написано понятно и немного. По «Кохане» есть примерно такой же мануал?
blogocms.ru/2009/12/…
devcookbook.net/blog… – тут вообще целый сайт об этом, хотя кое-какие моменты мне не нравятся.
kohanaframework.org/… – ну а это вообще обязательно к прочтению, хотя и очень мало.
В общем – было бы желание ;)
Кстати, сам начинал с cakephp – поэтому и отговариваю ;)
Посмотрю, спасибо.
Самая гибкая система расширения, что я видел – в фреймворке Kohana3. Именно для программистов.
Универсального решения все равно не выйдет. Эвал зло (в контексте ПХП, конечно). Я бы посоветовал цепочку фильтров.
Правда, если это ты о модулях контроллерах. А если о расширяемости вообще всей системы, то тут только интерфейсы и инверсия зависимостей.
Кстати, много где пишут, что eval — зло. А почему?
Уязвимо, медленно, ошибки на этапе компиляции не отлавливаются, на этапе выполнения отлавливаются крайне плохо.
Про какую компиляции в PHP ты говоришь? :)
В общем, если ты о расширяемости системы, то тут только интерфейсы и инверсия. То есть для каждого случая своя система, по сути :). А модули-контроллеры лучше всего делать фильтрами, где сам фильтр решает отрабатывать ему или нет, исходя из аргументов запроса. Кроме того есть еще middleware.
Про компиляцию в промежуточное представление.
Может стоит подумать на реализацией простой системы расширений, а потом всё реализовать на апи и плагинах.
Изначально просто систему расширений поддерживать легче.
ОК, буду ещё учится. Узнал тут много новых слов, всем спасибо :) Обязательно стану умнее.
NameOrNickname, так вообще-то примерно о том и речь.
Интерфейсы и ООП в помощь.
Возможно на пхп есть уже готовые системы расширений, фреймвёрки. Можно вырезать то, что нужно для своих проектов.
простенький ioc контейнер будет оптимальным решением в продукте типа даос, ящитаю
Во, на Хабре сейчас наткнулся на описание XenoForo, там как раз о плагинах и принципах их устройства есть маленько. Сам движок в высшей степени отстойный (но достойный продолжатель наследия предков), но принципы организации этого всего дела представляют некоторый интерес.
Тормоз, имхо, ты пытаешься сделать нечто большое из того, что должно оставаться маленьким. Ты же читал getting real. Рост – не всегда развитие. Сделаешь больше функций получишь больше багов!
Угу, а остановить развитие на этом этапе — остаться без продаж. Просто действительно многое необходимо ещё сделать, и делать это наращивая существующий код совсем неправильно. То, что я хочу сделать, это упрощение как раз, а не усложнение, как тебе кажется. При этом, как ни странно, система будет более функциональной и качественной.
Тормоз, слово гибкость в некоторых случаях становится ругательным, помни это. Простота и надежность гораздо важнее гибкости. А по поводу «остаться без продаж» – это надо не разработку, это надо рекламу наращивать. Нашел бы себе хорошего сейлза – дела бы гораздо быстрее пошли. Про грамотного продажника говорю по опыту компании в которой работаю.
Большинство твоих продуктов подкупают именно своей простотой. Полное следование заветам 37Сигналс… А насчет гибкости, поверь большая часть возможностей будет не то что не востребована, она будет просто неизвестна большинству пользователей и сторонних разработчиков.
Стандартный АПИ значительно упрощает и ускоряет разработку. Даже тебе самому.