или как будущее декодирует прошлое.

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

Среди стеков я несколько раз встречал Bitches Brew Майлза Дэвиса. Я знал, что этот альбом должен был быть важным, но обычно это заставляло меня чесать голову и выключать его в пользу какой-нибудь яванской музыки гамелана или, может быть, Master of Puppets Metallica.

Перенесемся на пару лет вперед. На сцену вышли Медески Мартин и Вуд.

Я слушал «Пятничный полдень во Вселенной» несколько десятков раз. И вуаля, когда я в следующий раз послушал Bitches Brew, что-то щелкнуло. Как будто я, наконец, "понял" после того, как испытал производную работу, которая представила дистиллированную сущность своего предшественника. Чтобы прояснить это, я полагаю, что MMW - это эволюционный результат BB. Ни BB, ни MMW.

Хорошо, это все, что касается музыкальной части этого поста. Извините. Перейдем к программистам.

Недавно у меня была возможность вернуться обратно в Backbone после года или около того, работая с React. Опыт был великолепен. Так много тонкостей библиотеки, которые я раньше полностью упустил, на этот раз просто щелкнул. На самом деле я обнаружил, что применяю уроки того, как делать что-то «способом React», к своему Backbone-коду.

Чтобы сделать связь между моими комментариями о музыке и кодом столь же тонкой, как летающий отбойный молоток (спасибо за выражение, Карл!), Я говорю, что React - это квинтэссенция предшествующего уровня техники, такого как как Backbone, и погружение в него помогло мне понять и лучше взаимодействовать с его предшественником, Backbone, точно так же, как прослушивание целой группы Medeski Martin и Wood помогло мне понять и оценить Bitches Brew.

Вот фрагмент кода, который демонстрирует мой стиль «первого восхождения» Backbone эм… доблесть ?:

к сведению: все мои старые образцы кода Backbone ссылаются на Goldstone Server, увлекательный проект, над которым меня наняли для работы с Solinea, который использовал d3 для создания многофункциональной интерфейсной панели для мониторинга и управления OpenStack. Я провел два года в качестве единственного разработчика JavaScript в проекте, полностью владея фронтенд-разработкой и, в конечном итоге, стал ведущим разработчиком.

var NewPasswordView = Backbone.View.extend({
  initialize: function (options) {
    ...
    this.addHandlers();
  },
  addHandlers: function () {
    var self = this;
    $('.login-form').on('submit', function (e) {
      e.preventDefault();
      var $password = $('#password');
      var $confirm_password = $('#confirm_password');
      if ($password.val() !== $confirm_password.val()) {
        goldstone.raiseWarning("Passwords don't match.");
      } else {
        self.submitRequest()...
      }
    });
  }
  ...
});

Почему это пахнет:

  • Метод addHandlers работает для создания прослушивателя событий, но полностью упускает возможность использовать встроенный events хеш, который Backbone предоставляет для этой цели.
  • Этот шаблон также требует использования очень злонамеренной ссылки self, чтобы сохранить контекст вызова при вызове submitRequest
  • Это создает прослушиватель событий с .on, который будет сохраняться даже после того, как это представление будет уничтожено, создавая утечки памяти, если не было принято меры для удаления активных слушателей с .off. Оглядываясь назад на свой исходный код для этого представления, я вижу, что этого не было сделано8. Довольно тривиально для формы изменения пароля, которая вряд ли когда-либо будет использоваться, но плохой шаблон для входа, поскольку в часто загружаемых представлениях каждый экземпляр создает новый набор слушателей, которые будут продолжать добавлять к вашей проблеме утечки памяти.

Как это можно улучшить:

var NewPasswordView = Backbone.View.extend({
  initialize: function (options) {
    ...
    // no longer needed --> this.addHandlers();
  },
  events: {
    'submit .login-form': 'handleSubmit'
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var $password = $('#password');
    var $confirm_password = $('#confirm_password');
    if ($password.val() !== $confirm_password.val()) {
      goldstone.raiseWarning("Passwords don't match.");
    } else {
      this.submitRequest...
    }
  }
...
});
  • теперь хэш событий регистрирует слушателя для события отправки, нацеленного на элемент .login-form.
  • в handleSubmit, submitRequest можно вызывать без использования self для ссылки на правильный контекст выполнения.

Помимо ряда встроенных библиотечных методов, которые я игнорировал, более захватывающее развитие, которое можно наблюдать, и основная тема этой статьи - это переход от «монолитных представлений» к более мелким компонентам, которые появились после работы с React, и возвращение в Backbone.

