Методы проектирования модульных систем

09.10.2010

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

Предварительно у меня вырисовывается такой алгоритм: в коде, который взаимодействует с пользователем, изначально вызывается метод проверки наличия модулей. Если модули есть, метод вставляет их код в нужные места основной ветки. Вот это и есть самое сложное и, откровенно говоря, сомнительное решение. Как вставляет и как выбирает это место? Мне пока видится это так: в коде модуля определяется, перед (или после) какого места в основном коде этот модуль должен вставляться. А потом уже обработчик-проверяльщик берёт основной код, вставляет модули? и после всё это дело выполняет (через eval, например).

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

Позже написал про альтернативу. Остальные, надеюсь, интересные и полезные мнения выскажут комментаторы.

Альтернативный подход

Так делают чаще всего в CMS и других системах. Модули (ещё их часто называют плагинами) могут быть встроены только в чётко определённых местах и сконструированы в 100% соответствии с определёнными API. Например, так могли быть организованы модули оплаты в интернет-магазине. Под каждый биллинг добавляется свой модуль, который реализует общий интерфейс и детали реализации конкретного биллинга.

Но свободы при этом гораздо меньше, не всё сделаешь таким способом.

Ну, что думаете? Как правильно?

  1. # Virtual: 

    >Мне пока видится это так: в коде модуля определяется, перед (или после) какого места в основном коде этот модуль должен вставляться.

    И как ты cебе это представляешь? Будешь указывать кусок кода?
    Единственное правильно решение, на мой взгляд, – это использование системы хуков и событий, как в любой другой cms.

  2. # Virtual: 

    >берёт основной код, вставляет модули
    >через eval

    Реализация с помощью call_user_func_array будет выглядеть более изящно

  3. # Тормоз

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

    Про хуки и события можно подробнее, только кратко, со своим опытом?

    И расскажи, пожалуйста, почему считаешь это единственно правильным решением.

  4. # Virtual: 

    >Не кусок, а небольшой кусочек.

    А если ты обновишь 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;
    }

  5. # Тормоз

    А если ты обновишь Daos, а там окажется ещё один точно такой же кусочек кода?

    Такая вероятность есть, действительно, но она очень маленькая и совсем исчезнет, если разработчик модуля озаботится более специфичным определением места вставки. Насколько я понимаю, 100% способа защиты модулей от изменений исходного проекта всё равно быть не может. В TextPattern, например, много плагинов, которые работают только со старыми версиями.

    Твой пример с WordPress показывает ограниченность его подхода. Обязательно нужно определять возможности, которые есть у плагинописателей: вот в частности ты можешь написать фильтр для форм. Перекрывает ли это все потенциальные возможности, в которых может возникнуть желание внести изменения?

  6. # Virtual: 

    >Твой пример с WordPress показывает ограниченность его подхода.

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

  7. # Тормоз

    Буду думать ещё. Есть плюсы и минусы у обоих подходов.

  8. # samlowry

    Нерабочие плагины — от недостаточно абстрактного дизайна API. Хз даже, плохо это или хорошо. Чем меньше свобод, фич — тем легче абстрагировать. Например, у того же Гугела, код вставки карт, видео и т. п. на страницу — это ведь тоже простой API. Но там ничего нельзя. А где можно — уже да, идут несовместимости. Например, в Google Maps API v.3 полностью перекорчевали всю ООП-модель.

    Конечно, хочется дать конструктор, чтобы что хотели — то и делали. Но кто его поддерживать будет потом? Любой пук — и тебя матерят уже толпы.

    Вообще — неужто в таком небольшом инструменте нужно бешеные теоретические возможности? Можешь 3 примера совершенно разных плагинов привести?

  9. # Alek$

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

  10. # Тормоз

    Samlowry, запросто могу привести три примера для «такого небольшого инструмента»: 1) Геотаргетинг, 2) поддержка баннеров, 3) вывод нескольких строк в одном блоке.

    Alek$, как раз сейчас читаю руководство по CakePHP, его порекомендовали как раз в качестве примера организации MVC. Довольно простым языком написано.

  11. # Alek$

    CakePHP на мой взгляд не самый удачный вариант для этого, поскольку использует возможности ООП на уровне всего лишь PHP4.
    Я бы порекомендовал Kohana или мой любиный Yii. С другой стороны, на базовом этапе все эти тонкости не особо влияют.

  12. # Тормоз

    Ну мне как раз пока базовые понятия и надо вкурить. Фреймворки серьезно изучать вряд ли буду, жаль время. Я всё равно не планирую ими пользоваться.

  13. # aktuba

    >Alek$, как раз сейчас читаю руководство по CakePHP, его порекомендовали как раз в качестве примера организации MVC. Довольно простым языком написано.

    Того, кто посоветовал, убил бы… Изучай Kohana 3 – вот где идеальная площадка для начала изучения ООП+MVC… Yii намного сложнее – очень много различных соглашений и ограничений. Кохана в разы проще и понятнее…

  14. # Тормоз

    Видишь ли, там именно текст, причем написано понятно и немного. По «Кохане» есть примерно такой же мануал?

  15. # aktuba

    blogocms.ru/2009/12/…
    devcookbook.net/blog… – тут вообще целый сайт об этом, хотя кое-какие моменты мне не нравятся.
    kohanaframework.org/… – ну а это вообще обязательно к прочтению, хотя и очень мало.

    В общем – было бы желание ;)

  16. # aktuba

    Кстати, сам начинал с cakephp – поэтому и отговариваю ;)

  17. # Тормоз

    Посмотрю, спасибо.

  18. # janso: 

    Самая гибкая система расширения, что я видел – в фреймворке Kohana3. Именно для программистов.

  19. # Миша: 

    Универсального решения все равно не выйдет. Эвал зло (в контексте ПХП, конечно). Я бы посоветовал цепочку фильтров.

  20. # Миша: 

    Правда, если это ты о модулях контроллерах. А если о расширяемости вообще всей системы, то тут только интерфейсы и инверсия зависимостей.

  21. # Тормоз

    Кстати, много где пишут, что eval — зло. А почему?

  22. # Миша: 

    Уязвимо, медленно, ошибки на этапе компиляции не отлавливаются, на этапе выполнения отлавливаются крайне плохо.

  23. # Тормоз

    Про какую компиляции в PHP ты говоришь? :)

  24. # Миша: 

    В общем, если ты о расширяемости системы, то тут только интерфейсы и инверсия. То есть для каждого случая своя система, по сути :). А модули-контроллеры лучше всего делать фильтрами, где сам фильтр решает отрабатывать ему или нет, исходя из аргументов запроса. Кроме того есть еще middleware.

  25. # Миша: 

    Про компиляцию в промежуточное представление.

  26. # NameOrNickname: 

    Может стоит подумать на реализацией простой системы расширений, а потом всё реализовать на апи и плагинах.
    Изначально просто систему расширений поддерживать легче.

  27. # Тормоз

    ОК, буду ещё учится. Узнал тут много новых слов, всем спасибо :) Обязательно стану умнее.

    NameOrNickname, так вообще-то примерно о том и речь.

  28. # NameOrNickname: 

    Интерфейсы и ООП в помощь.
    Возможно на пхп есть уже готовые системы расширений, фреймвёрки. Можно вырезать то, что нужно для своих проектов.

  29. # Миша: 

    простенький ioc контейнер будет оптимальным решением в продукте типа даос, ящитаю

  30. # Тормоз

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

  31. # Evgeny Sergeev: 

    Тормоз, имхо, ты пытаешься сделать нечто большое из того, что должно оставаться маленьким. Ты же читал getting real. Рост – не всегда развитие. Сделаешь больше функций получишь больше багов!

  32. # Тормоз

    Угу, а остановить развитие на этом этапе — остаться без продаж. Просто действительно многое необходимо ещё сделать, и делать это наращивая существующий код совсем неправильно. То, что я хочу сделать, это упрощение как раз, а не усложнение, как тебе кажется. При этом, как ни странно, система будет более функциональной и качественной.

  33. # Штудер

    Тормоз, слово гибкость в некоторых случаях становится ругательным, помни это. Простота и надежность гораздо важнее гибкости. А по поводу «остаться без продаж» – это надо не разработку, это надо рекламу наращивать. Нашел бы себе хорошего сейлза – дела бы гораздо быстрее пошли. Про грамотного продажника говорю по опыту компании в которой работаю.

    Большинство твоих продуктов подкупают именно своей простотой. Полное следование заветам 37Сигналс… А насчет гибкости, поверь большая часть возможностей будет не то что не востребована, она будет просто неизвестна большинству пользователей и сторонних разработчиков.

    Стандартный АПИ значительно упрощает и ускоряет разработку. Даже тебе самому.

Комментирование этой статьи закрыто.

Интересное Покупки ТехникаРазное Отдых Статьи Строительство Услуги Общество Хобби Культура Советы Уют