Статьи

Органическое развитие


Несколько лет назад я работал графическим дизайнером, и я столкнулся с общей проблемой выбора цветовых схем для новых проектов. Один из моих коллег сказал: «Просто выбери красивую фотографию и возьми оттуда цвета» . Эта техника хорошо работает, потому что фотографии предлагают вам естественную комбинацию цветов. Поэтому я подумал: «Почему бы не перенести эту же концепцию на мою работу в качестве программиста?». И вот тут начинает играть Organic . Когда я впервые познакомился с Organic, я был поражен, насколько он прост и в то же время насколько гибок его подход. Наконец, у меня было кое-что, что поощряет модульное программирование, это так же полезно, как шаблон MVC, и это отличный инструмент для архитектуры.


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

органо-концепция

Organic распространяется в виде Node-модуля. Так что у вас должен быть уже установлен NodeJS. Если вы этого не сделаете, перейдите на nodejs.org и скачайте последнюю версию для вашей ОС. Ваш файл package.json должен выглядеть так:

1
2
3
4
5
6
7
8
9
{
    «name»: «OrganicDevelopment»,
    «version»: «0.0.0»,
    «description»: «Organic development»,
    «dependencies»: {
        «organic»: «0.0.11»
    },
    «author»: «Your Name Here»
}

Запустите npm install в том же каталоге, и менеджер загрузит необходимые файлы. Ядро Organic на самом деле довольно маленькое. Он содержит только определение основных элементов — клетка, ядро, мембрана, плазма, органелла, химия и ДНК. Конечно, он идет с несколькими тестами, но в целом это небольшой пакет. Это помогает облегчить обучение и начать разработку практически сразу.


Для этой статьи я решил создать простой веб-сайт, используя только ядро ​​Organic. Исходный код можно скачать в верхней части этой статьи, если вы хотите следовать. Я думаю, что этот пример приложения — лучший способ представить этот новый шаблон. Сайт содержит две страницы — Home и About . Вот скриншот сайта:

сайт

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

структура

Пользователь отправляет запрос в наше приложение NodeJs. Сервер принимает запрос и отправляет его в маршрутизатор. После этого Render знает, какую страницу следует использовать, и возвращает ответ на сервер. В конце ответ отправляется пользователю.

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

Вот как наше приложение будет выглядеть как Cell в Organic:

structureorganic

В ячейке у нас есть мембрана, которая удерживает внутренние элементы от внешнего мира. Внутри этой мембраны находится наш первый органел, наш Сервер, потому что именно здесь данные могут либо входить, либо выходить из нашего приложения. Другие органеллы (Router, Render и CSS) помещаются в плазму. Все эти модули взаимодействуют друг с другом через химикаты ( запрос , страница и CSS , отмечены красным). Сервер испускает химический запрос . Маршрутизатор испускает страницу, а органал CSS отправляет CSS . Я должен также упомянуть, что плазма действует как шина событий для химикатов. Органеллы прислушиваются к определенному химическому веществу и, если найдены, реагируют на него.

Вот еще одна схема потока запросов, но на этот раз с выделенными химическими веществами (отмечены красным):

structureorganic2

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


Все начинается с ДНК (дезоксирибонуклеиновой кислоты), которую вы можете рассматривать как конфигурацию клеток. Эта ДНК — то, где вы будете определять свои органеллы и их настройки.

Давайте создадим новый файл index.js и index.js следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var DNA = require(«organic»).DNA;
var Cell = require(«organic»).Cell;
 
var dna = new DNA({
    membrane: {
        Server: {
            source: «membrane.Server»
        }
    },
    plasma: {
        Router: {
            source: «plasma.Router»
        },
        CSS: {
            source: «plasma.CSS»,
            file: «./css/styles.css»
        },
        Render: {
            source: «plasma.Render»,
            templates: «./tpl/»
        }
    }
});
 
var cell = new Cell(dna);

Приведенный выше код является лишь определением для инициализации ДНК и клеток. Вы можете видеть, что мы поместили наш Сервер в мембрану, а Маршрутизатор, CSS и Render — в плазму, как мы обсуждали в предыдущем разделе. source свойство на самом деле является обязательным и содержит путь к вашим отдельным органеллам.

Имейте в виду, что свойство file в CSS organel и свойство templates в Render organel на самом деле являются пользовательскими свойствами, которые я установил. Здесь вы также можете добавить любую необходимую вам настройку.

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

01
02
03
04
05
06
07
08
09
10
/css
    /styles.css
/membrane
    /Server.js
/node_modules
/plasma
    /CSS.js
    /Render.js
    /Router.js
/tpl

01
02
03
04
05
06
07
08
09
10
var Chemical = require(«organic»).Chemical;
var Organel = require(«organic»).Organel;
var util = require(«util»);
 
module.exports = function YourOrganelName(plasma, config) {
    Organel.call(this, plasma);
    // your custom logic here
}
 
util.inherits(module.exports, Organel);

Приведенный выше код показывает основной формат для создания органел. Если вы хотите использовать this.emit или this.on вы должны убедиться, что наследуете Organel, как мы делали выше. И на самом деле, переменная параметра plasma имеет те же самые методы ( emit и on ), так что вы можете напрямую использовать plasma и пропустить наследование, если хотите.

Также обратите внимание на параметр config ; Это объект, который вы определили в своей ДНК, и это хорошее место для любой вашей пользовательской конфигурации.