После 18 месяцев работы над Goldstone, последние 6 месяцев с Solinea я потратил на разработку клиентского микросервиса для проекта SAAS с React / Redux. И с тех пор, последний год, я работал над личными проектами с React, и мне стало комфортно работать с библиотекой. Однако недавно меня наняли для выполнения клиентского проекта (который я добавил в свой профиль на github по этой ссылке), для которого идеальный процесс разработки должен был поддерживаться возвращением к Backbone (ах!) . Я не нахожу очень много упоминаний о людях, возвращающихся в Backbone после освоения React, но в этом случае большая часть разработки приложения заключалась в отображении коллекций данных в различных конфигурациях, чтобы помочь в создании годового календаря для Школьная система Нью-Йорка. Встроенные в Backbone функции сбора данных идеально подойдут для этой задачи, а функция View более чем адекватна.

Проверяя большинство моих Backbone Views в проекте Goldstone, они, как правило, разрастаются, охватывая функциональность для нескольких элементов на странице. Потратив некоторое время на работу с React и попрактиковавшись в Thinking In React, при возвращении к Backbone стало естественным начинать составлять функциональность из более мелких индивидуальных представлений, используя преимущества событий Backbone и сохранять состояние в моделях вместо использования такие вещи, как $ ('. foo'). val (). Другими словами, практика:

«Извлеките правду из DOM» - Джереми Ашкенас (создатель Backbone.js)

Вот пример (синтаксис ES6):

export const EventsView = Backbone.View.extend({
  initialize() {
    this.collection = database;
    this.filterChooser = new FilterChooser();
    this.individualEventBlock = new IndividualEventBlock({
      model: this.filterChooser.model,
      collection: this.collection
    });
    this.editModal = new EditModal({
      collection: this.collection
    });
    this.addModal = new AddModal({
      collection: this.collection
    });
    this.render();
    this.listenTo(this.collection, 'updateEditModal', this.handleUpdateEventModal);
  },
  onClose() {
    this.filterChooser.close();
    this.individualEventBlock.close();
    this.editModal.close();
    this.addModal.close();
  },
  render() {
    this.$el.html('');
    this.$el.append(addNewEventButton());
    this.$el.append(this.filterChooser.el);
    this.$el.append(this.individualEventBlock.el);
    this.$el.prepend(this.editModal.el);
    this.$el.prepend(this.addModal.el);
    return this;
  },
  events: {
    'click .addEvent': 'handleAddEventModal'
  },
  handleAddEventModal() {
    this.addModal.trigger('updateAddView');
  },
  handleUpdateEventModal(model) {
    this.editModal.trigger('updateEditView', model);
  }
});

Отметить:

  • Это представление верхнего уровня, которое отображается при переходе к /events. Его основная задача - создать экземпляры дополнительных компонентов, которые будут отображаться в представлении, и настроить пару слушателей. Слушатели устанавливаются с использованием хэша events или с использованием синтаксиса listenTo, который позволяет очистить слушателей, когда представление закрывается маршрутизатором.
  • Для тех, кто знаком с работой с React, вы, вероятно, знакомы с концепцией хранения вашего состояния где-то в восходящем направлении, чтобы оно было доступно для подкомпонентов ниже по дереву компонентов. В функции initialize я использую то, что ссылки переменных на подкомпоненты находятся в одном месте, чтобы при необходимости разделять состояние между компонентами. Например: присвоение модели из filterChooser индивидуальному блоку событий. В IndividualEventBlock настроен прослушиватель, так что при изменении модели фильтра индивидуальный блок событий повторно визуализируется.
  • Я добавил close метод в Backbone.View через прототип. Он вызовет необходимые функции, чтобы отвязать слушателей. [см. примечание 1 внизу]. Если вы в прошлом занимались разработкой Backbone, вы можете узнать в этом паттерн, рекомендованный отличным (хотя и относительно старым) сообщением в блоге на тему предотвращения утечек памяти с помощью Backbone views.
Backbone.View.prototype.close = function(){
  this.remove();
  this.unbind();
  if (this.onClose){
    this.onClose();
  }
};
  • В основной функции маршрутизации при замене представления вызывается метод close предыдущего представления.
  • Это отличается от «монолитного представления» тем, что каждое из этих подчиненных представлений включает гораздо меньший набор проблем, чем упаковка всего этого кода в одно представление.

Заключение:

Я не знаю, сколько людей осталось думать, что React - это просто еще одна модная вспышка в кастрюле, но если вы все еще используете библиотеку MV *, такую ​​как Backbone, я рекомендую хотя бы попробовать React на некоторое время, пока шаблоны проектирования на основе компонентов щелкните. Я считаю, что даже если вы вернетесь к Backbone, это сделает вас лучшим разработчиком.

Эта статья является частью серии

[примечание 1]: когда я писал этот пост, готовясь описать относительные достоинства возможности отвязать слушателей в пределах представления, я понял, что на самом деле я еще даже не реализовал это в моем примере проекта. Фиксированный. Это первое опубликованное упоминание о «разработке, управляемой блогами»?