тиражируемые решения

    Т.З. примерно следующее — необходимо иметь некоторый «быстрый старт» для приложений с стандартным функционалом. Дополнительным (и самым «заковыристым») условием является то, что этот стандартный функционал необходимо иметь возможность изменять самым невероятным образом, вплоть до полного отключения и замены своим (специфичным для данного приложения) кодом.

    Приведу жизненный пример: есть необходимость делать ОЧЕНЬ похожие приложения. Например интернет-магазины, которые построены на примерно одинаковых схемах данных, бизнес-процессах и тп. Т.е. функционал любого из магазинов примерно идентичен, различается только view слой.

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

    Собственно задача такая — как уменьшить «повторяемость кода» (т.е. отойти от monkey-patching-а) и при этом не потерять полный контроль над кодом.


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

    RoR-style (он же maven-archetype)


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

    Примером такого подхода являются большинство фреймворков на динамических ЯП: ruby on rails, django, grails,… Кроме того в java существует такой фреймворк как appfuse, использующий maven примерно для тех же целей (автогенерации начального кода).

    Плюсы:
    • Очень простая структура кода. Нет дополнительных описаний модулей или их конфигурирования. Зачастую — просто код на основном ЯП.
    • Скорость работы приложения — см. ниже


    Минусы:
    • Monkey-patching. Изменения (например bugfix) в основном коде придётся вносить во все проекты вручную.


    Java-style


    Код разносится по библиотекам и делается очень «настраиваемым» (код в таких библиотеках должен очень хорошо настраиваться и, кроме всего прочего, его можно заменить собственным кодом, специфичным для данного проекта).

    Примером такого подхода является например eclipse ide или nuxeo ecm, которые используют equinox (OSGI реализация) для уменьшения «связанности» кода (code decoupling).

    Плюсы:
    • отсутствие monkey-patching-а (изменения произошедшие в базовой библиотеке автоматически появятся во всех приложениях, его использующих).


    Минусы:
    • скорость (при использовании такой прослойки как equinox все операции взаимодействия между модулями приложения будут по определению медленнее, чем без использования такой прослойки. Насколько это замедляет приложение на практике сказать сложно — необходимо тестирование).
    • дополнительное «оформление» кода (в зависимости от фреймворка описание отдельного модуля потребует как минимум одного «файла описания» этого модуля. Так в nuxeo — это xml файл, в котором описывается модуль, его зависимости от других модулей и методы его «расширения». Т.е. то, как его можно сконфигурировать или отключить.


    Специфичное ручное тиражирование


    Наверное всем знакомое разнесение кода по библиотекам… Это когда ручками, без всяких «методов и концепций» а так — как бог на душу положит и архитектура позволит… Для Java кода — это использование Interface-ов и применение паттерна plugin, для view слоя — это написание чего-нибудь типа customViewHandler-а и так далее.

    Плюсы:
    • Не надо ничего изучать, не надо применять новые фреймворки. Весь код «специфичен» для данной области (будь то core или view или ещё что).


    Минусы:
    • Неуниверсальность. Для частного случая сложно предсказать заранее можно ли будет придумать «вынесение кода в библиотеку» или нет. А если будет возможно вынести код, то возможно это потребует нестандартного (не привычного) стиля написания кода или дополнительного его описания.


    Заключение



    В заключение хотелось бы спросить у аудитории — кто какой метод использует и насколько успешно?

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 52

      –4
      забракат!
        +1
        И хрюкотали зелюки, как мюмзики в маве...(Л. Кэрролл) Простите, но такие ассоциации с вашим комментарием ;)
          0
          Вот мне всегда было интересно, а почему вот это «хабракат!» надо обязательно писать в комментариях? Что, никак нельзя зайти в свои сообщения (%username%.habrahabr.ru/mail) и нажать ссылку «написать»?
            0
            потому что этот коммент всегда плюсуют
              0
              Неправда.
          +2
          на одном из проектов применяли следующий подход.
          Было написано базовое приложение состоящее из множества maven модулей. На выходе получался war'ник с кучей jar'ников внутри. В дальнейшем дописывались новые maven модули, которые либо замещали существующую функциональность, либо дополняли. Дальше, с помощью мавен-плагина Carge, war'ник базового проекта мёржился с war'ником конкретной надстройки, в результате получался war'ник, в котором было всё из общего приложения, плюс некоторые jar'ники были заменены новыми.
            0
            сори, плагин называется Cargo
              +2
              Интересное решение 8)

              А насколько мелкие jar-ники были? Получается, что надо делать очень маленькие библиотеки, чтобы при необходимости можно было их заменять?
                0
                да, джарники весьма маленькие. Всего в базовом приложении было около 30-40 jar'ников (не включая стандартные или 3rd-party)
                  0
                  Минус микро-jar модульности — остуствие/несовершенство инструментов для инкрементной сборки проекта=(.

                  Изменённые модули/зависимости приходится либо собирать вручную и затем «подкладывать» в приложение, либо пересобирать весь проект заново.

                    0
                    Офтоп: буду сильно признателен тому, кто подскажет решение проблемы «повторяемости сборки» для больших maven-проектов.
                      0
                      Не совсем понял суть проблемы, поясните, возможно ответ и найдётся.
              +1
              был еще более сложный и специфичный подход, который долго объяснять, поэтому всего в двух словах:
              точно так же написано базовое приложение, в котором куча jar'ников. В каждом jar'нике есть некий файл product.context, в котором хранится значение product=BASE.
              В тех jar'никах, которые должны заменить существующие из базового проекта, эта переменная выставлялась в новое значение product=APP1.
              Приложение написано на Spring'e + JSF. Для подгрузки подходящего JSF ресурса был написано ResourceResolver, который в зависимости от контекста приложения доставал либо базовый, либо кастомизированный ресурс. То же самое с бинами из Spring — был переопределён BeanLoader, который в зависимости от контекста доставал нужные бины, определённые либо в базовом, либо в кастомизированном приложении.
              Этот вариант позволял делать кастомизацию с несколькими уровнями, например APP1 кастомизировал BASE, а APP2 кастомизировал уже APP1
              Извините если непонятно написал:)
                +1
                сдается мне, что вы неправильно понимаете термин monkey-patching.
                  +1
                  термин очень расхожий, прежде чем писать статью я проконсультировался с википедией 8)
                  0
                  Весь (практически) код приложения создаётся для приложения в начале разработки автоматически (скриптом, батником, архетипом и тп) а в последствии изменяется под свои нужды в каждом конкретном проекте.

                  Примером такого подхода являются большинство фреймворков на динамических ЯП: ruby on rails, django, grails

                  ОМГ, про grails и RoR не скажу, но Django вы сюда точно зря приписали. Там полным ходом используются pluggable applications. Некоторые из них распространяются с самим Django: админка, система аутентификации, комментарии, и т.п.

                  А ещё и судя по тому, что вы написали про monkey-patching, про RoR и grails тоже не совсем правда написана. Что вызывает некоторые сомнения про весь остальной текст.
                    +1
                    Мильпардон, возможно я ошибся в деталях — RoR и Django знаю только постольку поскольку, но суть принципа я описал достаточно понятно я надеюсь.
                      0
                      Суть принципа — Код разносится по библиотекам и делается очень «настраиваемым»? Если да, то много букв из ничего. И в противовес приведены совершенно сомнительные методы.
                    0
                    appfuse генерит много ненужного кода и всяких левых зависимостей.
                    да, все это отключается, но в чем тогда смысл? в общем, штука полезная для ознакомления с веб-приложениями, но использовать его постоянно для себя нет смысла — проще брать скелет какого-то своего обкатанного приложения.
                    ну и вообще, оно предлагает поддержку только action framework, а сейчас народ все больше делает нервные движения в сторону ухода к component frameworks… опять же, для богато-аяксового приложения особой помощи appfuse не делает.
                    Полагаю, после пары лет дальнейшей эволюции и обкатки яваскриптовых библиотек виджетов, это направление вообще отомрет, и веб разработка будет в основном делаться в стиле GUI приложений. А сгенерить по нескольким классам-сущностям hibernate-DAO много ума не надо.
                      +1
                      мы сделали так

                      xslt решает все проблемы с view-слоем

                      в качестве framework для подключаемых модулей используем jpf.sourceforge.net, очень крутая штука, рекомендую

                        0
                        Если речь идет о небольших изменениях/отклонениях (пример с магазином), то аспекты вам в помощь.
                          +1
                          Как вариант стоит рассмотреть, но в большом проекте я боюсь, что аспекты черезчур усложнят разработку.
                            +1
                            Зависит от того, что такое для вас «большой проект», какие изменения в функционале требуются и насколько грамотно построена архитектура самого приложения.

                            У меня есть достаточно положительный опыт использования аспектов в приложении среднего размера (АРМ для обработки заявок на АДСЛ подключения).
                              0
                              согласен с каждым словом, как высвободится немного времени попробую решить проблему аспектами 8)
                                0
                                какие аспекты были, кроме элементарных логгирования, аутентификации и транзакций?
                                  0
                                  вот этих как раз и не было фактически (кроме нескольких advice в jdbc части при отладке)

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

                                    0
                                    ну… вроде это как-то мелко, что ли… чтобы отдельно на таком использовании аспектов акцентироваться
                            0
                            Где то выше уже говорилось о Spring. Крайне советую обратить на него внимание. Это IOC для того того и был придуман чтобы подставлять в нужные места классы с нестандартной функциональностью не основной код.
                              0
                              Спринг — замечательный фреймворк, но все потребности «плагинистости» он не покрывает. В частности я незнаю как с его помощью можно запихнуть в либу интерфейс страницы, а потом в проекте частично его изменить.
                                +1
                                >запихнуть в либу интерфейс страницы

                                oh noes
                                make me unsee it
                                  0
                                  селяви %)
                                    0
                                    А какие есть варианты? Копи-пастить страницы из проекта в проект?
                                      0
                                      а что у вас за проекты? типичный use-case хранения страницы в библиотеке не приведете?
                                        0
                                        почему же не приведу, приведу:

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

                                        Что в этом такого необычного?
                                          0
                                          а что такое в вашем понимании страница? Непосредственно html или ещё что-то?
                                            0
                                            Динамически генерируемая страница, статика в jar-нике это банально.
                                    +1
                                    жжоте
                                    что-то надо править в консерватории
                                      0
                                      Не совсем понял о чём Вы?
                                        0
                                        он о том, что хранить в либе страницы это как-то странновато
                                          0
                                          ну, по реплике «Копи-пастить страницы из проекта в проект?» я догадался, что bmc хочет реюзабельных законченных UI компонентов.
                                            0
                                            Мне кажется, что это не всегда так.

                                            К примеру, говоря о JSF и Facelets: вполне легальным случаем использования является хранение параметризуемых частей XHTML-страниц в библиотеках. Это, конечно, не дает возможности полностью избежать копи-паста, но, тем не менее, существенно сокращает количество кода, повторяющегося из проекта в проект. Характерный пример — функциональность login/logout.

                                            0
                                            в рамках вашего подхода проблема вообще вряд ли решается.
                                            посмотрите на компонентный подход:

                                            echo.nextapp.com/site/

                                            www.zkoss.org/

                                            wicket.apache.org/
                                              0
                                              Постойте, какого такого «моего подхода»? Я тут собственно спрашиваю о том кто как делает.
                                                0
                                                я про «страницы» которые как-то засунуть в джары, а потом их как-то модифицировать.
                                                в общем, так не делают :)
                                                  0
                                                  Почему же не делают? Вон тут люди xml юзают, я так полагаю, что xslt они как раз для целей изменения используют. Да кроме того я и сам использую подобный подход (дефолтные страницы в jar-е) с использованием jsf.
                                      +1
                                      Общего решения, к сожалению не существует. В зависимости от размера проекта (как по количеству кода, так и по количеству разработчиков) применимы разные подходы.

                                      скорость (при использовании такой прослойки как equinox все операции взаимодействия между модулями приложения будут по определению медленнее, чем без использования такой прослойки. Насколько это замедляет приложение на практике сказать сложно — необходимо тестирование).

                                      На практике использование только Equinox на производительности сказывается немного. Другое дело, что сам по себе Equinox особо удобно не поиспользуешь — слишком много кода для интеграции приходится писать. Частым вариантом является связка Equinox + Spring Dynamic Modules + Spring Framework. И вот здесь уже понятно, что работает это все довольно медленно. К сожалению, потому что концептуально все выглядит неплохо.
                                        0
                                        О Рельсах немного неправду сказали вы.
                                        Сами Rails хранятся в библиотеке Ruby как Gem (модуль, плагин, jar, как вам будет понятнее). На этапе создания приложения скрипт генерирует скелет, который использует эти основные библиотеки, при чем использует довольно активно. Затем программист уже на основе этого скелета выстраивает своё приложение. Convention over Configuration, и всё такое.

                                        После обновления ядра RoR ваше приложение при следующей загрузке подхватит обновленные библиотеки. Максимум, что придется сделать — это, возможно, изменить где-то в приложении участок кода для лучшей совместимости, или убрать старые костыли.
                                        И даже этого можно избежать, «заморозив» приложение (rake rails: freeze) — оно будет всё время использовать одну и ту же версию Rails-библиотек, независимо от того, до какой версии вы обновите у себя Rails.

                                          0
                                          Ну так вот человек хочет иметь не просто скелет в базовой поставке, а ещё пару моделей-контроллеров. В Django это реализованно с помощью приложений. В Rails этого нет, есть вроде костыль в виде Rails-Engines, но DHH против этого, так что в корке этого нет и не будет.
                                            0
                                            Ключевые слова: Plugins и Gems
                                            Плагины и гемы тоже умеют «делать» генераторы и расширять базовый функционал, с помощью которых человек в итоге может сгенерировать какой угодно скелет. Обновление плагинов так же просто, как и гемов — checkout с репозитория, и у тебя последняя версия плагина или гема, и никакого Monkey-patching'а.
                                            Рекомендую посмотреть на Radiant, как довольно интересный пример. Целая CMS в виде Gem'а, которая обновляется так же легко, как и ядро: gem update. И всё.
                                            Хотя я может чего-то и недопонимаю, т.к. не работал с Django.

                                            Что, по вашему, нельзя сделать в рельсах такого, что не требовало бы monkey-patching'а?
                                          +1
                                          1 — grails, 3 — ручками
                                            +1
                                            Есть еще такая вещь как Model Driven Architekture & Model Driven Development. Тут смысл не в рисовании UML-моделей на стадии «конципирования» а создании собственных, т.н. спецефических языков предметной области (domain specific language), использующие конкретную предметную область для моделирования приложения по принципу метамодель->тех. независимая модель->трансформация->тех. зависимая модель->генерация->готовый код.

                                            В данном случае «тиражирование» и «дополнение/изменение» находится на модельном уровне + создании/изменении генераторов или трансформаторов.

                                            вот довольно распространенные ОС инструменты из этой области
                                            www.andromda.org
                                            www.openarchitectureware.org

                                            мне лично очень нравится oaw, позволяющий работать с текстовыми моделями (хТехт) с помощью самодельных редакторов -> они (модели) намного легче читаются чем UML, легко сравниваются, изменения понятны и вообще, крутая вещь:)
                                              0
                                              Старый добрый ООП для business layer-а еще никто не отменял. Достоинство: на основе написанных компонентов при минимальном изменении можно кастомизировать логику. Недостаток: усложняется инъекция новых объектов, решается при помощи фреймворков типа Spring.

                                              Only users with full accounts can post comments. Log in, please.