?

Log in

No account? Create an account
November 2016   01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

5. Backbone Sucks

Posted on 2015.07.14 at 01:37
Tags: , , , , ,
Кому-то могло показаться после прочтении предыдущей статьи, что мне "просто нравится бэкбон", или что я считаю его лучшей в мире технологией. Это не так. Мы начали с backbone по двум причинам: (1) многие с него начинают, и (2) это, пожалуй, минимально возможный фреймворк для браузерных приложений.

Так как мы приверженцы "бритвы Оккама" - сравниваться мы будем именно с ним, это как точка ноля. Теперь мы разберемся, с какими именно сложностями сталкиваются люди, использующие Backbone, и умеющие готовить его хорошо. Эти сложности однозначно надо исправлять, и по этим причинам можно выбрать другой фреймворк. А вот то, что в минимально возможном Backbone сложностей не вызывает - для этого нужна очень хорошая аргументация, чтобы это исправлять.

Вообще-то это черновик, написанный в один проход. Но мне сегодня влом вычитывать.


Из того, что мы можем хорошего сказать про Backbone - он быстр. Вот такой простой шаблон, сговняканый на коленке при помощи underscore.js, будучи развернут 100 раз в один и тот же узел DOM при помощи присваивания в innerHTML...
<% for( var i = 0; i < 1000; i++ ){ %>
    <div class="row">
        <div class="col"> a </div>
        <div class="col"> b </div>
        <div class="col"> c </div>
    </div>
<% } %>

...берет на свой разворот примерно 1,5-2 секунды. Полностью идентичный разворот HTML на ультрасовременном ReactJS с элементами искусственного интеллекта обновления DOM занимает 12 секунд. Это с учетом того, что React разворачивает его только один раз, а остальные 99 - вообще пытается не трогать DOM. Из соображений тонкой оптимизации.

React имеет репутацию невероятно быстрого фреймворка, настолько, что отдельные коллеги вставляют его в приложение на AngularJS, "для ускорения рендеринга". Ви таки будете смеятся, да.

Из сходу плохого про бэкбон мы можем сказать то, что в своем исходном виде он не дает совсем никаких сервисов, облегчащих разработчику жизнь. Он дает правила, но почти никак не вознаграждает за следование им. Это почти голая дисциплина. И вот здесь начинается самое интересное. Что же это за сервисы такие? А я вам скажу - их отсутствие очень просто определить в любом фреймворке. Обратите внимание на две простых вещи:
- В чем люди регулярно ошибаются?
- Каким из хороших практик люди по факту предпочитают не следовать?

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

Я вам отвечу - это плохая архитектура, для следования которой надо изменять человеческую природу. Люди по природе не любят прикладывать ум для простейших бытовых ситуаций, и не любят дисциплины. Особенно, глупой дисциплины, не имеющей за собой действительно веской причины. А ваш фреймворк - это не веская причина. Смиритесь с этим.

Итак, к чему у нас склонны люди, работая с backbone.
- По разному разворачивают шаблон во View, кто куда горазд.
- По разному подключают subview, и вообще, это делается настолько тяжеловесно, что они предпочитают по возможности не делать subview, раздувая шаблон.
- В шаблоне, постоянно забывают писать model.get( 'name' ), пишут model.name.
- И не в шаблоне - тоже постоянно путаются, и делают присваивания вместо вызовов model.set( 'attr', value );
- В моделях - не пишут defaults для атрибутов. Ленятся. В итоге, понять, что на самом деле лежит в модели, и что туда попадает во время работы программы - практически невозможно.
- В атрибуте, который содержит массив или объект, меняют что-то, и удивляются, почему не обновился View. А модель не замечает глубоких изменений атрибутов. И не должна. Она замечает только model.set
- Не понимают, как им работать с атрибутами типа Date. С ними творится АД, который слишком красочен, чтобы описать его в рамках данной статьи.

Это не полный список. Я, собственно, только начал. Вопросов у команды, начавшей работать с backbone, возникает слишком много. Давайте, руководствуясь критериями, обозначенными в предыдущих статьях, выделим две главные проблемы:
- В Backbone отсутствует рекурсивный паттерн для View. Нет стандартного способа, как сделать View состоящее из других View.
- В Backbone отсутствует рекурсивный паттерн для Model. Нет стандартного способа, как включать другие модели и сложные объекты типа Date в качестве атрибутов.

Без этих двух рекурсивных паттернов, ничего сложного вы с Backbone не сделаете.

