Обзор JS-фреймворков. Путешествие через джунгли JavaScript MVC. Ч. 2
Содержание первой части:
■ Что такое MVC или, лучше сказать, MV*?
■ Когда нам нужен MV*-фреймворк JS?
■ Где же мы будем нуждаться в MV*, а где нет?
■ Проблема выбора: слишком много вариантов?
■ TodoMVC: общее приложение для обучения и сравнения
■ Предложенные нами критерии выбора фреймворка
■ Dojo и усложнение фреймворков на JavaScript
■ Коллекция TodoMVC (фреймворки, на которых сделаны реализации тестового приложения Todo)
■ Какой фреймворк когда следует использовать?
Для сужения круга поиска фреймворков хотим предложить выбор фреймворка высокого уровня по признакам, которые, надеемся, помогут отобрать несколько вариантов для проб.
Я хочу нечто гибкое, с решениями в стиле минимализма для разделения задач в моем приложении. Оно поддерживает постоянное подключение и REST-синхронизацию, модели, представления (с контроллерами), обмен данными, управляемый событиями, шаблонизацию и навигацию (по якорям в URL). При изменении модели немедленно изменяется представление. Я хотел бы сам в должной мере управлять архитектурой. Идеально, если решение использовалось у многих больших компаний для нетривиальных приложений. Поскольку у меня может получиться что-то сложное, я хотел бы видеть активное сообщество вокруг фреймворка, которому можно всегда попытаться поставить не слишком простые вопросы (Marionette, Chaplin, Aura, Thorax). Идеально иметь также инструменты сборки (grunt-bbb, brunch). Используйте Backbone.js.
Я хочу основу приложений десктопного уровня для Сети. Этот фреймворк должен быть высокоуровневым, модульным, MVC, без потребности собирать всё вместе вручную, поддерживать персистентность (постоянные объекты с метафорой файла, устройства), вычисляемые свойства и автообновление шаблонов. Это нужно для интеллектуального управления состояниями вместо ручной настройки, совместимость с многими смежными фреймворками. Это должно быть с хорошей документацией, с шаблонами пользования, инструментами сборки (ember.gem, ember for brunch). Используйте Ember.js.
Я хочу что-то легковесное, с подключением шаблонов на лету, навигацией, интеграцией с основными библиотеками (типа jQuery и Dojo) и быстрое, с поддержкой наследования компонентов MVC, что может быть ещё не отработано на крупных приложениях, но должно быть. Идеально, если сделано людьми с опытом создания сложных приложений. Используйте CanJS.
Я хочу оболочку декларативного стиля, использующую View для сбора данных о поведении пользователя через кастомизацию HTML и компонентов по правилам приложения. С простой поддержкой тестовой системы, с URL-навигацией и разделением задач через MVC или его вариант. Это даёт кастомизированный подход к смежным библиотекам, делающим компиляцию HTML, чтобы строить собственный DSL (предметно-ориентированный язык) в HTML. Это нужно для таких элементов сетевой платформы как веб-компоненты; и ещё надо иметь инструменты сборки (angular-seed). Используйте AngularJS.
Я хочу хорошую основу для объёмных приложений, с проверенной и отработанной инфраструктурой виджетов, модулей с постзагрузкой; возможно — с асинхронной и простой интеграцией с CDN-ами, с выбором модулей и виджетов (графики, диаграммы, таблицы, и т.д), с хорошей мультиязычностью (i18n, l10n). Нужна поддержка ООП, MVC и сборщик из блоков (модулей) для создания сложных архитектур. Используйте Dojo.
Я хочу что-то оптимизированное под работу с расширениями YUI. С поддержкой моделей, представлений и навигации, что сделало бы простым написание приложения с разными способами отображения информации, с переходами вариантов отображения из одного в другой и подобное. Это — полное решение с виджетами/компонентами, со способностью описать архитектуру приложения. Могут быть инструменты сборки (yuiproject), но с возможной заменой на другие. Используйте YUI.
Я хочу кое-что простое для асинхронных интерфейсов и не имеющее зависимостей, гибкое при сборке приложения, с поддержкой MVC, событий, навигации, оставаясь при этом компактным. Оптимизированное для CoffeeScript, с подробной документацией. Используйте Spine.
Я хочу инструмент построения сложных динамических UI на основе модели данных и декларативного стиля связывания. Для обновлений UI при изменениях модели, используя двунаправленное связывание и поддержку зависимостей через отслеживание данных. Я должен быть в состоянии использовать это с любым фреймворком или даже с готовым приложением. Нужно иметь встроенную шаблонизацию и легкую расширяемость. Используйте KnockoutJS.
Я хочу что-нибудь для простых веб-приложений и сайтов. Я не ожидаю там иметь много кода, поэтому он не будет сильно мешать. Кроссбраузерность для сосредоточения на задаче. Легкая обработка событий, взаимодействие с удаленными сервисами, расширяемость и огромный набор плагинов. Используйте jQuery.
■ Что разработчики думают о самых популярных фреймворках?
Как часть исследования по MV*-фреймворкам для TodoMVC и этой статьи, мы провели опрос среди разработчиков. Какой фреймворк они чаще используют, и главное, почему бы его порекомендовали? Что они почувствуют, если бы этого фреймворка не было в проекте?
Вот некоторые самые интересные ответы:
Ember.js
«за»: комбинация живых шаблонов и связанных (observable) объектов изменила способ работы с JavaScript. Вначале он может показаться несколько замороченным, но работу заканчиваете с хорошим разделением ответственности в коде. Я обнаружил, что как только у меня все описано, добавление довольно сложных особенностей занимают пару строк. Без Ember эти те же особенности были бы адски сложными в реализации.
«против»: Ember, всё-таки, должна достигнуть версии 1.0. Много вещей ещё в движении, таких как маршрутизатор и Ember data. Новый вебсайт очень полезен, но нет такой документации для Ember, как у других фреймворков, особенно Backbone. С таким количеством магии в фреймворке это немного страшно. Если что-то ломается, вы не сможете выяснить точно, почему. Да и сообщения об ошибках в Ember часто неточны.
«за»: ключевые факторы:
a) Особенности, которые позволяют мне избегать массы шаблонного кода (привязки, вычисляемые свойства, слой представления с хорошим управлением).
b) команда разработки. Я — рубист и знаю, чего стоит Yehuda Katz. Я доверяю парню =).
«против»: документация. Действительно грустно, что у Ember нет хорошей документации, обучающих программ, скринкастов как у Backbone, Angular или других фреймворков. Прямо сейчас мы просматриваем код, ища документацию, которая не идеальна.
«за»: соглашение по конфигурации. Ember принимает много мелкой работы за вас; это — безусловно, самый легкий способ построить приложение на стороне клиента в наши дни.
«против»: порог обучения. Отсутствие массы руководств для начинающих, которые существуют для других фреймворков типа Backbone, это частично из-за маленького сообщества, но я думаю, что больше из-за подвижности кода в подготовке к версии 1.0.
«за»: простота связывания, плотная интеграция с управлением, легкая модульность в моем собственном коде.
«против»: я хотел бы иметь устойчивую интеграцию с Ember data и интегрированную поддержку localStorage, синхронизированную с REST API — всё это несбыточные мечты.
Backbone.js
«за»: простота — только 4 основных компонента (Коллекция, Модель, Представление, Маршрутизатор). Огромное сообщество (экосистема) и много решений на StackOverflow. Фреймворки высшего порядка типа Marionette или Vertebrae — с большим количеством умного кода внутри. Кому-то нравится «низкий уровень» — надо написать много шаблонного кода, но получить сделанную под себя архитектуру.
«против»: мне не нравится наследование — копируется содержание родительского объекта в новый. Нужно прототипное наследование. Иногда я не читаю «real world scenarios» в примерах из доков. Приходится делать большое исследование после чтения туториала с TODO, чтобы выяснить, как построить чуть более сложное приложение.
Я не использую официальную поддержку AMD в проектах от DocumentCloud (Backbone, Underscore) [но это не проблема с новым методом shim() в RequireJS 2.0].
«за»: после начального головоломного изучения работы Backbone всё это оказывается крайне практично. Практичность — в хорошо поддержанной, легковесной и постоянно обновляемой библиотеке в правильном окружении. Дружественная поддержка Underscore, jQuery/Zepto, инструменты, с которыми работало бы большинство проектов из моей студии.
«против»: количество обучающих программ о том, как работать с Backbone — разное для разных версий. Я попросил других разработчиков взглянуть на Backbone, и они написали бы код для версии 0.3. Неосознанно. Пока нет проблем, Backbone может это исправить, но это, пожалуй, главное неудобство, с ней связанное.
Теоретически, это же можно сказать о чём угодно, но с Backbone это периодически повторяется на моих глазах. Черт, я даже видел статью месячной давности, где используются древние методы и приёмы.
Безотносительно моего отношения к фреймворку, именно эта проблема могла бы быть исправлена сообществом разумными правками и подходами. Для меня Backbone именно поэтому заслуживает уважения, из-за поддержки сообщества.
«за»: обеспечивает только минимальную абстракцию без необоснованных ограничений — даёт возможность собирать проект по потребностям.
«против»: я переписал бы или удалил Backbone.sync. Он построен для протокола HTTP и плохо приспосабливается к особенностям WebSocket.
«за»: чрезвычайно легко начать работать, предлагает хороший путь ознакомления. Он сравнительно хорошо кастомизируется, и есть тонны других людей, использующих его, которые могут помочь.
«против»: факт, что нет никакого связывания представления по умолчанию (хотя можно задать его). Обновление всего представления, когда меняется единственное свойство, неэкономично.
У REST API есть много плюсов, но есть трудности при большом количестве записей (по общему признанию, проблема с REST — её собственная, но все еще остаётся) и неприятные проблемы в получении различных схем URI для работы с различными типами операций.
AngularJS
«за»:
a) Двунаправленное связывание данных — очень сильный подход. Вы думаете больше о вашей модели и состоянии вместо организации ряда событий. Модель — единственный источник правды.
b) Скорость. AngularJS легко загружаем. Он шаблонизирует построением узлов вместо innerHTML, что, по идее, производительнее.
c) Если вы ориентируетесь на современные браузеры и/или достаточно бережливы, можете обойтись без jQuery.
«против»: я хотел бы уметь указывать переходы состояний UI, изменяемые моделью. А именно, элементы, использующие ng-show / ng-hide, я хотел бы скрывать или сворачивать простой декларацией.
«за»: Он очень интуитивен, с отличной документацией. Мне нравится их подход к связыванию данных, HTML, основанный на Views, вложенные окружения (scopes). Я переходил от Backbone/Thorax к Angular и никогда не оглядывался назад. Новое расширение (addon) Chrome Batarang интегрируется с Chrome Developer’s Tools и даёт доступ в реальном времени к структурам данных Angular.
«против»: хотелось бы иметь встроенную поддержку функций типа drag-n-drop, но это может быть добавлено через внешние компоненты, доступные на GitHub. Хотел бы видеть больше сторонних компонентов, подходящих для повторного использования. Я думаю, что это — только вопрос времени для экосистемы вокруг AngularJS, чтобы стать более зрелым, и затем они будут доступны и разнообразны, как в сообществах типа jQuery.
«за»: Он решительно уменьшает шаблонный код, позволяет повторно использовать код через компоненты, расширяет синтаксис HTML так, чтобы много сложных возможностей стали так же просты, как написание атрибутов в HTML, и крайне легко тестируемыми благодаря полному описанию зависимостей.
Вы можете написать нетривиальное приложение без jQuery, без непосредственного управления DOM. Сделать такой инструмент — настоящее мастерство.
«против»: еЕго порог изучения несколько выше, чем у Backbone (который весьма легок для мастера), но результат стоящий. Документация могла бы быть лучше.
KnockoutJS
«за»: я не всегда его использую, но KnockoutJS великолепен для одностраничных приложений. Очень легкая подписка на изменения объектов; намного лучше API для так называемой в Backbone “collection views”, используя наблюдаемые (observable) массивы. И пользовательские события на наблюдаемые объекты для эффектов, и т.д.
«против»: чувствется, что API трудно расширить; я, вероятно, предпочел бы выбрать Backbone на больших приложениях (в том числе, из-за поддержки сообщества).
«за»: мне нравится механизм связывания данных и его удобное использование. Особенно нравится, как заменили шаблоны на привязывание (binding) управляющей логики.
«против»: плохо, что нет никакого руководства по лучшим практикам со структурой приложения. Кроме наличия View Model, фреймворк не помогает вам в описании хорошо структурированной View Model. Это очень легко закончится большой неуправляемой функцией.
Dojo
«за»: синтаксически — Dojo очень простой. Это хорошо для динамических и устойчивых сборок, с начальным файлом подгрузчика, обычно размером 6 КБ. Это AMD-совместимый (допускающий постзагрузку), что делает его очень компактным, и приходит «из коробки» с тонной расширений, от базовой работы с DOM до сложного SVG, VML и canvas. Система виджетов Dijit великолепна в простоте использования и способности к расширению. Это очень хорошо подобранный и полный набор инструментов.
«против»: dojo/_base/declare функциональность — не 100%-ый строгий управляемый инструмент, сейчас есть некоторые накладки из-за обратной совместимости, хотя это в основном исправится в Dojo 2.0.
«за»: хХорошие компоненты: табы, таблицы для данных, менеджер форм… Одинаково для всех браузеров. Работающий AMD. Легкие тесты с имитаторами данных. Хорошо интегрируется с другими фреймворками благодаря AMD (я буду интегрировать с JMVC).
«против»: проект настроен по умолчанию для вышедших из моды компонентов. Не полностью html5. Документация — так себе. Плохая система шаблонизации (никакого связывания «на лету»).
YUI
«за»: YUI3 — модульная и типа «делай-что-хочешь» библиотека компонентов, которая включает все достоинства Backbone и даже больше. Она, на мой взгляд, даже улучшает некоторые концепции Backbone, разделяя некоторые вещи (например, атрибут — отдельный модуль, который может быть подмешан в любой объект — «модуль» события может быть тоже подмешан).
«против»: я хотел бы видеть, что YUI3 поддерживает автоматическое связывание (wiring) из Ember. Думаю, что это действительно большое достижение для Ember; в остальном, вижу YUI3 превосходной библиотекой компонентов, где можно подобрать то, что требуется. Хочу видеть улучшенную AMD-совместимость загрузчика модулей. Он сегодня работает хорошо, но было бы лучше, если я мог бы начать новые проекты на модулях AMD и вставлять в компоненты YUI3 и другие вещи третьих сторон, которые тоже используют AMD.
JavascriptMVC
«за»: Имеет все инструменты «из коробки», остаётся только запустить команды и начать сборку. Я использовал 6 месяцев, и это было действительно хорошо.
«против»: единственная вещь, которую я хотел бы видеть — ускорение развития следующей версии. Разработчики знают о проблемах и решают их, но процесс мог бы быть другим — не месяцы на некоторые проблемы, которые я хочу исправить и отправить решение — тогда я мог бы сделать патч и пулл-реквест.
Maria
«за»: поскольку Maria — фреймворк реализации чистого MVC, она сосредоточена на том, чтобы быть фреймворком MVC. Не больше и не меньше. Всё строго и просто.
«против»: немного больше документации, чем написано в исходном коде плюс несколько тесткейсов. Не помешал бы туториал, показывающий основы реального использования MVC в Maria.
Cujo.js
«за»: для реальных приложений почти никогда не бывает достаточно MV* из коробки, и самый важный инструментарий часто вне коробки. С cujo.js — вы определяете коробку.
Да, cujo.js имеет высокоуровневые MV*-подобные возможности для создания Views, моделей, контроллеров, и т.д., но каждое приложение различно, и никакой фреймворк не может быть 100%-ым решением. Вместо попытки угодить всем, cujo.js даёт в том числе и низкоуровневые инструменты, настройку архитектуры и богатую систему плагинов, которая может даже объединить и расширить другие MV*-фреймворки.
Создайте архитектуру, лучше всего подходящую под ваше приложение, вместо укладывания приложения в рамки чьей-то архитектуры.
«против»: широкие массы джаваскриптеров совершенно неподготовлены и не обучены развитию крупномасштабных приложений. Большинство из них даже не знает о существовании паттернов проектирования и архитектур.
Так как cujo.js так отличается от других, он нуждается в нечто большем, чем просто отсылка к API и примерам кода. Без обучающих программ, образовательных материалов, и развивающих примеров cujo.js будет выглядеть странным и угнетающим для ненамётанного глаза, но скоро ожидается документация.
ExtJS
«за»: думаю, ExtJS работает лучше всего вместе с Ext Designer. Он отделяет себя от других GUI-фреймворков, позволяя непрограммистам макетировать UI, а программисты заполняют пробелы. Сравнение с фреймворками MVC типа Backbone, на мой взгляд, неправомерно: сила ExtJS — в создании богатого GUI, а не легковесных веб-приложений.
Для коммерческих, удалённых офисных, rich-приложений думаю, что ExtJS остается лучшим выбором, когда дело доходит до решений на JavaScript (кроме GWT и т.д). Для публичных веб-приложений я имею кое-что другое, дающее мне больше контроля над разметкой (и идеально отрабатывающее greaceful-деградацию).
«против»: у него высокий порог вхождения, выше многих других современных структурных (structural) фреймворков. Можно сказать, что если вкладывают капитал в ExtJS для долгосрочных разработок, время на изучение окупится, однако думаю, что решения типа этого должны стремиться минимизировать время обучения команды.
«за»: думаю, что особое свойство ExtJS 4 — что он бросает вас в понятия MVC и требуемую структуру файлов с места в карьер. Начальные обучающие программы Dojo, говорят главным образом об улучшении существующих сайтов, а ExtJS предполагает, что вы начинаете делать сайт с нуля.
ExtJS действительно, вообще не показывает, что вы имеете дело с HTML. Библиотека компонентов достаточно богата, чтобы долго работать, не касаясь HTML при построении приложения.
Было бы интересно увидеть, как это уживается вместе, если веб-компоненты начнут полнее поддерживаться. Это наконец, позволило бы управлять DOM без боязни поломки виджетов или необходимости становиться внутреннему состоянию Вашего приложения непоследовательным.
«против»: лицензирование считают ограничительным и оно трудно понимаемо некоторыми. Больше людей вложило бы капитал в ExtJS, если бы было понятнее, каков задаток и каковы долгосрочные затраты при использовании. Таких проблем нет с некоторыми другими структурными инструментами, но это, вероятно — не повод для беспокойства в условиях большого бизнеса.
«за»: ExtJS — фантастический пакет для быстрого построения RIA для интранета. Я, например, люблю писать с HTML и JavaScript, и для меня есть большое удовлетворение копаться на этом уровне. Хотя ExtJS позволяет чувствовать, что вы не работаете с HTML, он, всё же, даёт много рычагов управления документом, особенно при создании сложного UI.
«против»: Тем не менее… я полностью соглашусь, что это очень тяжелая оболочка, и я не думаю, что порекомендую её для фронденда в вебе. Моя самая большая претензия к пакету, что это — бОльшая головная боль для тестов, чем я мог представить. Наш тестер закончил это тем, что переключился на Sikuli, потому что попытки работать в Selenium становились слишком большим сражением.
Batman
«за»: у него есть большая и удобная система просмотра связываний. Игры с Рельсами очень приятны и это — все требования по конфигурации.
«против»: документация могла быть намного лучше, и я чувствую, что Shopify не будет добавлять новые возможности, хотя говорят, что будут.
■ Не бойтесь экспериментировать
Хотя вряд ли разработчику надо учиться использовать больше этой горстки, я поддержу исследование незнакомых вам фреймворков. Там воз (с маленькой тележкой) интересных фактов и техник, которым между делом можно обучиться.
У меня был случай: я нашёл, что Batman.js требует минимум самописного кода в реализации. Я не постоянный CoffeeScript-щик и не пользователь Batman.js, но результат дал мне пищу для размышлений. Возможно, что я смогу взять часть исходников инструмента и использовать у себя. Или, возможно, в будущем проекте я просто использую Batman.js, когда он обрастёт сообществом и поддержкой.
Независимо от того, будете ли использовать увиденное и построенное за день, вы получите больше знания о том, что там находится и как с ним работать.
■ Выход за пределы понятий MV*
Хотя семейство MV* паттернов весьма популярно для структурирования приложения, они ограничены в том, что нет различия в разновидностях слоёв приложений, связи между разными Views, нет сервисов, выполняющих работы или прочего. Разработчики могут оказаться перед необходимостью исследовать другие паттерны.
Мы обратились к разработчикам, которые шли дальше MVC, проникали в суть требований с их собственными паттернами или расширениями существующего.
Мне однажды понадобилось подобие паттерна Компоновщик. Я заметил, что разработчики в приложениях Backbone поняли, что была потребность в объекте, который координировал бы различные части приложения. Разработчики долго пытались решить это использованием элемента Backbone (например, Представления), даже когда в нем нет потребности. Вместо этого я исследовал потребность в приложении Initializer.Derick Bailey — автор Marionette
Я нашел, что MVC действительно не имеет способа работы с областями страницы или приложения. Суть управления областью — вы определяете видимую область экрана и задаёте самые общие данные о нём, не зная, какое содержание будет показываться во время выполнения.
Я создал решения для управления областями, инициализации приложений и с другими функциями в моем расширении проекта Marionette. Это — одно из многих решений, которые расширяет фреймворк (создаёт архитектурный паттерн) для разработчиков, сталкивающихся с необходимостью строить действительно сложные одностраничные приложения.
Есть даже приложение Marionette TodoMVC, доступное для желающих сравнить стандартное приложение Backbone с тем, которое работает вне обычного MV*.
Большая часть задач решается через JavaScript MVC, но некоторые решиться просто не могут. Например, приложение получило стороннее API во время выполнения, но не дало информации, как будут структурированы данные.Dustin Boston — соавтор Aura
Я потратил почти год, пытаясь решить ту самую проблему, но в итоге пришёл к выводу, что втискивание этого в MV* было нежизнеспособно. Я имел дело с «аморфной моделью», и это — то, из-за чего всё развалилось. Другими словами, если у вас нет четкой модели, самые современные фреймворки JavaScript вам не помогут.
Вот здесь появились паттерны ядра J2EE. Я про них узнал, читая «PHP Objects, Patterns, and Practice», Matt Zandstra, и хорошо, что так случилось! Паттерны J2EE в основном описывают в общих чертах процесс, управляемый запросом, когда URL управляет поведением приложения.В двух словах, запрос создаётся, меняется, а затем используется для отрисовки представления.
Я подробно остановился на своём опыте с управляющими запросами и паттернами J2EE для всех, кто хочет научиться большему.
■ Заключение
При том, что есть несколько способов структурировать данные веб-приложения, важно с должным вниманием отнестись к выбору: потратить время на полную оценку вариантов, чтобы прийти к жизнеспособному и ремонтопригодному коду. Разнообразие фреймворков помогает инновации результатов, а множество похожих инструментов создает только шум.
Проекты типа TodoMVC помогают сузить выбор инструментов до самых интересных или удобных для конкретного проекта. Помните, что не надо торопиться с выбором, не чувствуйте себя принужденными, выбирайте то, что лучше соответствует потребностям.
Экспериментирование с фреймворками ознакомит вас со способами решения общих проблем, которые помогут вам программировать лучше.
Благодарю моего коллегу, участника команды TodoMVC Sindre Sorhus за его помощь с поправками и вычиткой этой статьи.