Сервер — ваш главный органел, который принимает запросы и отправляет ответы в браузер. Вот как должен выглядеть органал вашего Сервера:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
var port = 3000;
module.exports = function Server(plasma, config) {
    Organel.call(this, plasma);
 
    var self = this;
    http.createServer(function(req, res) {
        console.log(«request » + req.url);
        self.emit(new Chemical({
            type: «request»,
            req: req
        }), function(html) {
            res.writeHead(200);
            res.end(html);
        });
    }).listen(port, ‘127.0.0.1’);
    console.log(‘Server running at http://127.0.0.1:’ + port + ‘/’);
 
}

Здесь происходят две вещи. Первым является определение сервера NodeJS, который, конечно, имеет обработчик, принимающий объекты запроса ( req ) и ответа ( res ). После получения запроса органелла Сервера отправляет химическое вещество вместе с request типа, уведомляя об этом остальные органеллы. Он также присоединяет объект req , поэтому тот, кто нуждается в дополнительной информации о входящем запросе, может получить доступ к данным химического вещества напрямую.

Затем метод emit принимает второй аргумент, который является функцией обратного вызова. Вы можете использовать это, чтобы вернуть поток обратно органелле, которая отправляет химическое вещество. Т.е. как только рендер завершит свою работу, он вызывает обратный вызов сервера. Он берет полученный HTML и с помощью объекта res отправляет страницу пользователю.


Для нашего следующего органа Маршрутизатор просто прослушивает request химического вещества, который отправляется сервером. Он получает URL от объекта req и решает, какую страницу следует показать. Вот код для маршрутизатора:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
module.exports = function Router(plasma, config) {
    Organel.call(this, plasma);
 
    var self = this;
    this.on(«request», function(chemical, sender, callback) {
        var page = chemical.req.url.substr(1, chemical.req.url.length);
        page = page == «» ||
        self.emit(new Chemical({
            type: «page»,
            page: page,
            ready: callback
        }));
    });
 
}

Теперь сам маршрутизатор испускает новый химикат с типом page . Имейте в виду, что есть два других органела, которые также слушают этот химикат, но по умолчанию он не передается всем другим элементам в плазме. Конечно, могут быть случаи, когда вам понадобится такая функциональность. Для этого вам просто нужно return false; в химическом слушателе. Мы увидим это в действии в следующем разделе.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
module.exports = function CSS(plasma, config) {
    Organel.call(this, plasma);
 
    var cssStyles = fs.readFileSync(config.file).toString();
    var self = this;
    this.on(«page», function(chemical) {
        self.emit(new Chemical({
            type: «css»,
            value: cssStyles
        }));
        return false;
    });
 
}

Этот модуль представляет собой простой органал с одной задачей, который получает путь к файлу .css , читает его, а затем испускает химическое вещество, содержащее фактические стили CSS. Также обратите внимание на return false; Заявление внизу. Как я уже говорил из предыдущего раздела, важно сделать это, иначе Render не получит химическое вещество page отправленное маршрутизатором. Это происходит потому, что CSSel органел определен до рендера в ДНК.


И, наконец, вот код для нашего Render Organel:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
module.exports = function Render(plasma, config) {
    Organel.call(this, plasma);
 
    var getTemplate = function(file, callback) {
        return fs.readFileSync(config.templates + file);
    }
    var formatTemplate = function(html, templateVars) {
        for(var name in templateVars) {
            html = html.replace(«{» + name + «}», templateVars[name]);
        }
        return html;
    }
    var templates = {
        layout: getTemplate(«layout.html»).toString(),
        home: getTemplate(«home.html»).toString(),
        about: getTemplate(«about.html»).toString(),
        notFound: getTemplate(«notFound.html»).toString()
    }
    var vars = {};
    var self = this;
 
    this.on(«css», function(chemical) {
        vars.css = chemical.value;
    });
    this.on(«page», function(chemical) {
        console.log(«Opening » + chemical.page + » page.»);
        var html = templates[chemical.page] ?
        html = formatTemplate(templates.layout, {content: html});
        html = formatTemplate(html, vars);
        chemical.ready(html);
    });
 
}

Здесь есть два вспомогательных метода: getTemplate и formatTemplate которые реализуют простой шаблонизатор для загрузки внешнего HTML-файла и замены переменных в стиле усов. Все шаблоны хранятся в объекте для быстрого доступа. После этого у нас есть всего несколько строк для форматирования HTML, и тогда все готово к работе. Органал Render также прослушивает химическое вещество css и, наконец, приложение при необходимости предоставляет страницу notFound 404.

Итак, вот как выглядит структура каталога конечного приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
/css
    /styles.css
/membrane
    /Server.js
/node_modules
/plasma
    /CSS.js
    /Render.js
    /Router.js
/tpl
    /about.html
    /home.html
    /layout.html
    /notFound.html

Просто запустите в консоли node index.js и вы увидите нечто похожее на это:

console1

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

Console2

Вы должны увидеть хороший отчет о недавней активности приложений. Теперь вы также можете заметить что-то еще в консоли:

1
2
request /favicon.ico
Opening favicon.ico page.

Вы можете видеть, что есть еще один запрос от браузера. Он хочет загрузить favicon.ico . Однако наш маленький сайт не имеет такой иконки, поэтому он просто открывает страницу 404. Вы можете попробовать это сами, посетив: http://127.0.0.1:3000/favicon.ico .

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


На мой взгляд, Organic — это отличная концепция. Он очень гибкий и стимулирует создание лучших приложений. Имейте в виду, что пример в этой статье основан на моем личном опыте работы с другими шаблонами проектирования. Таким образом, мое использование таких терминов, как Router, Data Provider или Render, является совершенно необязательным, и вы можете изменять имена по своему усмотрению. Не стесняйтесь экспериментировать, создавая новые модули на основе Organic, и дайте мне знать, что вы думаете в комментариях!

Ядро Organic разработано Борисом Филиповым и Валерием Богдановым, и я настоятельно рекомендую вам проверить их на Github. Если вы заинтересованы в использовании Organic, вы найдете такие вещи, как Angel и WebCell, действительно полезными.