Розробка з Meteor.js і реактивне програмування

    Я почав працювати з Meteor.js приблизно півтора роки тому, коли він був ще зовсім сирим і нестабільним. Я зробив пару маленьких проектів, які живі досі, написав статтю на Хабре і навіть отримав дикі проблеми в продакшені з забиванням CPU на 100% при тому, що сервер майже нічого не робив. Але минув час, і я вирішив поставити ще один експеримент і розробити з використанням цього фреймворка проект середньої складності. Розробка затягнулася, і в процесі я сформулював свої правила того, як структурувати додаток, як вирішувати проблеми з безпекою, як деплоіть і які інструменти використовувати на серверах. Про це і розповім.
 
Уважний читач вже помітив, що я нічого не сказав про автоматизоване тестування. Так, я не писав тести, і це погано. Як кажуть у таких випадках: було мало часу . Якщо хочете почитати про тестування Meteor.js додаток, тобто стаття тут.
 
 
 
 Реактивність
Якщо стежте за трендами в світі програмування, ви точно багато разів чули цей термін. Швидше за все, ви чули його настільки часто, що він встав в один ряд з «big data». Як і у випадку з «big data», термін «реактивність» вживають тепер з приводу і без. Якщо ви не впевнені, що знаєте точно, що ж таке «reactive programming», раджу почитати невелику статтю The Reactive Manifesto , а тим, хто остаточно вчадів по реактивному програмуванню і хоче ще, — пройдіть курс c Мартіном Одерського .
 
Meteor.js спочатку позиціонувався як фреймворк, заснований на парадигмі реактивного програмування, тому, якщо ви не прочитали посилання вище, просто запам'ятайте 4 поняття: масштабованість (scalability), подієво-орієнтоване програмування (event-driven programming), чуйність (responsivness) і стійкість (resilience). Вони знадобляться нам пізніше.
 
 З чого почати
Почніть з читання документації. Потім дізнайтеся про meteorite і atmoshpere .
В блозі додатки Kadira можна знайти багато цікавих статей про Meteor.js. Сам додаток присвячено моніторингу Meteor додатків (типу newrelic).
Подивіться скрінкасти від розробників Meteor.js
 
Тут я навів кілька ресурсів, де ви можете знайти багато про те, як працює фреймворк, з чого він складається і як з його допомогою розробляти програми. Далі я продовжу, припускаючи, що ви знайомі з азами і можете написати простий чат на Meteor.js.
 
 Структура додатки
Я багато розмірковував над тим, як краще організувати додаток, в результаті прийшов до наступного:
     
  • client / helpers
  •  
  • client / vendor
  •  
  • client / views
  •  
  • controllers
  •  
  • methods
  •  
  • models
  •  
  • repositories
  •  
  • server
  •  
  • services
  •  
  • templates
  •  
Загальна структура така:
Для кожної сторінки (роута) створюється controller. У кожного controller є один або кілька template. У кожного template є один view.
 
Тепер детально розглянемо кожну директорію і те, що там має бути.
 
 
Controllers
У цій папці лежать контролери. Я пропоную використовувати IronRouter . Він зроблений спеціально для Meteor, підтримує визначення Роут на клієнті і сервері, створення контролерів і layout'ов. Він досить популярний, і до нього є пристойна кількість полігонів (наприклад, iron-router-progress ).
 
 
Models
Тут лежать моделі: колекції та будь-які інші класи, відповідальні за моделювання додатки.
 
 
Repositories
Так як дані будуть передаватися з сервера на клієнт через підписки, вам доведеться писати аналогічні запити як на клієнті, так і на сервері. Repository — хороша абстракція, щоб инкапсулировать всі запити до колекцій. Тим більше що вбудовані в meteor методи для роботи з колекціями ідентичні для сервера і клієнта.
 
 
Server
Тут зберігаються всі файли, які повинні виконуватися тільки на сервері.
 
 
Services
Як і в звичайних додатках, тут лежать класи, які містять собі бізнес-логіку.
 
 
Templates
Тут лежать html-файли.
 
 
Client
Всі файли, які тут лежать, будуть завантажені тільки на клієнті.
 
 
Views
Тут лежать файли, в яких міститися обробники подій і Spacebars хелпери.Такім чином ми отримуємо щось на зразок ViewModel без зайвого коду.
 
