Pull to refresh

От Google Wave к Node.js

Reading time 7 min
Views 2.4K
В мае 2009-го был анонсирован Google Wave (GW), через несколько месяцев мы получили инвайты и начали его изучать. В GW, как и в GoogleDocs, есть возможность совместного редактирования текста, использующая технологию OT. Есть и бонусы: можно сворачивать разделы документа в структуру, добавлять гаджеты и роботов. Мы обсуждали в GW наши текущие проекты, в целом инструмент нравился, а обилие неудобств рождало множество идей по расширению функционала и улучшению интерфейса. Особенно остро ощущалась нахватка шортката для сворачивания всех разделов документа. Также часто обсуждалась идея ставить каждую задачу в контексте, к которому она относится.


Владимир Семёнов, наш web-разработчик, начал исследовать возможность контекстной постановки задач и обработки роботом регулярных выражений. Идею расширения, обеспечивающего возможность сворачивания разделов обсуждений по шорткату, Владимир поведал одногруппнику из ТУСУРа, Сергею Хегаю. Сергей заинтересовался этой идеей и начал в свободное от учебы и основной работы время её исследовать.

Через два месяца появилось расширение к браузеру Google Chrome и робот, который обрабатывал задачи в контексте. Сейчас архитектура наших инструментов на базе Google Wave выглядит как показано на рисунке выше.

Жизнь в схеме

Рассмотрим схему взаимодействия нашей системы с пользователем.

Задачи в волне связаны со списком задач в гаджете так:
1. Пользователь пишет в тексте регулярное выражение (например, слова «задача» или «экспорт» в скобках).
2. Робот находит это выражение в тексте.
3. Робот вносит необходимые данные в базу и генерирует ссылку.
4. TaskGadget видит, что появилась новая задача, и при следующем открытии показывает ее в своем списке.

Необходимо, чтобы окошко с формой открывалось рядом с регулярным выражением прямо в волне, а не на отдельной странице или вкладке. Это реализовано так:
1. Пользователь нажимает ссылку, сгенерированную роботом на 3-м шаге предыдущего описания.
2. Нажатие на ссылку перехватывается расширением.
3. Расширение формирует iframe (пустое окно), в котором в качестве адреса (src) указыватся эта ссылка.
4. Браузер сам получает с нашей базы форму и загружает ее в iframe.
Еще есть взаимодействие с GoogleCalendar, о нем далее.

Фотографии организаторов работы роботов:



Владимир Семёнов, Сергей Хегай

Спор «GUI vs. Cmd» и другие интерфейсы

Извечный вопрос «Что удобнее: текстовая команда или графический интерфейс?». Мы долго холиварили о том, как удобнее организовать взаимодействие пользователя с инструментами «задач в тексте», «поиска по волнам» и «экспорта в HTML». Было два варианта развития:
— окошки с GUI-формами: так понятнее новым пользователям и не требует запоминания параметров команды (например, формата даты);
— ввод команд напрямую в тексте волны: это увеличит скорость получения команды роботом, а всем известно, что гики готовы вникнуть в детали для экономии времени.

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



GUI vs. CMD для интерфейса задач

Разница между тем, как ставят задачи обычный и гик-пользователи:
— привыкший к оконным формам начинает с того, что пишет «задача» в круглых скобках. Робот обрабатывает это слово и заменяет на ссылку. Затем пользователь нажимает ссылку и в появившемся окошке уточняет параметры задачи.
— пользователь, привыкший к командной строке, сразу в тексте документа пишет "(задача вася)". То есть указывает все основные параметры задачи: исполнитель, дата, (иногда другие параметры). На этом постановка задачи закончена.

Список задач в волне

Текст задачи часто составляет всего пару слов. Почти всегда чтобы понять задачу, необходимо осознать и какую-то долю контекста, к которому она относится. Основная идея TaskGadget — обеспечить переход из списка задач в контекст:



TaskGadget. Переход из списка задач в контекст

По умолчанию задачи упорядочены по дате. Каждая задача в гаджете содержит ссылку на сообщение, в котором она была поставлена. При клике на задачу рядом с гаджетом открывается обсуждение — контекст задачи.

Интерфейс экспорта статей из волны

Сначала мы реализовали экспорт самым простым способом: из волны экспортировалось только одно выбранное сообщение. После экспериментов стало понятно, как сделать в статье структуру. В этом случае для каждого сообщения (в GW сообщения называются блипами) публикация настраивается отдельно. Вот так выглядит статья в свернутом виде:



Пример структуры статьи в волне

Каждое сообщение можно включить в экспорт или исключить из него. Для этого в начале каждого сообщения робот проставляет значки: "+" или "-", обозначающие включенность блипа в экспорт.




Примеры сообщений. Верхнее со значком "+" включено в экспорт. Нижнее со значком "-" в экспорт не включено.

Каждый "+" или "-" является ссылкой, при нажатии на которую можно изменить статус экспорта блипа. Для этого используются вот такие GUI-формы:



Формы для настройки экспорта

Google Chrome Extension

Расширение WaveShortCuts выполняет действия, которых нам не хватало в клиенте GW. Вот их перечень:



Горячие клавиши WaveShortСuts

В своей работе мы часто используем два шортката, выделенные на этой картинке. С помощью них можно выделить предложение или фрагмент текста на любом сайте, нажать Alt+C, а затем вставить этот фрагмент в волну сразу в виде ссылки на сайт, с которого он был взят.

