В начале 2014 года я никогда даже не думал об использовании фреймворка компонента Flight JavaScript в Twitter, но здесь я недвусмысленно заявляю, что это правильный выбор для вашего существующего веб-сайта, о котором я, вероятно, ничего не знаю. Я лучше объясню, пока вы готовите свои вилы для раздела комментариев.
Дай мне нарисовать картину
Полет — это то, с чем создан Twitter. Flight не пользуется большим спросом, потому что его специализация — не модные одностраничные демонстрационные приложения с привязкой данных, а реальные веб-приложения, построенные в основном на кодовых базах на стороне сервера. Его дизайн целиком и полностью состоит из компонентов и событий. Там нет переменных экземпляра. Там нет магии. Компоненты данных запускают события для широковещательной передачи данных, а компоненты пользовательского интерфейса прослушивают события данных и, в свою очередь, запускают свои собственные события пользовательского интерфейса.
Компоненты полета исключительно отделены, никоим образом не «захватывают» вашу страницу (в отличие от ng-app
Angular), и по своей природе они очень просты для тестирования, миграции в / из и рефакторинга. Когнитивная нагрузка наследования обслуживания существующих компонентов Flight или рефакторинга существующих компонентов значительно ниже, чем это возможно с Backbone или Angular, и вы не заканчиваете утечкой или дублированием доменной логики в свое приложение, как это происходит с Backbone или любой структурой JS, которая включает в себя модели.
Почему рейс?
Ваша команда работает над сайтом в течение нескольких лет. Он в первую очередь основан на серверной технологии — Ruby, PHP, Python, .Net — и именно здесь вы решили реальные проблемы, специфичные для конкретной области. Многие из этих решений являются причиной успеха вашего сайта. Наряду с этими серверными функциями вы постоянно добавляете больше улучшений JavaScript для улучшенного взаимодействия, более быстрых интерфейсов и тому подобное. Возможно это началось как спагетти jQuery, склеивающие плагины других людей. Возможно, там есть какой-то jQueryUI или Backbone, Angular или Ember, которые достаточно хорошо работают в своих изолированных уголках сайта.
По мере того как эти улучшения стареют и размножаются, вы начинаете замечать тревожную тенденцию. В то время как ваша бизнес-логика в основном живет на стороне сервера с ее набором тестов и инструментарием QA ( RIGHT ?! ), все больше и больше приходится тиражировать на уровне JavaScript. Вы не хотите удваивать, но у вас есть логика в вашем пользовательском интерфейсе, и она должна принимать правильные решения. Точно так же пользовательские компоненты и помощники форматирования, которые вы накопили на сервере, должны быть реплицированы на стороне клиента, чтобы превратить ваши ответы API в правильно отформатированные представления.
Так что теперь вы на распутье. Продолжаете ли вы идти по этому пути, тиражируя логику между двумя кодовыми базами и рискуя их потерять синхронизацию, или же вы решили переориентировать свою энергию на подход «толстого клиента», поддерживаемый API, с одной из больших платформ приложений JavaScript?
Как насчет третьего варианта — тот, который позволяет вам избежать переписывания основной бизнес-логики и уровня представления, в то же время предоставляя вам чрезвычайно слабосвязанную, легковесную методологию JavaScript, которая легко тестируется, проста для понимания и рефакторинга и, что самое главное, позволяет вам постепенно двигаться из вашей путаницы существующих функций JavaScript. Что, если эту ту же самую альтернативу было бы так же легко отодвинуть, если вы однажды решите, что она больше не подходит, в то же время позволяя вам легко вводить новшества, быстро предлагая новые идеи вашим пользователям и с уверенностью, что они работать как задумано?
Вариант три звучит хорошо для меня. Так как же Flight предлагает выполнить эти высокие обещания?
Все говорят, все слушают
Хотя вы определяете свои компоненты в стиле, очень похожем на обычные классы (включая контекст, связанный с вашим компонентом в обработчиках событий), ни один компонент не может ссылаться на экземпляры других компонентов. Это означает, что вы не можете тесно связать API-интерфейсы, и ни одна из связанных ошибок не возможна из-за благих намерений проектов, которые естественным образом выходят из-под контроля. Компоненты могут взаимодействовать только через события, которые либо ограничены узлом DOM, к которому прикреплен компонент, либо document
. Это соглашение о полете для трансляции события любому, кто захочет его услышать.
Из-за этого компонент Flight не знает и не заботится, общается ли он с другим компонентом Flight. Нет ожидаемого интерфейса, потому что интерфейса практически нет. Если вы хотите, чтобы часть вашего существующего JS отправляла данные в компонент Flight, все, что нужно сделать, — это вызвать событие с именем, которое прослушивает компонент, и отправить данные (например, $(document).trigger('dataShoppingCart' cartContents)
).
Самая сложная проблема в информатике
Имя события dataShoppingCart
намекает на часть, которую Flight не решает за вас — присвоение имени событию. Если каждый компонент прослушивает и запускает все эти события, как вы собираетесь их отслеживать? По крайней мере, с помощью традиционного API, основанного на экземплярах, вы можете легко увидеть, что зависит от того, что и откуда ожидаются данные. Вы должны помнить, однако, Twitter сделал это для себя. Они не хотят создавать среду, которая будет ориентировать новичков, они нанимают опытных разработчиков и имеют внутренние соглашения по кодированию, которые необходимо соблюдать.
Соглашения о кодировании — именно то, что мешает проблеме именования событий выйти из-под контроля. В основе этого есть два типа событий — события пользовательского интерфейса, имена которых начинаются с пользовательского ui
, и события данных, имена которых начинаются с data
. Событие data
всегда является трансляцией новых доступных данных, в то время как событие пользовательского интерфейса представляет взаимодействие с пользователем. Для получения дополнительной информации о присвоении имен событиям, Том Хэмшир предлагает несколько советов по именованию событий Flight из своего опыта миграции TweetDeck в Flight.
Разделение проблем
Этот пользовательский интерфейс и разграничение данных продолжаются в самих компонентах, и именно здесь я вижу наибольшую выгоду от использования Flight по назначению. Примеры компонентов Twitter для Flight разделены на две отдельные группы: components_ui
и components_data
. Компоненты данных ничего не знают о DOM, а компоненты пользовательского интерфейса никогда не касаются сети. Таким образом, пользовательские события обрабатываются только в компонентах пользовательского интерфейса, поэтому вы не получаете методы обработки данных (например, отправку формы e.preventDefault()
, начиная с e.preventDefault()
, среди других анти-шаблонов.
Полностью практическая разработка через тестирование
Такое разделение JavaScript, специфичного для поведения и данных, дает разработчикам (разработчикам) преимущества в виде снижения когнитивной нагрузки при разработке и упрощения тестирования. Подготовка и выполнение вызовов API происходит в компоненте данных и легко тестируется с помощью jasmine-ajax . С другой стороны, события взаимодействия и поведения пользователя обрабатываются в соответствующем компоненте пользовательского интерфейса и тестируются с помощью jasmine-jquery и jasmine-flight . Спецификации для компонентов данных будут загружать приборы JSON, представляющие ответы API, в то время как компоненты пользовательского интерфейса будут загружать минимальные приспособления HTML, которые также служат канонической ссылкой для разметки, ожидаемой компонентом.
Полет использует DOM, а не доминирует над ним
Полет убедил меня, что он отлично подходит для реальных долгоживущих продуктов, когда я впервые использовал его (что было всего месяц назад). Я и другой разработчик в моей команде работали параллельно над областью пользовательского интерфейса, которая предлагает выбор соавторов с вкладками, где список соавторов имеет критерии поиска, которые применяются асинхронно. Я реализовывал панели вкладок и навигацию как один компонент пользовательского интерфейса, а он реализовывал элементы управления поиском и список результатов в другом. Когда мы оба закончили, я пошел объединять две ветки git, ожидая, что оба наших дополнения JS будут нарушены из-за предположений других.
Это просто сработало !
Компоненты Flight не принимают никакого участия в узлах DOM, к которым они подключены, и не делают предположений о состоянии этих узлов. Нет никакого соблазна крепко this.el
как this.el
из Backbone Views, ни ng-app
от Angular — ни одна из этих притяжательных директив. Flight действительно использует DOM, он не отражает его, не угоняет и не использует подход «наш путь или шоссе». С тех пор я вернулся и реорганизовал список результатов в его собственный компонент, и снова это не потребовало никаких изменений в ожиданиях или реализации соседних компонентов. Наш код легко протестировать, легко изменить и легко понять для следующего человека, которому необходимо его прочитать.
Вывод
Там нет недостатка в подходящих случаях использования для множества всеобъемлющих, доступных JavaScript-фреймворков. Если бы я запускал новое веб-приложение, в котором с самого начала знал, что клиент будет сильно загружен JavaScript, я бы, скорее всего, выбрал что-то вроде Ember, Angular или Backbone + Marionette. Я бы использовал их маршрутизацию, их самоуверенный подход к X, я бы реализовал его «The ____ Way». Но в мире, в котором я работаю — одно из долгоживущих веб-приложений, разрабатываемых и поддерживаемых разнообразной командой, — система компонентов, такая как Flight, идеально подходит и является вариантом, который я с уверенностью рекомендую любой команде, занимающей аналогичную должность.