Приклад:
Template.dbase.events =
  'click .js-more': ->
    @questionPagination.loadNextPage() if @questionPagination.ready()

Template.friends_guess.showSteps = ->
  StepsHelper.showSteps(@questionNum, @questionMax)

 
Helpers
Клієнтський код, який використовується в декількох різних view.
 
 
Vendor
Клієнтський бібліотеки, які ви підключаєте для проекту.
 
 
Methods
І нарешті, тут лежать визначення Meteor-методів
 
 Обмеження доступу до бази
З самого початку прямий доступ до бази з клієнта був однією з головних фіч Meteor. Саме на неї спирався весь механізм реактивності, саме завдяки цьому став можливий механізм latency compensation і саме за неї найбільше фреймворк критикували. Однак у версії 0.6 з'явився механізм обмеження маніпуляцій з даними.
 
З базовими принципами можна ознайомитися тут .Проте, залишається питання. Як організувати код, який визначатиме: дозволити чи ні запитану операцію. Для примітивних випадків можна просто описати все в 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 . Уже приблизно півроку він вміє працювати як з node.js, так і конкретно з Meteor додатками. Найоптимальнішим буде встановити його як плагін для nginx , а також у них є ціла стаття про те, як налаштувати passenger працювати у зв'язці з Meteor.
 
Також Meteor вміє читати Mongo Oplog для того, щоб відслідковувати зміни в базі. Це досить сильно зменшує навантаження на CPU, але, щоб це запрацювало, потрібно налаштувати інстанс Mongo як Replica Set.
 
З коробки Meteor підтримує команду meteor deploy. Ця команда відправить ваш код на хостинг, який розробляють творці Meteor спеціально для хостингу додатків цього фреймворка. Це дуже зручно для того, щоб просто потестировать додаток або організувати staging environment, але для production логічніше мати свої власні сервера.
 
Способів організувати Деплой на свої власні сервера багато, але мені найбільше подобається node-модуль flightplan , тому для нього у мене вже написаний спеціальний рецепт , який заточений під інтеграцію з Phusion Passenger і вміє робити zero-downtime deployment (більш- менш).
 
 Корисні smart packages
Тут я просто перерахую список корисних smart packages, які допомогли мені при розробці. Усі їх можна знайти на Atmosphere .
     
  1. accounts-vkontakte — додає авторизацію для VK в стандартний модуль авторизації Meteor
  2.  
  3. iron-router — кращий router для Meteor додатків
  4.  
  5. user-status — повідомляє про те, чи знаходиться зараз конкретний користувач на online.
  6.  
  7. define — якщо у вас багато файлів, то вам необхідна система модулів. Ця дуже проста, але є все, що потрібно
  8.  
  9. houston — хороша админка
  10.  
  11. cron-tick — міні-cron всередині Meteor додатки
  12.  
  13. kadira — модуль моніторингу додатки для сервісу Kadira
  14.  
 
 Реактивність
Тепер поговоримо про те, наскільки Meteor задовольняє властивостям реактивного додатки.
 
 
Event-driven development
Тут обговорювати нічого: звичайно, задовольняє, правда, в трохи спотвореному варіанті. Замість підходу, який пропонує, наприклад, Rx або Observables в Scala, де ми оперуємо потоками подій, тут вся подієвість від нас захована. Ми працюємо з простим сіінзронним js-кодом. Це, з одного боку, простіше, з іншого — сильно ускладнює розуміння того, як все працює всередині.
 
 
Scalability
Так як Meteor — звичайне node додаток, то і питання scalability вирішується для нього точно так же. Тобто порівняно непогано. Якщо ви використовуєте Phusion Passenger, то він подбати про те, щоб тримати потрібну кількість інстанси додатки. Можна довго сперечатися про швидкодію MongoDB, але вона досить легко масштабується, так що вибір саме цієї БД додає пристойну кількість очок до параметру масштабованості Meteor пріложеній.Еслі ви хочете знати більше про те, як собі все це уявляють творці Meteor, подивіться це відео .
 
 
Resilience
Ну тут все знову ж упирається в архітектуру node.js. А ми знаємо, що node.js працює в одному тред і, незважаючи на високу пропускну здатність, в певний момент починає захлинатися. За що його багато разів копали ногами любителі Erlang в численних бенчмарк-тестах. Також, якщо node.js додаток падає, то падає дружно всім процесом, і нічого крім перезапуску тут не допоможе. Так що я б не назвав Meteor додатком стійкими.
 
 
Responsive
Це головна фішка Meteor. Безкоштовний real-time з коробки.
 
 
Підсумок
У загальному і цілому, Meteor додатки можна назвати реактивними з деякими застереженнями. Основні обмеження тут, швидше, не у Meteor, а у node.js. Але, так чи інакше, Meteor точно може претендувати на реактивність.
 
 Переваги
