Pull to refresh

Модульное проектирование RIA проектов

Reading time 4 min
Views 3.2K

Проблемы при разработке больших проектов


ninjaОтделение котлет данных от представления, проектирование, велосипеды… главное без фанатизма. Какая проблема часто встречается при разработке RIA приложений. Команда сильных программистов «влюбляется» в новый проект, и с мыслями «сейчас мы сделаем нечто — главное все сделать самим, чтобы ни один чужой баг не закрался» начинают отказываться от готовых фреймворков, библиотек, решений.
Правда существует одно логичное объяснение этой тенденции, боязнь завязаться на чужой продукт, бывает такое, что в ходе разработки выясняется — такой интерфейс будет очень сложно разработать на доступном инструментарии, и рождаются костыли, правки чужих фреймворков и тд. Хотел бы предложить решение этой проблемы. Создание менеджера интерфейсов (модулей). Один модуль может использовать ExtJS, другой dhtmlx, а может и вообще чистый Javascript

Не чужое — а открытое


Какие плюсы использования готовых решений? Проще найти нового человека на проект, когда вы используете известный сторонний продукт. В ситуации когда вы остались единственный из создателей фреймворка и решаетесь уйти, то скорее всего новая команда перепишет все с нуля. Плюс правка багов и добавление новых фич пока вы работаете над бизнес логикой. Хотите мощное оружие в разделении данных от представления – используйте ExtJS например, зачем писать свой фреймворк!? Нужно динамически подгружать зависимости – посмотрите в сторону YepNope. Работу с dom предоставьте jQuery или любому другому известному фреймворку. Сконцентрируйтесь на результате. Я понимаю что большинство программистов любит писать все с нуля – но это не от того что он хочет учится, развиваться… это от лени… да-да, именно от лени. Изучение чужого кода, чтение документации куда сложнее чем разработка всего “с нуля”. Когда пишешь все “с нуля” многому не научишься, люди учатся в основном от других, исследуя чужую работу перенимаешь опыт (это как съесть печень своего противника), а в совокупности со своим опытом придумываешь что-то новое… более совершенное. Создавая стабильные приложения за короткие сроки вы получите больше признания чем закапываясь в правках очередного своего мега-фреймворка после выхода нового браузера IE6, IE7, IE8, IE9.
Если у вас цель написать свой фреймворк, вместо разработки ERP на которую вам дали срок 2 месяца – то начните с ОС… или с архитектуры процессора… а почему нет!?

Модульность как лекарство от многих болезней


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

Ядро – всему голова


Ядро приложения – это менеджер частей системы. Топ менеджер комнании, который выполняет функции супервизора. Он контролирует доступ к ресурсам и общение между объектами компании. Но никак не контроль загрузки товара на склад, выдача провианта и тд. Этим пусть занимаются утилиты и библиотеки, которым будут делегироваться задания.
В обязанности ядра входят:
  • Делегация загрузки модулей и необходимых зависимостей отделу библиотеке (в нашем случае я выбрал YepNope).
  • Делегация создания канвы для интерфейса модуля.
  • Передача информации между модулями.
  • Оповещение о каких либо событиях системы (закрытие приложения, активация нового модуля, изменения размера окна, потеря коннекта с сервером и тд.).
  • Выполнение запросов модулей (например загрузка другого модуля)
Полный код проекта смотрите на GitHub

Упрощенный вариант ядра:
/*=== core.js ===*/
!function () {

    var listOfLibraries = {};
    
    $(window).resize(function() {
        $.each(listOfLibraries, function(){
            this.body.onResize($(window).width(), $(window).height());
        });
    });

    $("script[id=core]").bind('request', function (data) {
        switch (data.header) {
            case "attach":
                var library = {
                    name: data.body.name,
                    body: new data.body.module()
                };
                listOfLibraries[library.name] = library;
                $('<div id="'+library.name+'"></div>').appendTo('body');
                var moduleContext = $('#'+library.name);
                library.body.main(moduleContext);
                break;
            }
    });
}();

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

Даешь независимость модулям!


Пример модуля:
/*=== HelloWorld.js ===*/
!function () { 

    var Lib = function () {
        var context;
        this.main = function (moduleContext) { 
            context = moduleContext;
            context.html('Hello World');
        }
        this.onResize = function(width, height){
            context.width(width);
            context.height(height);
        }
    }

    $("script[id=core]").trigger({  
        type: "request",                
        header: "attach",
        body: {
            module: Lib, 
            name: "HelloWorld"
        }
    });
} ();

Как видно из примера ядро общается с внешними компонентами по средствам событий, вернее одного события “request” – пула сообщений.
Тело сообщения состоит из заголовка (header) и тела (body). В данном случае модуль сообщает ядру что он хочет зарегистрироваться в системе под именен “HelloWorld” и сообщает ссылку на тело модуля.
Каждый модуль получает от ядра контекст с которым ему нужно работать. Общение с ядром, другими модулями или элементами страницы должно осуществляться через сообщения.
Зачем же нужно тогда ядро, если мы могли легко в модуле создать контекст и работать с ним!?
Отвечаю: для реализации многооконного интерфейса, для подгрузки модулей по требованию, для возможности загрузки зависимостей модулей, для создания единой системы общения между модулями, для просто поддержания кода… и тд.
В итоге мы получили легковесное модульное решение, при котором даже при полном изменении логики ядра – код модулей не меняется.
Все изменения касаются лишь добавления новых событий. Для унификации интерфейса для общения ядра с модулями лучше выделить абстрактный класс с базовой реализацией рутины и все Lib классы модулей наследовать от него.

window.Module = function () { 
    this.context;  
}
window.Module.prototype = {
    main: function (context) {
        this.context = context;
    },
    onResize: function (width, height) {

    }
}

При подключении модуля к ядру нужно лишь убедиться, что подключаемый модуль наследует функционал абстрактного класса Module, в случае успеха подключать его к системе.
Полный код проекта смотрите на GitHub
Tags:
Hubs:
+18
Comments 12
Comments Comments 12

Articles