Наш взгляд: Meteor против Derby

в 7:19, , рубрики: Derby, Derbyjs, javascript, Meteor, Meteorjs, node.js, nodejs, Веб-разработка

От переводчика: Не встречал на хабре материалов, посвященных фреймворку Derbyjs, который часто упомянается, как основной конкурент Meteor. Под катом сравнение этих двух фреймворков, сделанное авторами Derby. Сравнению уже больше года, но тем, кто не читал, думаю будет интересно.

Нас часто просят сравнить эти два продукта. Хотелось бы поблагодарить Ника Рителлока (Nick Retallack), который проделал большую работу по их сравнению в нашей группе: Google Group. Часть его выводов будет использована в данной статье.

Как все начиналось

Прежде всего, хотелось бы отметить, что впервые мы с Брайаном встретились с командой Meteor в ноябре, во время демонстрации ранней версии Derby на конференции Keeping it Realtime, организуемой &yet. Когда мы встретились, команда Meteor уже начала разработку своего фреймворка, и сходство было видно невооруженным глазом. Немногим ранее, я так же встречался с Девидом Гринспеном (который недавно присоединился к Meteor), интересно было пообщаться и обсудить его опыт создания Etherpad. Наши команды дружат, общаются и многому учатся друг у друга.

Нас объединяет общее видение мира, где все приложения работают “в реальном времени” и “в режиме совместной работы”. Мы, как и множество других разработчиков, полтора года назад внезапно остро осознали, что, используя современные подходы к веб-разработке, чрезвычайно трудно создать положительный пользовательский опыт, особенно там, где данные обновляются динамически.

Мы с Брайаном обсуждали это год назад. Я в то время работал менеджером по продукту в команде Google Search, а он занимался несколькими открытыми Node.js проектами, включая Mongoose и everyauth. Мне было интересно разработать этот фреймворк, поскольку я считал, что так лучше всего создавать приложения с нужной мне производительностью, а Брайан чувствовал, что Node.js сообществу нужен легкий в использовании фреймворк для тех разработчиков, которые предпочитают Rails или PHP.

Святой Грааль: сервеный и клиентский код

Работая в Google Search я понял, что для того что-бы приложение было отзывчивым, критически важно генерировать вебстраницы, как на сервере, так и на клиенте. Google в состоянии сделать это — там уйма разработчиков, а скорость первостепенна при поиске. Что бы достичь быстрой загрузки и быстрого обновления, в Google Search весь код генерации страниц наполовину написан на С++ и лишь наполовину на JavaScript. За последнюю пару лет они запустили несколько проектов для упрощения этой задачи, но не стоит и говорить, что подобный процесс разработки слишком дорог и бесполезен для стартапов или сложных приложений.

Gmail, Twitter и другие сайты, которые рендерятся только на клиенте, слишком медленно грузятся. Twitter прошел по полному кругу – они начинали с полностью серверной генерации на Rails, затем перенесли всю генерацию на клиент, получив в качестве результата то, что чтение 140 символьного сообщения стало занимать у пользователя 4 секунды. Теперь Twitter формирует половину страницы на Scala на сервере, и затем, другую половину на JavaScript на клиенте. Все это вместе делает поддержку кода более сложной и означает, что менее важные части страницы появляются только через нескольких секунд после того, когда страница полностью загрузилась. Люди очень чувствительны к изменениям, и вновь появляющиеся элементы отвлекают внимание от более важных.

Благодаря перерождению JavaScript-производительности в V8 и простоте создания JavaScript серверов с Node.js, многие разработчики воодушевились идеей использования JavaScript одновременно на клиенте и сервере. Но, несмотря на эту удивительную возможность, только некоторые приложения используют совместный код. Даже с одним языком здесь все ещё множество проблем, включая: различия в задержках и стабильности соединения, различия в способах работы с URL на сервере и в браузере, существование DOM в браузере и отсутствие его на клиенте, и наконец, наличие прямого доступа к файловой системе только на сервере.

Итак, к делу!