При нажатии шортката расширение генерирует команду для клиента GW. Соответственно, расширению нужно право отправлять команды в GW от имени пользователя. GW настороженно реагирует на такую ситуацию, а пользователи часто пугаются вот такого уведомления (появляется при установке нашего расширения):



Запрос доступа к Google-аккаунту

Для работы функции вставки ссылок расширению требуется доступ от имени пользователя на сайты, которые он посещает. Поэтому появляется еще и такое пугающее сообщение:



Уважаемые разработчики, при разработке расширений по возможности избегайте подобных предупреждений :)

Выкладываем расширение на Chrome WebStore

В работе над снижением порога вхождения для новых пользователей выяснилось, что одним из узких мест является установка расширения. Много непонятных ссылок и кнопок путали новых пользователей. Поэтому мы решили переехать с code-хостинга гугла на WebStore.

Непростой квест, который нас ожидал, подробно отражен в этой волне. Если свернуть в ней все блипы, увидим такую структуру:



Разделы волны, в которой мы обсуждаем размещение WaveShortCuts на WebStore

Настройка уведомлений и работа с Google Calendar

Для нормальной работы с задачами требовалось настроить всевозможные уведомления и синхронизацию с мобильными устройствами.

Уведомления в джабер реализованы через добавление нашего робота себе в контакты, а уведомления по SMS и синхронизацию с мобильным мы реализовали через Google-календарь, потому что SMS оттуда бесплатны, а в телефоне работать с задачами через календарь удобнее.



Cкриншот со страницы Настройка уведомлений

Подключение Google-календаря

Сначала мы хотели связать робота с личным календарем пользователя. Но тогда возникает проблема синхронизации: если пользователь изменит или удалит задачу в своем личном календаре, то нужно потом эти изменения обработать и записать в волну. Технически такую синхронизацию сделать довольно сложно.

Мы выбрали другой вариант: робот создает календарь и расшаривает его пользователю.

Причем мы не можем расшарить календарь, если пользователь не активировал сервис GoogleCalendar. Именно поэтому в интерфейсе активации календаря, скриншот которого выше, мы не смогли избежать моветона: предупреждающих слов и восклицательных знаков.

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

Пару слов о будущей архитектуре Platform Odessa

То замечательное, что есть в GW, давно не развивается, скорее наборот. В этом году мы поняли, что нам нужно развивать этот сервис. Для этого нужно найти альтернативу GW. Компания Google передала все исходники и знания по проекту GW в фонд Apache. В Apache стартовал проект WiaB — Wave in a Box. Cейчас уже существует альфа-версия продукта. Мы начали изучать состояние проекта и пришли к следующим выводам:
— непонятно, кто и в какую сторону развивает WiaB сейчас;
— WiaB плохо годится для масштабирования;
— архитектура WiaB не до конца поддерживает нашу бизнес-логику;
— большая проблема с документацией, которой скорее нет, чем есть;
— большая связанность серверного и клиентского кода;
— по сути, самый большой плюс в WiaB на данный момент — хорошо реализованный OT-редактор, в остальном минусов больше, чем плюсов;
— и, наконец, у нас не так много java-разработчиков.

Мы задались вопросом: сможем ли мы разработать собственную платформу? Одна из сложных задач ОТ уже реализованна в ShareJS, к тому же мы располагали готовыми решениями по масштабированию. Поскольку клиенты постоянно держат соединение с сервером, для эффективного потребления ресурсов необходимо использовать серверные решения, которые позволяют дешево поддерживать множество долгоживущих соединений. Для такой задачи отлично подходят асинхронные (неблокирующие) серверы. Для себя мы сделали вывод, что принципиально нерешаемых архитектурных задач тут нет.

В результате мы решили делать сервис на собственной платформеRizzoma.com. Думая о том, какие конкретно технологии нужны для каждого модуля, мы пришли к такому видению архитектуры:



Слайд из нашей презентации на OdessaCamp

Из неблокирующих серверов есть Node.js или Tornado. Выбор пал на Node.js, так как:
— ShareJS написано для Node.js;
— часть кода может быть использована как на сервере, так и на клиенте. И не надо переключать внимание между разными языками;
— платформа активно развивается и появляется очень много библиотек. К примеру, Яндекс выпустил свой фреймворк.
CoffeeScript был выбран языком разработки из-за наличия синтаксического сахара по сравнению с простым JavaScript.

Базу данных выбрали CouchDB, так как:
— база документо-ориентирована, что лучше подходит нашей бизнес-логике: очень много иерархически вложенных друг в друга вещей. А это в документо-ориентированных БД проще реализовать;
— благодаря своей документо-ориентированности CouchDB требует меньше связей между записями, что облегчит масштабируемость в светлом будущем.

Чтобы лишний раз не писать гаджеты, мы будем поддерживать стандарты OpenSocial и все гаджеты, которые работали в Google Wave (Orkut, MySpace и т.д.), будут работать и на платформе Odessa.

Также мы планируем реализовать федеративность, чтобы наш сервер мог взаимодействовать (обмениваться волнами) с серверами WiaB, Novel Vibe и другими серверами, которые будут это поддерживать.

Поисковую систему используем Sphinx. Упрощенно описать эту схему работы можно так: при изменении данных в СouchDB изменения будут попадать в индекс, по которому уже будет происходить поиск. Все поисковые запросы будут исполнятся Sphinx'ом, учитывая теги, время, уровни доступа и т.д. Благодаря этому мы получаем высокую скорость выполнения запросов и минимальную нагрузку на серверы с БД.
Tags:
Hubs:
+37
Comments 12
Comments Comments 12

Articles