Роман Дворнов (twitter) – руководитель фронтенд-разработки в Авито, автор basis.js, мейнтейнер CSSO, CSSTree, Component Inspector и не только. Роман работает над новым проектом, призванным упростить разработку инструментов удаленного мониторинга и отладки web-приложений.
Давайте узнаем, какие проблемы поможет решить проект Романа, и к чему он в итоге пришел.
– Расскажи, что такое rempl и зачем он вообще нужен?
– rempl – решение, которое позволяет получить контролируемый удаленный доступ к runtime приложения. Решение композитное и состоит из нескольких разноплановых компонент.
Мы начинаем с того, что создаем провайдера (наблюдателя), сущность, которая мониторит приложение (или страницу, процессы в браузере и т.д.) и публикует некоторые данные. Дальше мы создаем интерфейс (потребитель), который эти данные визуализирует или делает с ними что-то еще. При этом интерфейс – это некоторый UI, который может быть запущен в произвольном WebView и к нему «магическим» образом попадают данные от провайдера. Провайдер и потребитель также могут обмениваться командами.
Когда мы говорим о произвольном WebView, то подразумеваем другую вкладку, вкладку другого браузера, браузерные Developer Tools, плагины в редакторах и IDE, как на той же машине, что и провайдер, так и на любой другой.
Rempl позволяет достаточно просто создать свой инструмент, то есть провайдера, и некоторый интерфейс, обеспечивает весь транспорт (мы создаем провайдера и потребителя, а они сами соединяются и начинают общаться между собой), а также предоставляет ряд хостов вроде веб-интерфейса, который можно открыть в любом современном браузере, плагины для браузерных Developer Tools (пока только Chrome, но будет и Firefox), различных редакторов (пока Atom и VS Code) и прочее. Также в планах есть SDK, которое упростит типовые операции, такие как работа с потоками данных и работу с DOM, например, подсветить некоторый элемент на странице.
Чтобы получить представление о том, как это работает, можно посмотреть видео – в этом видео показаны инструменты для basis.js, на которых обкатывался подход. Собственно, при работе над этими инструментами стало понятно, что подход достаточно универсальный. А именно большая его часть, которая касается транспорта и хостов, не зависит от специфики фреймворка или приложения. Можно считать, что реализация инструментов в basis.js стала прототипом для rempl – универсального решения для создания подобных инструментов. Когда все заработало с инструментами basis.js, я подал заявку на HolyJS и начал пилить rempl :)
Провайдер и потребитель
– Что из себя представляет провайдер? Эта сущность только предоставляет API для взаимодействия с инструментом, а сами данные должен собирать инструмент?
– Провайдер (provider) и потребитель (customer) — это роли. Сейчас есть некоторая проблема с терминологией, но то что получается близко к паттерну publish-subscribe и проблеме producer-consumer.
Провайдер – это та часть, что генерирует и публикует данные, а потребитель их использует. Rempl позволяет получить API для публикации на одной стороне (стороне провайдера) и принимать данные на другой (потребитель). То, как эти данные собирать и в каком виде публиковать, разработчик решает сам при создании провайдера. Точно так же как и что делать с этими данными на стороне потребителя. В методах и технологиях ограничений нет, в этом случае rempl лишь облегчает передачу данных от одной стороны другой.
– По какому протоколу происходит общение провайдера и потребителя? Для такого взаимодействия нужен посредник (сервер)? Это будет работать в IE?
– Все зависит от того, где хостится провайдер и потребитель. Если провайдер хостится в браузере или node.js процессе, а потребитель в другой вкладке браузера (или в другом браузере), то коммуникация происходит через socket.io. В этом случае, да, используется промежуточное звено в виде сервера. Сервер не только является связующим звеном, но и предоставляет веб-интерфейс со списком всех подключенных провайдеров, возможностью выбора интересующего и организующий запуск пользовательского интерфейса выбранного провайдера в песочнице (sandbox). Последнее по сути является хостом для потребителя.
Так как для коммуникации используется socket.io, то будет использоваться либо WebSocket, либо long polling как фолбек. То есть в IE, теоретически, в плане транспорта все должно работать.
Но socket.io используется не всегда. Например, с браузерными Developer Tools через веб сокеты не пообщаешься. В этом случае коммуникация обеспечивается через DOM-события. Более того, для того, чтобы что-то передать в вашу закладку, нужно соединить между собой 4 узла: провайдер <--> content script <--> background page <--> plugin (схема есть в начале статьи). Это нетривиальная задача, но с rempl вам не нужно об этом думать.
– Когда ты говоришь про сбор данных провайдером, ты имеешь в виду мониторинг клиентской части приложения?
– Мониторинг это лишь одно из возможных направлений, как это можно использовать. Да, первоначальная идея была именно в области клиентской части приложений и сайтов. Но в ходе обсуждений с коллегами вариантов использования rempl, уже в ходе подготовки доклада, неожиданно пришло понимание, что провайдер может жить не только в браузере, но и в node-процессе. Таким образом, вся та же инфраструктура стала доступна и для node-приложений. Так можно получать информацию о внутренних процессах в удобном и наглядном интерфейсе.
Например, есть такой проект как дешборд для Webpack, который рисует в консоли информацию о происходящем в более наглядной форме, чем обычный вывод Webpack'а. Коллега сделал клон этого плагина, главное отличие которого в том, что информация выводится с использованием веб-технологий и может выполняться в произвольном WebView. Это дает гораздо больше возможностей для визуализации и более богатого UX. Например, можно прикрутить уже готовые решения по анализу бандла, такие как source-map-explorer и другие. При этом для анализа бандла необязательно, чтобы он был на диске, ведь провайдер имеет доступ к рантайму Webpack, и тут большой простор для фантазии.
Инструментов разработки по-прежнему не хватает
– То есть, нам стоит ожидать появление новых инструментов, которые будут лучше старых?
– Время покажет, но я очень на это надеюсь :) Одна из основных целей, помимо того, чтобы предоставить готовое решение, это снизить порог входа для разработчиков в изготовлении собственных инструментов. Я считаю, что инструментов много не бывает, и от того, что вы используете в разработке, очень сильно зависит ваша продуктивность. Несмотря на, казалось бы, обилие инструментов разработки, их по-прежнему не хватает. Это связано с тем, что инструменты часто делают другие разработчики, решая свои задачи. Но у каждого свои потребности, задачи, возможно, уникальный стек технологий или собственный фреймворк. В этом случае решением проблемы будет разработка своих инструментов. Но придется сделать многое, особенно, если есть цель запускать инструмент вне страницы, в которой работает приложение. Это требует много времени и нервов.
Более того, это нельзя назвать полезной работой – это своего рода оверхед, который отдаляет вас от разработки непосредственно самого инструмента. Так вот, rempl позволяет избежать лишней работы и сосредоточиться непосредственно на инструменте, что куда проще и интересней.
Есть еще один важный момент. Разные хосты для интерфейса инструмента могут дать дополнительные возможности. Особенно хостинг инструмента в редакторе – ведь это дверь в мир новых возможностей для веб-разработки. Сейчас есть множество инструментов, которые помогают писать код и анализируют его. Есть инструменты, которые что-то показывают о происходящем внутри приложения (в его runtime). И эти две категории инструментов живут отдельно. Но что, если мы объединим эти два мира? Так, имея загруженный интерфейс инструмента в вашем редакторе/IDE, имеющий удаленный доступ к runtime – можно получить новые возможности. Просто представьте, у нас есть информация о коде и runtime в одном месте! И с этим определенно можно что-то сделать. К примеру, редактируя JavaScript, CSS или шаблоны, можно подсвечивать на странице то, что затрагивает редактируемый файл. Или в шаблонах подсказывать, какие доступны биндинги. Или показывать, во что Webpack ресолвит require, с возможностью перейти на нужный файл. Или во что траспилируется текущий файл и т.д.
На самом деле, я сам еще не знаю все возможные кейсы, но могу сказать наверняка, возможностей очень много, и новые идеи появляются постоянно. Очень интересно, что придумают другие :)
Границу между кодом и runtime в редакторах я увидел достаточно давно, и понял, что ее можно преодолеть. Но для того, чтобы это как-то утилизировать в своих инструментах, пришлось сделать немало. К rempl так или иначе я шел больше пяти лет, создавая промежуточные решения. Многие рефакторинги и работы в направлении «сделать по уму» приводили в тупик и не имели хэппи энда – кончалось терпение и время. Рад, что сейчас вырисовывается законченное решение, хотя еще много над чем нужно поработать.
Это как пример того, что решение рутинных инженерных задач отдаляет от полезной работы. Сейчас я только подхожу к тому, чтобы реализовать многие из своих идей. Путь был тернист, и я точно не стану советовать кому-то его повторять. Считаю своей маленькой победой, что многим и не придется, достаточно будет взять rempl и сделать то, что они давно хотели для своего проекта или стека.
Разработка такого инструмента – это каторга
– А как rempl повлияет на уже существующие инструменты?
– На этот вопрос сложно ответить, так как сложно прогнозировать реакцию разработчиков инструментов. Захотят ли они перевести свои инструменты на общую платформу или продолжат пилить свое. Одно могу сказать, инструменты basis.js точно мигрируют на rempl и начнут использовать новые возможности, что должно положительно сказаться на их функциональности. Component Inspector тоже будет переведен на rempl. И думаю, что в нашей компании, вскоре появятся новые инструменты на основе rempl, решающие насущные проблемы.
Говоря о существующих инструментах, хотелось бы рассказать о нескольких проблемах. И хотя проблемы разные, как ни странно, одна вытекает из другой.
Во-первых, проблема транспорта и хостов только кажется простой. В ней очень много подводных камней и, повторюсь, это не самая простая и тем более интересная задача. Если посмотреть на разработчиков инструментов (обычно это инструменты к фреймворкам в виде плагинов для браузерных Developer Tools), то все они ходят по одному и тому же минному полю. То есть каждый разработчик заново, с нуля, реализует все необходимое, а именно транспорты, хосты и т.д. При этом теряя время, решая те же проблемы, что и остальные. С rempl разработчикам инструментов можно будет удалить свое решение для разных платформ (хостов) и заботиться только об основной функциональности их инструмента. Например, у react-devtools возможно будет удалить папку shells – можно поизучать, насколько там непростой код.
Во-вторых, сложность разработки и развития инструмента. Например, инструменты для фреймворков часто ограничиваются плагином для браузерных Developer Tools. Разработка такого инструмента – это каторга. Ведь чтобы увидеть изменения, нужно пересобрать плагин, перегрузить его в настройках браузера (в Chrome это Extensions), перезагрузить страницу, где используется плагин, закрыть браузерные Developer Tools, заново их открыть и выбрать вкладку вашего плагина. И это нужно делать каждый раз, когда вы вносите изменение. Мы сами через это проходили, очень быстро надоедает и начинает бесить.
Куда проще запускать тот же интерфейс, что и в плагине, в отдельной вкладке браузера и так разрабатывать. А когда все будет готово, то просто запустить этот интерфейс в Developer Tools. Все становится куда проще: для того, чтобы увидеть изменения, достаточно перезагрузить страницу, а если стек, на котором создается интерфейс, поддерживает live update или live reload, то и этого обычно не нужно. Но чтобы это организовать, вам нужно реализовать еще один вид транспорта и запуск интерфейса в отличном от Developer Tools окружении. И здесь кто как выходит из ситуации, но, в любом случае, процесс нельзя назвать приятным и увлекательным. Потому такого рода инструменты развиваются медленно, а то и вовсе их развитие замирает. Rempl позволяет запускать ваш инструмент (его интерфейс) в том хосте, который наиболее подходит для решаемой вами задачи, и вам не нужно делать что-то особенное для этого.
В-третьих, версионирование. Когда вы делаете инструмент, например, для фреймворка, который развивается, то нужно быть готовым к тому, что в фреймворке что-то может поменяться и инструмент перестанет работать. Собственно, так и случается, фреймворк меняется – инструмент меняется вслед. Но инструмент не может работать только с последней версией фреймворка: не все мигрируют быстро, а некоторые проекты вообще могут быть на поддержке, и обновление библиотек может быть очень дорогим и нерациональным мероприятием.
Оставаться совсем без инструментов в таких случаях тоже плохо. Потому инструменты «учатся» работать с разными версиями фреймворка, что со временем превращает их код в кашу и сильно усложняет добавление новой функциональности. Мы это тоже проходили с инструментами basis.js и это большая боль, особенно для немолодых фреймворков. Rempl решает эту проблему своей моделью распространения интерфейса. А именно: хост (например, плагин для браузерных Developer Tools) это всего лишь песочница, в которой может быть выполнен произвольный скрипт. Хост ничего не знает об интерфейсе. Когда со страницы выбирается некоторый провайдер (инструмент), с которым предстоит работать, то хост отправляет к провайдеру запрос «дай мне твой интерфейс», а в ответ провайдер отдает скрипт (бандл, в котором есть все необходимое для построения интерфейса). Хост получает и выполняет этот скрипт в песочнице и вы видите интерфейс инструмента. Таким образом, для каждой версии фреймворка вы подключаете свою версию провайдера (инструмента) на странице. В результате, в зависимости от версии фреймворка в Developer Tools, вы увидите ту или иную версию инструмента, версии могут отличаться функциональностью и завязаны на конкретную версию фреймворка. Поддержка инструмента в таком случае здорово упрощается и вам не нужно разных браузерных плагинов для того, чтобы работать с разными версиями фреймворка.
Подытоживая, могу сказать, что существующие инструменты могут здорово выиграть, перейдя на решение вроде rempl, так как он берется решать достаточно широкий спектр проблем. Кроме того, это также может упростить жизнь разработчикам, которые используют инструменты разработки, так как им можно будет не ставить отдельные плагины для разных фреймворков и библиотек.
– Я сильно удивлен, что в этой сфере нет ничего готового.
– Темой занимаются немногие, так как она не простая. Кастомное решение хоть и непросто сделать, но куда проще универсального. Ну и нужно повариться в теме значительное время, чтобы это окончательно достало и увидеть способы решения проблемы ;)
– Спасибо, что уделил мне время. Подскажи, когда и где можно будет увидеть результат?
– Все относящееся к проекту доступно на GitHub в организации rempl. Правда, сейчас там «рабочий беспорядок» и пока не все готово, но к выступлению на HolyJS все должно стать гораздо лучше. В любом случае, можно поставить лайк и подписаться на обновления уже сегодня ;)
В ходе самого выступления на HolyJS, 11 декабря, я постараюсь рассказать все более структурировано, с примерами кода, схемами и live demo. Это будет первое публичное выступление о проекте. Но, думаю, далеко не последнее – впереди еще много дивных открытий, о которых можно будет услышать на будущих конференциях.
Всем, кто заинтересовался данной темой, мы предлагаем посетить доклад Романа на JavaScript-конференции HolyJS. Также вы сможете услышать еще 19 докладов о проблемах, решениях и будущем JavaScript-мира: говорить будем про фронтэнд, бэкенд и даже десктоп.