Учитывая все это, наши команды решили двигаться сходными путями в одних вопросах, и совершенно различными в других. Цель Derby — дать любому разработчику возможность писать приложения, которые грузятся так же быстро, как и поисковая система, такие же интерактивные, как текстовый редактор и работающие оффлайн. Цитируя Джефа (Geoff), цель Meteor — создать “платформу ‘для широкого рынка’ используемую в 90% сайтов в интернете, и для этих 90% сделать веб-разработку быстрой настолько, насколько это возможно”.

GPL против MIT

В настоящий момент Meteor поставляется только по лицензии GPL. Это означает, что если вы не хотите публиковать свои исходники под лицензией GPL или совместимой с ней, вам нужно будет связаться с ними и договориться о коммерческой лицензии.
Derby, Racer и все остальные компоненты нашего фреймворка публикуются под свободной от этих недостатков лицензией MIT. Вы сможете сделать со своим приложением все, что угодно, и мы не сможем помешать вам ни сейчас ни в дальнейшем.

Я не юрист, поэтому не стоит воспринимать все, что я только что сказал совсем буквально. Я не видел будущее в хрустальном шаре или что-то в этом роде. (Да, наш юрист однажды попросил меня упомянуть это.)

Система пакетов Meteor против npm

В Meteor создали свою пакетную систему и средство распространения пакетов.

Модули Node.js подчиняются хорошо описанному стандарту CommonJS и имеют встроенном модульный API. Однако, изначально система распространения пакетов отсутствовала. В самом начале у Node.js было несколько пакетных менеджеров, но большинство разработчиков сейчас остановилось на использовании npm. Он настолько универсален, что даже включается в дистрибутив с Node.js.

Говоря откровенно, это главное, что тревожит меня в Meteor. Как будто люди, пробующие Meteor, никогда не использовали Node.js и не знают о преимуществах распространения пакетов через npm. Я, и множество других разработчиков, видим в npm ключевую силу Node.js, и будет очень грустно видеть её ослабление несовместимой пакетной системой.

Как и во множестве других Node.js проектов, мы распространяем Derby, Racer и их плагины, как npm-модули. И мы продолжим разбивать наш проект на небольшие модули, так чтобы ими легче было воспользоваться другим. Возможно вы не используете Derby, но вам необходимо осуществлять разбор HTML. Нам нужно было написать простой и быстрый HTML-парсер для работы нашей системы шаблонов, и вы можете им воспользоваться в своих Node.js проектах. Connect – прекрасный пример проекта с богатой экосистемой модулей, основанных на нем и распространяемых через npm, и мы тоже надеемся следовать по этому пути.

Совместимость с другими библиотеками

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

Meteor обычно управляет созданием сервера по своему. Это делает процесс создания и развертывания Meteor-приложений на их сервер необычайно простым, но в то же время сильно усложняет использование Meteor, как модуль на обычном Node.js сервере.

В противоположность этому, Derby — это обычный npm-модуль, который может быть добавлен к любому Node.js серверу. Если вы хотите использовать один из 8900 npm модулей (сейчас 39 тысяч — прим. пер.), просто добавьте их в свой package.json файл и выполните npm install.

Derby не предоставляет никакого решения для хостинга, поскольку на рынке уже есть множество прекрасных хостинг-сервисов. В будущем мы предоставим инструкции о том, как быстро установить и запустить Derby на любом публичном сервере.

Racer (движок реального времени, управляющий моделями в Derby) это отдельный модуль, и может быть использован независимо от Derby. Вы можете внедриться в любой UI уровень Racer и контролировать методы, вызываемые при обновлении модели. Racer создан на основе популярного модуля, Socket.IO, к которому можно обращаться и напрямую, если это необходимо.

В ядре Derby также используются несколько популярных библиотек, особенно Express для маршрутизации и Browserify, который упаковывает большинство Node.js модулей для браузера автоматически.

MongoDB API против Racer-методов

