UNPKG

node-warp

Version:

Web-agnostic Rapid Prototyping tools

176 lines (141 loc) 7.52 kB
## Architecture #### Решить, нужен ли вообще класс `Application` Его интерфейс везде (кроме методов `use` и `useConfig`) повторяет интерфейс `Component`. Вместо этого доработать `Component`, реализовав паттерн [Composite](https://sourcemaking.com/design_patterns/composite). В качестве "приложения" использовать специальный "корневой" компонент (ex.: `RunnerComponent`). ## Code Design ### Упростить разработку компонентов Изначально было так: ```javascript export default class ComponentA extends Component { /** 'get', потому что нативных статических полей пока нет */ static get prop() { return 10; } static get complexProp() { return { fieldA: 'a', fieldB: 20 }; } // ... behaviour implementation ... } ``` Но затем, в надежде разгрузить сам класс и повысить читаемость кода, решено было как-то разделить декларативную и поведенческую части компонента. Стало так: ```javascript export default class ComponentA extends Component { // ... behaviour implementation ... } ComponentA.id = 'component-a'; ComponentA.imports = ['imported-component']; ComponentA.exports = ['createClient', 'getClient']; ComponentA.events = { in: { 'event.a' }, out: { 'event.b' } }; ComponentA.defaults = { name: pkg.name, // duplicated in every module version: pkg.version // duplicated in every module desc: pkg.description // duplicated in every module }; ``` **Проблемы:** - Как известно, объявление `class` **не "всплывает"** (в отличие, например, от `function`). Поэтому всю "статику" приходится объявлять **после** класса (т.е. в самом низу модуля), -- выглядит противоестественно (сначала имплементация, потом декларация), и не очень удобно в целом. - Дублирование `defaults.name`, `default.version`, `default.desc`. Эти три строчки идентичны в каждом конкретном компоненте. - Поле `events` хранит названия сообщений в объектном формате (чтобы не хардкодить и снизить вероятность опечаток), но доступно оно только в пределах локального модуля. А поскольку о любом отдельно взятом сообщении "знают" как минимум два компонента (в реальности часто больше), то строковое содержимое `events` **повторяется** внутри каждого из них: ```javascript //component-a.es6 export default class ComponentA extends Component { /** ... */ } ComponentA.events = { in: { 'need.some.shit' } // <-- oops out: { 'some.shit.happened' } // duplicated on every subscriber }; //component-b.es6 (one of subscribers) export default class ComponentB extends Component { /** ... */ } ComponentB.events = { in: { 'some.shit.happened' } // <-- oops out: { 'need.some.shit' } // duplicated on every subscriber }; ``` **Решения:** - _Убрать поле `id` из статических членов класса._ Использовать имя класса в [Lisp-нотации](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Lisp), если 'id' не задан явно при создании. - _Убрать поле `events`._ Для объявления констант событий временно использовать общий модуль `messages` - _Убрать из `defaults` поля `name`, `version` и `desc`_ Сделать их подгрузку автоматической из `package.json` при регистрации компонента как модуля. ### Ввести универсальный формат сообщений #### Цели: - быстрая отладка; - более информативный мониторинг; #### Пример: ```javascript let _lastMessageID = 0; function CreateMessage(from, topic, data = {}, type = 'Event') { return { header: { id: _lastMessageID++, type: type, topic: topic, from: from, created: Date.now() }, payload: data }; }; function CreateReply(from, requestMessage, data = {}) { return { header: { id: _lastMessageID++, correlationID: requestMessage.id type: 'Reply', topic: `reply::${requestMessage.topic}::${requestMessage.id}`, from: from, created: Date.now() }, payload: data }; }; ``` ## Tools ### Написать CLI - утилиту для `warp` #### Цели: - более гибкая конфигурация; - более эффективная отладка компонентов; #### Пример использования: ```bash $ warp-cli --config=config.js --add=['component1', 'component2'] initializing @hp/warp v1.0.0 ------------------------------------- loading [config.js] done. loading [component1] fail. loading [component2] done. installing [@hp/warp-ticker] done. wiring up done. ------------------------------------- ready. type 'help' to show available commands warp > help 'help' - show available commands 'state' - show warp current configuration and state 'components' - show registered components 'start' - start warp with current configuration loaded 'destroy' - destroy warp and exit 'set <component-id> <key> <value>' - set config option to component 'get <component-id> [key]' - print components config option(-s) 'use <path>' - register component by module path 'unuse <id|all>' - destroy and remove component(-s) from warp 'emit <event> [data]' - emit event on warp message bus 'request <msg> [data] [timeout=0]' - send request to warp message bus, and print result ``` ## Other ### Выделить универсальные компоненты Вынести компоненты из ptz-common в отдельные репозитории. Объединить/разъединить/переименовать компоненты, проведя рефакторинг. - объединить `http-server` и `http-route-adapter` в **`warp-adapter-http`** - перенести `graceful-killer` в **`warp-process-guard`** - объединить `redis-relay` и `redis-client-pool` в **`warp-bridge-redis`** - из `application-storage` выделить **`warp-storage-redis`** ### Покрыть код тестами Сейчас тестируются только модули из состава `utils` и частично `Bus`