Крім реактивності, що вже само по собі є величезною перевагою, я хотів відзначити ще кілька моментів.
 
 
Швидкість розробки
Розробляти під Meteor дійсно приємно. Livereload з коробки, вбудована система білдінга статики. Зручність додавання препроцесорів. Підключення нових файлів на льоту. Деплой вбудованої командою на сервера
*.meteor.com
для тестування. Тут все зроблено, щоб ви витрачали менше часу на розробку.
 
 
Spacebars
Spacebars — переписаний handlebars. Чимось нагадує Reac.js і htmlbars , але (по відчуттях) працює повільніше, а також має магічну здатність не змінювати html, який ви поміняли за допомогою jquery (наприклад), змінюючи все навколо нього. При цьому не треба обертати в шаблоні цей шматок коду ні в які хелпери. Загалом, якщо ви хочете змінити частину сторінки так, щоб state додатки не змінювався, spacebars це може.
 
 
Гомогенність
Один з перших фреймворків, який намагається використовувати той факт, що і на сервері, і на клієнті використовується один і той же мова, на повну котушку. За замовчуванням, весь ваш код виповнюється і там, і там, а це значить, що вам не потрібно дублювати код, якщо однакова логіка зустрічається на сервері і клієнті.
 
 Проблеми
Незважаючи на всі переваги, є і недоліки.
 
 
Нестабільність
Що ні говори, а поточна версія Meteor — 0.8. Коли буде 1.0 незрозуміло, а значить будуть зміни API, баги і регресії. Але в принципі, з цим можна жити. Також я кілька разів стикався з багом, коли Meteor просто з'їдав 100% CPU без видимих ​​на те причин, але в останніх версіях цього, начебто, вже немає.
 
 
Налагодження
Коли я говорив, що чуйність (responsiveness) реалізована трохи викривлено, я не жартував. Частина логіки поновлення сторінки при появі нових даних реалізується за допомогою винятків (exceptions), і це тягне неприємні наслідки: іноді ви просто не бачите помилку, бо вона була спіймана якимось внутрішнім оброблювачем Meteor, і тут доводиться займатися налагодженням наосліп, це дійсно бісить.
 
Також іноді видається неповний stacktrace помилки через наявність асинхронних операцій, але цю проблему можна вирішити за допомогою zones.js .
 
 
Невизначеність
Ви постійно перебуваєте в стані незнання того, які дані у вас зараз є, а які ще не прийшли. Тому доведеться ставити купу if. Щоб цього уникнути, намагайтеся не робити дуже складних моделей документів: 1-2 рівня вкладеності. Ну і звичайно, доведеться обробляти всі випадки відсутності даних: ставити спіннери і так далі, але це скоріше добре.
 
 Висновок
Творці Meteor називають своєю головною метою максимально спростити розробку web-додатків. Зробити процес створення прототипу максимально швидким і зручним. І мені здається, що Meteor дійсно сильно спрощує і прискорює розробку. У ньому досить багато нових і цікавих ідей і це, мабуть, перший проект, який використовує переваги розробки frontend і backend на одному язике.Еслі ви думаєте, чи варто використовувати Meteor в своєму наступному проекті, то задайте собі три запитання:
     
  1. Чи потрібен вам real-time?
  2.  
  3. Чи підходить вам MongoDB?
  4.  
  5. любите ви bleeding edge технології?
  6.  
Якщо хоча б на два питання ви відповіли «так», то раджу дати Meteor шанс.
 
Власне сам проект, який я реалізував, можна подивитися тут: ilito.paperpaper.ru . Мені сподобалося, і я неодмінно буду використовувати Meteor надалі.
Якщо у вас є якісь питання, пишіть в коментарях або мені в твіттер tagsep53thought_sync .
    
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.