Meteor использует MongoDB API прямо в браузере. MongoDB API мощное и простое в использовании из JavaScript. К нему уже привыкли, возникли определенные шаблоны разработки, и, в целом, его достаточно для решения большинства задач, которые могут возникнуть при разработке приложения. Похоже многие находят достаточно удобным такой подход для создания приложений, поскольку он снимает необходимость понимания слоев абстракции. Кое-кто говорит о проблемах с безопасностью, но я думаю не стоит судить строго, пока команда Meteor не вынесет на свет свой подход к аутентификации и авторизации.

У Racer же свой собственный API, построенный вокруг “методов изменения данных” и “путей”. Это API позволяет 1:1 подключаться к любому документо-ориентированному хранилищу, включая и MongoDb. В этом конечно есть свои плюсы и минусы, но мы считаем, что так лучше по нескольким причинам:

Разрешения конфликтов

“Пути” и “методы” отлично подходят для техники разрешения конфликтов, которая, как мы ожидаем, будет одной из самых больших преимуществ Racer. Сейчас, по умолчанию, мы используем технику “последний записывающий изменения выигрывает”, что эквивалентно тому, как сохраняет данные Meteor. Однако у нас есть предварительная реализация системы разрешения конфликтов через Software Transactional Memory и методы Operational Transformation. Эти техники позволяют использовать приложения Derby оффлайн, а затем корректно синхронизироваться. Так же становится возможным реализовывать вещи, в стиле Google Docs — совместное одновременное редактирование содержимого в одном текстовом поле.

Заменяемость хранилищ данных

Наши “пути” и “методы” достаточно гибки для того, чтобы использовать возможности большинства хранилищ данных, переключаться с одного на другое и даже использовать несколько из них одновременного. Переключение между Riak, Postgres, CouchDb или каким-нибудь другим сервисом происходит без необходимости модифицировать исходных код.

Эффективность PubSub (публикация данных/подписка на изменения данных)

Наши “пути” отлично сочетаются с механизмом PubSub, именно так мы в реальном времени синхронизируем изменения данных. В реализации LiveMongo в Meteor данные просто записываются в базу, потом же база периодически опрашивается на изменения, причем для каждого клиента. Преимущества их пула запросов в том, что к базе может быть применен любой Mongo-запрос, мы же реализовали обертку для большинства запросов PubSub без необходимости обращения к базе. У нас пока нет очевидных доказательств, но мы ожидаем что PubSub масштабируется намного лучше, чем пул запросов к базе.

API расширений

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

Генерация страниц на сервере и общая маршрутизация

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

Это значит, что вы получаете очень быструю загрузка страниц прямо из коробки. Даже у простых приложений, генерирующих страницу на клиенте, загрузка и рендеринг страницы занимают 1 – 2 секунды. В простых Derby-приложениях событие “onload” вызывается уже через 200 мс. Чем сложнее становится приложение, тем больший наблюдается прирост в скорости за счет серверной прегенерации.

Много крупных компаний, таких как Google, Amazon и Facebook выделяют огромные ресурсы на оптимизацию времени загрузки страниц, поскольку это напрямую влияет на конверсию и на доход. Я чуть не умер в тот день, когда Gmail добавили прогресс бар с индикацией загрузки. Никогда так не делайте.

К тому же, генерация страниц на сервере критически важна для SEO, и обеспечивает доступ браузерам и ридерам в которых отсутствует поддержка JavaScript.

Модуль маршрутизации (routes) в Derby на сервере представляет собой middleware-модуль Express, поэтому вы можете использовать его совместно с другими серверными маршрутами Express, например, для загрузки файлов, и вы даже можете написать множество приложений использующих различные наборы маршрутов на одном и том же Express сервере. Например вы можете написать отдельное админское или мобильное приложение, которое не будет загружать весь код десктопной версии.

В то время, как Derby обеспечивает вас всеми преимуществами скорости и доступности обычного многостраничного приложения, он так же дает вам возможность создать полностью оптимизированное одностраничное приложение, которое может генерироать любой шаблон и маршрут напрямую в браузере. Клиентская маршрутизация позволяет просто отрисовывать переход по ссылке без перезагрузки страницы, вам не потребуется исльзовать какое-либо специфическое API для моршрутизации. Просто установите обычную ссылку на клиенте, и Derby сделает все за вас.