Авторы backbone честно и гордо ответят вам - парни, у нас unopinionated framework. Он дает вам свободу. Вы вольны сами решать, какие у вас будут на них ответы. И они правы. По сути, BackboneJS дает слишком слабые правила, чтобы упорядочить групповую разработку. Это конструктор, основа для конкретных фреймворков, которые вы собираете сами, из Backbone, и его расширений, дополняя это своими правилами.

То есть, Backbone сам по себе - это не ответ на вопрос, как делать браузерные приложения. С ним одним приложения сделать нельзя. Это не инструмент команды, а инструмент архитектора.

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

Этого ни один вменяемый архитектор допустить не может. Поэтому, появились Chaplin и Marionette. Эти две штуковины - два варианта, как сделать из Backbone более-менее сносный фреймворк, который имеет свое мнение по части ответов на вопросы выше.

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

Год назад я был сильно удручен этими другими решениями, и поэтому мы сделали свое (Backbone.NestedTypes). Это хорошая система моделей, по своим возможностям на данный момент перекрывающая не только остальные плагины Backbone, но и системы моделей близких по идеологии фреймворков, таких как EmberJS. Кстати, знаете, например, что model.set в моделях NestedTypes в десятки раз быстрее в Chrome, в сравнении с моделями Backbone? Нет, это не NestedTypes быстр. Это Backbone-модели чудовищно тормозны.

Однако, дело сейчас не в них - давайте просто будем считать, что с моделями никаких проблем нет. И не в databinding - он для backbone также есть в виде плагинов, если вы захотите.

Сейчас я опишу комплекс проблем, нивелирующих основное преимещество Backbone, с которого мы начали - высокую скорость рендеринга UI. И с ней, в отличии от моделей, ничего поделать нельзя. Для этого нам надо будет углубиться в частные случаи, но иначе будет непонятно, в чем общая проблема. Так что приготовьтесь, оно того стоит.

Давайте предположим, что наш UI дизайнер хочет скругленные углы у элементов форм. Понятное желание, человеческое. Проблема только в том, что IE10 не откликается на соответствующий CSS-стиль. И еще, он хочет заменить уродливый скроллбар в элементе select на красивый. И чекбоксы он хочет тоже свои.

В общем, нет проблем. input надо обернуть в div, и уже этому div скруглить элементы. Сразу возникает проблема с фокусом - он хочет, чтобы элемент подсвечивался рамкой, ну ок - это делается неким глобальным скриптом. Главное для вас, как разработчика, в том, что с этого момента вы уже не можете просто писать input, а должны вставлять на его месте нетривияльный HTML.

То же самое с checkbox - вместо простого input вы должны вставлять некий непростой HTML определенной структуры.

И совсем плохо с select, в котором мы хотим подменить скроллбар и цвет фона. Это адово непростой HTML, который уже затруднительно вставлять в шаблон, и которому нужен продвинутый JS.

Если вы будете применять для каждого такого контрола backbone subview (а subview делать все еще достаточно напряжно в том числе и с Chaplin и Marionette) - вы застрелитесь на второй день. Разработчики ошибаются. Нечеловеческая дисциплина. Не вариант. И вы ищете выход.

Выход называется Web Components, позволяющий определять свои HTML-тэги. Но это новый стандарт, который браузерамм не поддерживается, и поэтому, вы находите Polymer, и чуть позже - x-tag. Та-да!

И тут вы вдруг понимаете, что ваши кастомные тэги разворачиваются асинхронно. То есть, после render, они не готовы к работе. Ну не беда, вы заменяете innerHTML на xtags.innerHTML, чтобы избежать race conditions. Та-да!

И вообще, эти Polymer - это очень модно. Вы на острие технологии. Круто. Та-да!

Только штука в том, что эти кастомные теги разворачиваются DOM-манипуляцией. И это происходит ацки медленно. На самом деле, вы получите скорость рендеринга хуже, чем в модных медленных фреймворках. Она будет настолько медленной, что вы будете замечать это невооруженным глазом. Упс.

Если проблему обобщить, то...
рекурсивный паттерн для subview в Backbone крайне неудобен на микроуровне, что не позволяет вам сделать библиотеку виджетов

А также...
применение Web Components приводит к деградации производительности, нивелируя единственное неоспоримое преимущество Backbone - скорость рендерига

И даже если бы нет, то...
работая в рамках шаблона, вы не можете передавать custom tags сложные объекты, например - модель
Только через текст. Что идиотизм, и очень сильно ограничивает вас в возможностях.

Другими словами, рекурсивный паттерн subview, в условиях того, что view состоит из текстового шаблона и подключения subview на javascipt - крайне неудобен, и значительно усложняет проектирование

