- PVSM.RU - https://www.pvsm.ru -
Я начал работать с Meteor.js примерно полтора года назад, когда он был еще совсем сырым и нестабильным. Я сделал пару маленьких проектов, которые живы до сих пор, написал статью на Хабру [1] и даже получил дикие проблемы в продакшене с забиванием CPU на 100% при том, что сервер почти ничего не делал. Но прошло время, и я решил поставить еще один эксперимент и разработать с использованием этого фреймворка проект средней сложности. Разработка затянулась, и в процессе я сформулировал свои правила того, как структурировать приложение, как решать проблемы с безопасностью, как деплоить и какие инструменты использовать на серверах. Об этом и расскажу.
Внимательный читатель уже заметил, что я ничего не сказал про автоматизированное тестирование. Да, я не писал тесты, и это плохо. Как говорят в таких случаях: было мало времени [2]. Если хотите почитать про тестирование Meteor.js приложение, то есть статья здесь. [3]
Если следите за трендами в мире программирования, вы точно много раз слышали этот термин. Скорее всего, вы слышали его настолько часто, что он встал в один ряд с «big data». Как и в случае с «big data», термин «реактивность» употребляют теперь по поводу и без. Если вы не уверены, что знаете точно, что же такое «reactive programming», советую почитать небольшую статью The Reactive Manifesto [4], а тем, кто окончательно угорел по реактивному программированию и хочет еще, — пройдите курс c Мартином Одерски [5].
Meteor.js изначально позиционировался как фрэймворк, основанный на парадигме реактивного программирования, поэтому, если вы не прочитали ссылку выше, просто запомните 4 понятия: масштабируемость (scalability), событийно-ориентированное программирование (event-driven programming), отзывчивость (responsivness) и устойчивость (resilience). Они понадобятся нам позже.
Начните с чтения документации. [6]Затем узнайте про meteorite [7] и atmoshpere [8].В блоге приложения Kadira [9] можно найти много интересных статей про Meteor.js. Само приложение посвящено мониторингу Meteor приложений (типа newrelic).Посмотрите скринкасты [10] от разработчиков Meteor.js
Здесь я привел несколько ресурсов, где вы можете найти много про то, как работает фрэймворк, из чего он состоит и как с его помощью разрабатывать приложения. Далее я продолжу, предполагая, что вы знакомы с азами и можете написать простой чат на Meteor.js.
Я много размышлял над тем, как лучше организовать приложение, в итоге пришел к следующему:
Общая структура такая:
Для каждой страницы (роута) создается controller. У каждого controller есть один или несколько template. У каждого template есть один view.
Теперь подробно рассмотрим каждую директорию и то, что там должно быть.
В этой папке лежат контроллеры. Я предлагаю использовать IronRouter [11]. Он сделан специально для Meteor, поддерживает определение роутов на клиенте и сервере, создание контроллеров и layout'ов. Он достаточно популярен, и к нему есть приличное количество плагинов (например, iron-router-progress [12]).
Здесь лежат модели: коллекции и любые другие классы, ответственные за моделирование приложения.
Так как данные будут передаваться с сервера на клиент через подписки, вам придется писать аналогичные запросы как на клиенте, так и на сервере. Repository — хорошая абстракция, чтобы инкапсулировать все запросы к коллекциям. Тем более что встроенные в meteor методы для работы с коллекциями идентичны для сервера и клиента.
Здесь хранятся все файлы, которые должны исполняться только на сервере.
Как и в обычных приложениях, здесь лежат классы, которые содержат себе бизнес-логику.
Здесь лежат html-файлы.
Все файлы, которые здесь лежат, будут загружены только на клиенте.
Здесь лежат файлы, в которых содержаться обработчики событий и Spacebars [13] хелперы.Таким образом мы получаем что-то вроде ViewModel без лишнего кода.
Пример:
Template.dbase.events =
'click .js-more': ->
@questionPagination.loadNextPage() if @questionPagination.ready()
Template.friends_guess.showSteps = ->
StepsHelper.showSteps(@questionNum, @questionMax)
Клиентский код, который используется в нескольких разных view.
Клиентский библиотеки, которые вы подключаете для проекта.
И наконец, тут лежат определения Meteor-методов [14]
С самого начала прямой доступ к базе с клиента был одной из главных фич Meteor. Именно на нее опирался весь механизм реактивности, именно благодаря этому стал возможен механизм latency compensation и именно за нее больше всего фрэймворк критиковали. Однако в версии 0.6 появился механизм ограничения манипуляций с данными.
С базовыми принципами можно ознакомиться здесь [15].Тем не менее, остается вопрос. Как организовать код, который будет определять: разрешить или нет запрошенную операцию. Для примитивных случаев можно просто описать все в callback при вызове .allow
или .deny
, но для более сложного поведения это не подходит. Нам нужна какая-то форма, которая бы позволяла композицию, переиспользование и понятную организацию кода.
Говоря о безопасности, принято считать, что лучше организовывать защиту как набор независимых слоев. Исходя из всего вышеперечисленного, я решил выбрать структуру аналогично потокам из node.js:
class @Guard
@create: ->
new @
constructor: ->
@_heads = []
pipe: (head) ->
@_heads.push head
@
guard: ->
self = @
->
args = arguments
ctx = @
_.all(self._heads, (head) ->; head.apply(ctx, args))
Пример использования:
Answer.allow
insert: Guard.create().
pipe(RegisteredHead).
pipe(GameNotEndedHead).
guard()
Таким образом, мы просто определяем набор последовательно исполняемых фильтров. Если один из них возвращает false
, операция прерывается. Здесь каждый фильтр это отдельный, изолированный от других слой защиты. Как оказалось, в таких терминах довольно легко думать, когда речь идет о том, что вы хотите и что не хотите разрешать делать пользователю.
Предположим, что ваше приложение готово и настало время его задеплоить.
Но для начала вам нужно настроить сервера и выбрать web-сервер, если вы не хотите, чтобы node.js раздавал статику (вы точно не хотите). Самый простой вариант — nginx. Вам не составит никакого труда настроить nginx раздавать статику и апстримить запросы вашему приложению. Но в этой ситуации вам придется думать о супервизоре, о том, как организовать кластеризацию (распараллеливании node.js приложения).
Лично я вам советую использовать Phusion Passenger [16]. Уже примерно полгода он умеет работать как с node.js, так и конкретно с Meteor приложениями. Самым оптимальным будет установить его как плагин для nginx [17], а также у них есть целая статья [18] про то, как настроить passenger работать в связке с Meteor.
Также Meteor умеет читать Mongo Oplog для того, чтобы отслеживать изменения в базе. Это довольно сильно уменьшает нагрузку на CPU, но, чтобы это заработало, нужно настроить инстанс Mongo [19] как Replica Set.
Из коробки Meteor поддерживает команду [20] meteor deploy. Эта команда отправит ваш код на
Способов организовать деплой на свои собственные сервера много, но мне больше всего нравится node-модуль flightplan [22], поэтому для него у меня уже написан специальный рецепт [23], который заточен под интеграцию с Phusion Passenger и умеет делать zero-downtime deployment (более или менее).
Здесь я просто перечислю список полезных smart packages, которые помогли мне при разработке. Все их можно найти на Atmosphere [24].
Теперь поговорим про то, насколько Meteor удовлетворяет свойствам реактивного приложения.
Тут обсуждать нечего: конечно, удовлетворяет, правда, в немного извращенном варианте. Вместо подхода, который предлагает, например, Rx [26] или Observables в Scala, где мы оперируем потоками событий, здесь вся событийность от нас спрятана. Мы работаем с простым сиинзронным js-кодом. Это, с одной стороны, проще, с другой — сильно усложняет понимание того, как все работает внутри.
Так как Meteor — обычное node приложение, то и вопрос scalability решается для него точно так же. То есть сравнительно неплохо. Если вы используете Phusion Passenger, то он позаботиться о том, чтобы держать нужное количество инстансов приложения. Можно долго спорить о быстродействии MongoDB, но она довольно легко масштабируется, так что выбор именно этой БД добавляет приличное количество очков к параметру масштабируемости Meteor приложений.Если вы хотите знать больше о том, как себе все это представляют создатели Meteor, посмотрите это видео [27].
Ну тут все опять же упирается в архитектуру node.js. А мы знаем, что node.js работает в одном треде и, несмотря на высокую пропускную способность, в определенный момент начинает захлебываться. За что его многократно пинали ногами любители Erlang в многочисленных бенчмарк-тестах. Также, если node.js приложение падает, то падает дружно всем процессом, и ничего кроме перезапуска тут не поможет. Так что я бы не назвал Meteor приложением устойчивыми.
Это главная фишка Meteor. Бесплатный real-time из коробки.
В общем и целом, Meteor приложения можно назвать реактивными с некоторыми оговорками. Основные ограничения тут, скорее, не у Meteor, а у node.js. Но, так или иначе, Meteor точно может претендовать на реактивность.
Помимо реактивности, что уже само по себе является огромным преимуществом, я хотел отметить еще несколько моментов.
Разрабатывать под Meteor действительно приятно. Livereload из коробки, встроенная система билдинга статики. Удобство добавления препроцессоров. Подключение новых файлов на лету. Деплой встроенной командой на сервера *.meteor.com
для тестирования. Здесь все сделано, чтобы вы тратили меньше времени на разработку.
Spacebars [13] — переписанный handlebars. Чем-то напоминает Reac.js [28] и htmlbars [29], но (по ощущениям) работает медленнее, а также обладает магической способностью не менять html, который вы поменяли с помощью jquery (например), меняя все вокруг него. При этом не надо оборачивать в шаблоне этот кусок кода ни в какие хелперы. В общем, если вы хотите изменить часть страницы так, чтобы state приложения не менялся, spacebars это может.
Один из первых фреймворков, который пытается использовать тот факт, что и на сервере, и на клиенте используется один и тот же язык, на полную катушку. По умолчанию, весь ваш код исполняется и там, и там, а это значит, что вам не нужно дублировать код, если одинаковая логика встречается на сервере и клиенте.
Несмотря на все преимущества, есть и недостатки.
Что ни говори, а текущая версия Meteor — 0.8. Когда будет 1.0 непонятно, а значит будут изменения API, баги и регрессии. Но в принципе, с этим можно жить. Также я несколько раз сталкивался с багом, когда Meteor просто съедал 100% CPU без видимых на то причин, но в последних версиях этого, вроде бы, уже нет.
Когда я говорил, что отзывчивость (responsiveness) реализована немного извращенно, я не шутил. Часть логики обновления страницы при появлении новых данных реализуется с помощью исключений (exceptions), и это влечет неприятные последствия: иногда вы просто не видите ошибку, потому что она была поймана каким-то внутренним обработчиком Meteor, и тут приходится заниматься отладкой вслепую, это действительно бесит.
Также иногда выдается неполный stacktrace ошибки из-за наличия асинхронных операций, но эту проблему можно решить с помощью zones.js [30].
Вы постоянно находитесь в состоянии незнания того, какие данные у вас сейчас есть, а какие еще не пришли. Поэтому придется ставить кучу if. Чтобы этого избежать, старайтесь не делать очень сложных моделей документов: 1-2 уровня вложенности. Ну и конечно, придется обрабатывать все случаи отсутствия данных: ставить спиннеры и так далее, но это скорее хорошо.
Создатели Meteor называют своей главной целью максимально упростить разработку web-приложений. Сделать процесс создания прототипа максимально быстрым и удобным. И мне кажется, что Meteor действительно сильно упрощает и ускоряет разработку. В нем довольно много новых и интересных идей и это, пожалуй, первый проект, который использует преимущества разработки frontend и backend на одном языке.Если вы думаете, стоит ли использовать Meteor в своем следующем проекте, то задайте себе три вопроса:
Если хотя бы на два вопроса вы ответили «да», то советую дать Meteor шанс.
Собственно сам проект, который я реализовал, можно посмотреть здесь: ilito.paperpaper.ru [31]. Мне понравилось, и я непременно буду использовать Meteor в дальнейшем.
Если у вас есть какие-то вопросы, пишите в комментариях или мне в твиттер @thought_sync [32].
Автор: Terminal
Источник [33]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/67240
Ссылки в тексте:
[1] статью на Хабру: http://habrahabr.ru/post/155579/
[2] было мало времени: http://lurkmore.to/%D0%9E%D1%82%D0%BC%D0%B0%D0%B7%D0%BA%D0%B0_%D0%93%D0%BE%D0%BC%D0%B5%D1%80%D0%B0_%D0%A1%D0%B8%D0%BC%D0%BF%D1%81%D0%BE%D0%BD%D0%B0
[3] статья здесь.: http://habrahabr.ru/post/213171/
[4] The Reactive Manifesto: http://www.reactivemanifesto.org/
[5] курс c Мартином Одерски: https://www.coursera.org/course/reactive
[6] документации.: http://docs.meteor.com/
[7] meteorite: https://github.com/oortcloud/meteorite/
[8] atmoshpere: http://atmospherejs.com/
[9] блоге приложения Kadira: https://kadira.io/academy/
[10] скринкасты: https://www.meteor.com/screencast
[11] IronRouter: https://github.com/EventedMind/iron-router
[12] iron-router-progress: https://github.com/Multiply/iron-router-progress
[13] Spacebars: https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md
[14] Meteor-методов: http://docs.meteor.com/#methods_header
[15] здесь: http://docs.meteor.com/#dataandsecurity
[16] Phusion Passenger: https://www.phusionpassenger.com/
[17] плагин для nginx: https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html
[18] целая статья: https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial
[19] настроить инстанс Mongo: http://www.manuel-schoebel.com/blog/meteorjs-and-mongodb-replica-set-for-oplog-tailing
[20] команду: http://docs.meteor.com/#deploying
[21] хостинг: https://www.reg.ru/?rlink=reflink-717
[22] flightplan: https://github.com/pstadler/flightplan
[23] рецепт: https://gist.github.com/Termina1/10020494
[24] Atmosphere: https://atmospherejs.com/
[25] Kadira: https://kadira.io/
[26] Rx: http://msdn.microsoft.com/en-us/data/gg577609.aspx
[27] это видео: http://www.youtube.com/watch?v=2oEPJGNNpkM
[28] Reac.js: http://facebook.github.io/react/
[29] htmlbars: https://github.com/tildeio/htmlbars
[30] решить с помощью zones.js: http://meteorhacks.com/client-side-debugging-for-meteor-apps.html
[31] ilito.paperpaper.ru: http://ilito.paperpaper.ru/
[32] @thought_sync: https://twitter.com/thought_sync
[33] Источник: http://habrahabr.ru/post/232961/
Нажмите здесь для печати.