Meteor не имеет этой возможности, хотя они недавно переписали свой шаблонизатор и могут её добавить.

Связывание данных Модели и Представления

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

В противовес этому, Derby использует свой шаблонизатор, основанный на Handlebars. Привязки (bindings) задаются явно, и HTML шаблон требует парсинга для вычисления требующих обновления частей DOM. В отличие от Meteor, в Derby привязки работают двумя способами – когда элементы привязаны, модель автоматически изменяется если пользователь вводит что-либо в поле редактирования, отмечает флажок или выбирает элемент из выпадающего списка. Так же можно либо привязать все данные, либо для оптимизации вручную установить привязки только необходимых данных. Вывод несвязанных данных может быть предпочтителен, если разработчик планирует собственноручно обновлять представление манипулируя элементами DOM.

Обработчики событий DOM

Здесь различия совсем небольшие – Meteor использует CSS-селекторы в шаблонах, а Derby HTML-атрибуты для привязки обработчиков событий. jQuery и Backbone сделали популярными CSS-селекторы, Knockout и Angular используют HTML-атрибуты.

Мы предпочитаем HTML разметку, поскольку труднее понять какой CSS-селектор отвечает за нужные элементы, и часто бывает, что HTML структура меняется, незаметно разрушая CSS-селекторы. С разметкой меньше вероятность, что имена функций будут случайно изменены и будет брошено исключение о том, что необходимая функция не найдена.

В Derby используется инновационный подход к всплытию (bubbling) событий, более интуитивный и понятный в сравнении с традиционным подходом. Вместо всплывания события вверх по узлам DOM до самого корня, Derby останавливае всплытие в тот момент, когда находит первый подвязанный обработчик, и, как и с маршрутами, можно продолжить всплытие событий, вызвав next().

Fibers

Meteor использует Fibers — расширение Node.js, которое делает возможным написание кода, выглядящего синхронно, вместо традиционного для большинства Node-проектов кода, основанного на цепочке обратных вызовов. Кому-то нравится такой способ написания асинхронного кода, кто-то категорически против. Есть много аргументов, как за, так и против.

Вопрос спорный, на данный момент мы предпочитаем стоять в стороне от него. Очень небольшой процент npm-модулей написан в этом стиле, и мы придерживаемся более традиционного подхода в Node.js с обратными вызовами.

Подведем итоги

Можно достичь практически одинакового результата обоими фреймворками. Оба являются мощными инструментами для разработки программ, которые было бы сложно сделать, используя традиционные веб-фреймворки, такие как Rails или PHP.

Derby больше фокусируется на поддержке таких технологий, как обнаружение конфликтов, поддержка оффлайн-клиентов и экстремально быстрой генерации страниц. Мы так же больше сфокусированы на совместимости с другими модулями, существующими в Node.js экосистеме, и лицензионно открыты.

В конечном итоге, мы все мы стараемся создать лучшие инструменты для разработчиков и дух соревновательности лишь породит больше инноваций. Нам приятно видеть другие подходы в таких продуктах, как Meteor, SpaceMagic или Firebase, поскольку мы все учимся друг у друга. В итоге, это приведет к лучшим инструментам, лучшему вебу и к большему удобству для наших пользователей.

От переводчика: За время прошедшее с написания обзора, продукты выросли, в двух словах, что поменялось в Meteor:
1. Метеор тоже теперь выпускается под лицензией MIT
2. Стало возможным использование npm-модулей, правда не напрямую в приложении — сначала их требуется обернуть в обертку от Meteor-пакетов
3. В метеоре появилась нормальная авторизация, аутентификация
4. Что касается серверной генерации страниц, то такая возможность заложена в Spark (промежуточный модуль генерации DOM, находится под handlebars в Meteor), но пока не реализована. Индексирование страниц возможно подключением модуля spiderable — работает и с Google и с Yandex.

Если кто-то может рассказать, что еще поменялось в Meteor или Derby — прошу комментировать.

P.S. При переводе использовалась: Мысли о DERBY VS METEOR

Автор: zag2art

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js