Сейчас мы могли бы рассмотреть AngularJS. Но есть одно обстоятельство, которое освобождает нас от необходимости это делать. Дело в том, что уже анонсирован Angular 2.0, который будет обратно не совместим с Angular 1.x, а посему - мало кто в отважится сейчас начинать проект на Angular.

Но если вы настаиваете - в Angular ситуация чуть лучше, так как вы можете определять "директивы", однако наличествует разница между "контроллером" и "директивой", и элемент UI так же расщеплен на HTML и JS. При этом, полностью отсутствует сервис моделей. Как и принципиальное преимущество перед Backbone, которое бы заставило вас выкинуть написанный с ним код. Two-way databinding им не является, он несложно делается и в backbone.

Поэтому, мы рассмотрим Ember, ExtJS, и React. Все они решают обозначенную проблему. Каждый по своему.

Comments:


brightist
brightist at 2015-07-13 23:14 (UTC) (Link)

спасибо

LiveJournal
livejournal at 2015-07-14 06:26 (UTC) (Link)

5. Backbone Sucks

Пользователь om8 сослался на вашу запись в своей записи «5. Backbone Sucks» в контексте: [...] Оригинал взят у в 5. Backbone Sucks [...]
Dima Kuchin
kuchin at 2015-07-14 06:51 (UTC) (Link)
в Angular есть очень хороший плагин restangular, который используют для моделей. ещё часто берут angular-ui-router
Осман Бинеев
sober_space at 2015-07-14 15:56 (UTC) (Link)
>>>Вот такой простой шаблон, сговняканый на коленке при помощи underscore.js, будучи развернут 100 раз в один и тот же узел DOM при помощи присваивания в innerHTML...

Как бы это померять в riot.js например? Я просто не понял. Более полный код можете привести?
Gaperton
gaperton at 2015-07-15 06:50 (UTC) (Link)
Осман Бинеев
sober_space at 2015-07-15 08:27 (UTC) (Link)
Спасибо, теперь яснее. Я просто из любопытства соорудил нечто подобное riot, тупо-глупо ворочая DOM, у меня такая операция займет 120 сек :) Но я не пытался оптимизировать никак.
alekciy
alekciy at 2015-07-16 19:25 (UTC) (Link)
Задам вопрос который в подобном посте не может быть не задан.
Если бы была сейчас возможность выбрать фрейворк/библиотеку на что бы пал выбор?
Gaperton
gaperton at 2015-07-16 21:11 (UTC) (Link)
Легко. То, что выбираю сейчас - самое лучшее. View-layer - ReactJS. Модели - NestedTypes.

Но если бы я выбирал полтора года назад - выбрал бы то, что выбрал. Backbone, но вместо Chaplin - Marionette. У меня тогда была команда PHP-шников, и два месяца до выставки, на которой надо показать прототип нового продукта. Без вариантов.

И мы показали прототип, такой, что выставка в Вегасе ахнула. Так что все было правильно.

Edited at 2015-07-16 09:13 pm (UTC)
Gaperton
gaperton at 2015-07-16 21:16 (UTC) (Link)
Только смысла в этом ответе немного, пока я не объяснил почему.

Если вы хотите использовать мой опыт, вам важно не что, а почему. Зная "почему" вы можете сделать свой выбор, а не мой - выбор обусловлен ситуацией, а у вас она своя.

А без почему - какая нафиг вообще разница, кто какой выбор делает.

Edited at 2015-07-16 09:23 pm (UTC)
alekciy
alekciy at 2015-07-17 06:18 (UTC) (Link)
Это я отлично понимаю. Я в итоге тоже склонился в сторону ReactJS. В том числе и поэтому интересно, какой выбор делают другие.

Если не секрет, что за прототип?
Gaperton
gaperton at 2015-07-16 21:29 (UTC) (Link)
И то, что я пытаюсь донести в этих постах - вовсе не какой Фреймворк "лучший". А показать некие более общие принципы, как я их оцениваю. И научить это делать, тех, кто хочет.

В этом смысле, что выберу я - не так важно. Что и почему выберете вы? Напишите об этом статью.

Edited at 2015-07-16 09:31 pm (UTC)
oceania_delive
oceania_delive at 2015-08-21 10:24 (UTC) (Link)
ПРИВЕТ)))
Добавила Вас в друзья ))
Не знаю насколько Вам это будет интересно, а вдруг...
Ищу созвучных людей, тех кому так же интересно что-то понимать в жизни и искать новые повороты в казалось бы обычных ситуациях каждого дня.
Найти другие способы общения и взаимодействия с людьми…
Интересов у меня очень много и перечислять их здесь, наверное, не имеет особого смысла.
Если появится желание зайти в гости, то буду очень рада )))
Previous Entry  Next Entry