Привет! Я Георгий, разработчик команды, которая создавала Unidraw. Расскажу историю о том, как мы искали инструмент для совместных сессий на виртуальной доске. Сначала развернули опенсорсное решение, но потом у нас так выросла нагрузка, что пришлось писать свое. Статья — о том, как начинался продукт, какой он сейчас и каким мы хотим видеть его в будущем. Будут технические данные, красивые шаблоны и история нашей главной ошибки.
Поиск подходящих решений
Мы постоянно используем сервисы с виртуальными досками, остановились на одном варианте, но с 2022 года искали альтернативу. Для нас важно, чтобы мы могли:
-
Проводить ретроспективу
-
Делать быстрые наброски мокапов, которым не нужна дизайнерская проработка
-
Рисовать архитектурные схемы для обсуждения
-
Проводить онлайн-встречи с визуализацией артефактов
-
Обучать коллег
Рассматривали разные варианты, в том числе BoardOs, но когда связались с ними, они ответили, что не планируют развитие для России, и локализуют свое приложения только для Китая.
У найденных решений были ограничения по количеству доступов к доскам, или они решали узкоспециализированные задачи.
В это же время пришла помощь от наших архитекторов, которые показали проект Open Source с P2P-шифрованием передачи данных. Мы решили на его основе поднять свой сервис-аналог с возможностью делиться ссылками, сохранять результаты в кабинете на сервере и добавлять реципиентов к контенту доски.
Open-source-решение предлагало:
-
одну доску максимум;
-
поддержку коллективных сессий;
-
хранение доски в браузере пользователя.
Технические детали решения:
-
socket.io для синхронизации изменений между пользователями;
-
нет единого источника правды: все клиенты хранят состояние доски у себя;
-
на клиенте есть механизм Reconciliation, который умеет мержить изменения от разных пользователей;
-
обновление доски привязано к жизненному циклу React.
Первые шаги нового продукта
Взяв за основу опенсорсный проект, мы создали кабинет, в котором пользователь видит все созданные им доски и проекты, по которым мог распределить эти доски.
В кабинете можно делится досками, давать общий доступ на весь проект с досками с распределением прав на чтение или редактирование — не только одной доски, а сразу всех досок этого проекта.
Задачей номер один было настроить персистентное хранилище досок. Техническое решение принимали в пользу скорости реализации, чтобы обкатать MVP и понять, насколько приложение может быть востребованным, поэтому:
-
Доска сохранялась целиком (JSON-объект) в БД каждые 20 секунд.
-
Локов при коллективных сессиях не было, каждый клиент выполнял сохранение независимо друг от друга. Небольшая нагрузка от 1 500 пользователей позволяла нам это делать.
-
В коллективных сессиях вновь зашедший пользователь получал данные доски не только с БД, но и от других пользователей по сокету. Поэтому в худшем случае данные в БД неактуальны 20 секунд.
Мы запустили сервис в конце сентября 2022 года и не делали никакого внутреннего маркетинга, кроме метода «расскажи другу». В первый же месяц мы получили 250 стабильно использующих сервис пользователей.
Количество пользователей росло органическим способом — ссылки на доски передавали из рук в руки. За это время мы решали задачи по развитию функционала:
-
сделали ссылки на место на доске: если после передачи этой ссылки другому пользователю он вставит ее в браузер, доска откроется на том месте, которое указал создатель ссылки;
-
добавили фреймы и стикеры;
-
добавили Color Picker, расширив возможности цветовой дифференциации элементов на доске;
-
добавили snap-объекты — линии, которые позволяют позиционировать элементы относительно друг друга.
На этом этапе мы стали получать сообщения, что система вполне удовлетворяет их потребностям в решении большого количества задач, для которых использовали Miro и другие системы. Например, к нам стали переходить из Storm BPM, draw.io и других.
Приложение постепенно набирало обороты. По MAU к февралю 2023 года мы подошли к значениям, сопоставимым с количеством пользователей, которые использовали Miro на тот момент, когда мы хотели купить их лицензию для компании. А к началу марта перешли порог 2000 MAU.
Возрастающая нагрузка больше не позволяла приложению работать по той схеме, которую выбрали для бэкенда изначально, — хранить полные модели досок одной записью. С такой схемой мы смогли прожить не больше года.
Ко второй итерации мы пришли с новым решением:
-
отказались от хранения досок целиком: нужно, чтобы каждый объект на доске сохранялся и передавался отдельно;
-
БД стали единственным источником правды;
-
изменения каждого объекта записывали сразу, а не раз в 20 секунд, как было раньше;
-
пользователь мог зайти, запросить данные доски из БД и быть уверенным в том, что эти данные актуальны, без ожидания синхронизации с другими пользователями.
Цифры внутри банка за два года:
-
> 75 тысяч досок;
-
> 30 тысяч пользователей;
-
3,5 тысячи уникальных пользователей в день;
-
сравнительно небольшой объем данных: 400 ГБ;
-
80 RPS в пике.
Архитектурную схему можно посмотреть и в Unidraw.
Технические детали проекта
Цифры по фронтенду: текущее количество циклических зависимостей в проекте — ~940.
Постепенно мы переходим на FSD — Feature-Sliced Design, чтобы построить масштабируемую систему и уйти от спагетти-кода, который достался нам от opensource.
Может показаться, что мы ругаем тот код, который взяли. На самом деле мы просто взяли крутые наработки и делаем их еще лучше.
Причины перехода на FSD:
-
не было идеи под структурой проекта;
-
не было единообразия;
-
отсутствовала композиция, что приводит к огромным файлам и большому количеству циклических зависимостей;
-
трудно работать с кодом: тяжело читать и понимать связи, сложный онбординг новичков;
-
нет масштабируемости на уровне структуры — развивая устоявшуюся структуру, пришлось бы увеличивать и без того большие модули.
FSD — это наиболее удачная имплементация луковичной архитектуры на фронтенде:
-
модули понятно делятся по зонам ответственности;
-
проще разрешать циклические зависимости;
-
модули небольшие за счет хорошей декомпозиции;
-
единообразие структур — проект декомпозирован по понятному принципу, поэтому легко находить и добавлять файлы;
-
проще понять, что собой представляет проект по слоям, существенно сокращается когнитивная нагрузка при разработке новых модулей и поддержании старых;
-
простой онбординг новых сотрудников.
Минусы: любой подход, решающий проблемы такого уровня, требует определенной квалификации. Нужно воспитывать понимание хорошей архитектуры за счет передачи знаний и опыта, а потом еще и контролировать соблюдение принципов. Это занимает время, а еще может вызывать сопротивление
Отрисовка графики. Раньше мы использовали Canvas API, и у него было несколько плюсов:
-
Простота освоения: API, не требующий глубоких знаний в области отрисовки. Большое количество разработчиков знакомы с ним как минимум на базовом уровне.
-
Сглаживание, которое работает без дополнительных инструментов.
-
Поддержка браузерами: работает во всех, даже старых, браузерах.
Главный минус Canvas API, по сравнению с WebGL, — производительность, поскольку Canvas API использует для отрисовки CPU, а WebGL — GPU. Это особенно заметно на досках с большим количеством элементов.
Рассматривали еще вариант перехода на KonvaJS. Это сложный и длительный процесс, который, несмотря на свои плюсы, мог дать ухудшение производительности. Мы решили не переписывать приложение под новую библиотеку, а доработать решение:
-
Использовать техники, примененные в KonvaJS, в уже готовом приложении. Например, разбиение на слои, функции рендера и редактирования текста элементов и тому подобное.
-
Переработать имеющуюся кодовую базу под нужные нам требования.
Для ускорения отрисовки мы решили перейти на WebGL-рендеринг. Проанализировали популярные библиотеки и фреймворки для браузерного рендеринга, среди которых выбрали PixiJS. Другие варианты не подходили по следующим причинам:
-
ThreeJS в первую очередь предназначен для работы с 3D-графикой. Большая часть функций будет не использоваться, а лишь выполнять дополнительные вычисления. Подавляющее большинство официальных примеров именно в 3D.
-
FabricJS. Нет поддержки WebGL.
-
PhaserJS, BabylonJS, PlayCanvas предназначены в первую очередь для игр — ориентированы на работу со спрайтами. У них слабые возможности для работы с графическими элементами.
PixiJS — это движок рендеринга графических объектов 2D. С ним можно анимировать и создавать интерактивную графику, рисовать приложения, и у него хороший API. А еще его легко адаптировать под свой стиль кодирования.
Плюсы перехода на PixiJS:
-
Значительный прирост производительности. Создали демоверсию Whiteboard с базовым неоптимизированным рендерингом PixiJS, которая показала 8-кратный прирост скорости.
-
Создали и оптимизировали для работы с 2D-графикой.
-
Проверенное временем решение с большим комьюнити (Miro тоже использует PixiJS).
-
Есть devtools-расширение для дебага.
-
Существуют дополнительные библиотеки для более продвинутого рендера, сглаживания и анимаций.
-
Есть возможность переложить hit-detection на событийную модель PixiJS.
-
Проще писать код без необходимости поддерживать «виртуальный» Canvas.
-
Используется батчинг отрисовки графических элементов (объединение нескольких отдельных небольших вызовов в один большой).
-
Есть встроенный механизм кэширования, который еще больше ускоряет отрисовку.
Особенности бэкенда. Старая архитектура:
-
выдерживала всего 1 500 пользователей (Х DAU);
-
за один год нагенерировали > 1 ТБ данных (при 1 500 пользователях);
-
до 10 человек на одной доске (с появлением задержек);
-
недоступность всей системы при 30+ человек на среднего размера доске (> 1 МБ).
С новой архитектурой у нас:
-
Неограниченное число пользователей (горизонтально масштабируемся).
-
400 ГБ за два года в Т-Банке (оптимизировали модель данных, стали хранить не доски целиком, а отдельно объекты).
-
Большие коллективные сессии на одной доске не оказывают влияния на систему в целом.
-
Не рассылаем оптимистичные изменения клиентам до тех пор, пока не запишем персистентно. Весьма дешевый способ, и хорошо работает при сравнительно небольшой нагрузке.
-
Stateless -приложение с быстрым временем восстановления.
Используем VPA — Vertical Pod Autoscaling, потому что стараемся осознанно подходить к утилизации ресурсов. С помощью VPA можно автоматически определить, сколько выдавать приложению RAM, CPU и других ресурсов.
По курсорам движения раньше отправлялись каждые 33 мс, что в теории позволяет добиться 30 фпс. На практике плавность без дополнительной обработки оставляла желать лучшего, при сетевых задержках или быстрых перемещениях участников по доске движение курсоров выглядело рваным.
Мы увеличили интервал до 200 мс и стали двигать курсоры алгоритмически: взяли две точки во времени и самостоятельно вычислили, с какой скоростью двигать курсор. Несмотря на то что теперь отправляем данные в 7 раз реже, реальная плавность, которая ощущается пользователем, стала выше.
Одно событие движения курсора весит 200 B. Вес события может меняться, например, если пользователь выделил какой-нибудь объект или двигает его. Если мы выделяем 16 объектов и двигаем их, размер сообщения уже 430 В. РПС в пике — 80, а количество операций по перемещению на доске — 250/с.
Есть еще область для улучшения скорости рендеринга. Мы планируем отделить состояние доски от жизненного цикла React, изменить управление состояния через ComponentDidUpdate и сделать свой отдельный Flow изменения модели. А еще хотим оптимизировать очень большие схемы, чтобы не было деградации отображения при Zoom.
Главная ошибка в пути
Мы не были готовы к большому количеству пользователей. Уделяя внимание работе с визуальной составляющей, мы рассчитывали чуть позже оптимизировать сервер по обмену сообщениями об изменении элементов модели.
Сама модель передачи данных, наследуемая от решения Open Source, была неудовлетворительной: модель доски полностью со всеми элементами передавалась по сети между реципиентами, работающими с этой доской. Это приводило к артефактам, когда на доске появлялось более пяти человек, и давало высокую нагрузку на сервер передачи данных.
Мы знали об этой проблеме и хотели полностью переписать сервис после того, как расширим функции для клиента новыми инструментами. Но приложение стали использовать и для презентаций разных идей на встречах, и однажды его использовали на внутреннем событии Demo Day, где уделили внимание и самому нашему приложению.
После этого у нас произошел кратный рост пользователей сразу в два раза — чуть более 2 500 WAU (5 000 MAU по итогу месяца). А такое количество пользователей дало значительную нагрузку на сервер.
Это повлияло на бэклог, и нам пришлось срочно решать проблему сетевого взаимодействия.
Нам пришлось уменьшать объем данных для каждого элемента, изменять функцию синхронизации модели, пересмотреть метод передачи сообщений.
Метод передачи сообщений сделали так, чтобы изменение одного элемента в рамках одного чанка вело к обновлению на сервере и у реципиентов только этого элемента и не приводило к передаче всей модели с измененным элементом.
Перед нами была схема, в которой вся модель доски сохранялась целиком. При этом операцию выполняли все пользователи, которые находятся на доске. Если пользователь менял элемент на доске, состоящей из 1 000 элементов, полезная нагрузка в этом случае была 0,1%.
Нам нужно было максимизировать полезную нагрузку и улучшить производительность.
Задачу осложняло то, что данные досок были зашифрованы end-to-end-шифрованием и в идеале мы хотели бы провести все изменения без даун-тайма.
Мы сделали так, что обновляется не вся доска, а каждое изменение элемента сохраняется отдельно.
Кейсы использования Unidraw
Ретроспектива — регулярное мероприятие в ИТ-командах для анализа предыдущей рабочей недели или итерации проекта, чтобы выявить успехи, проблемы и способы улучшения будущей работы.
Типов проведения online-ретроспектив много. Вот несколько примеров:
-
Карусель идей. Участники пишут идеи на карточках и обсуждают их по кругу.
-
Дерево решений. Проблемы записываются как ветви дерева, а решения — как листья.
-
4-Quadrant Model. Участники делят проблемы на четыре квадранта: важно и срочно, важно, но не срочно, не важно, но срочно, не важно и не срочно.
Unidraw часто используется для построения стратегий, потому что упрощает коммуникацию, стимулирует творческое
Активное участие в заполнении Unidraw делает процесс стратегического планирования более интерактивным и интересным для участников. Вот несколько способов, как он используется.
Визуализация целей и миссии:
-
Mind Mapping. Создание мозгового штурма для визуализации цели компании, ее ценностей и ключевых направлений стратегии.
-
SWOT-анализ. Запись сильных сторон, слабых мест, возможностей и угроз на отдельных секторах Unidraw, что помогает ясно увидеть позицию компании на рынке.
Brainstorming и генерирование идей:
-
Brainwriting. Участники по очереди записывают свои идеи на стикерах, которые размещаются на Unidraw для группового обсуждения.
-
Проектирование сценариев. Разработка возможных сценариев развития компании и их влияние на стратегию.
Структуризация процессов и планирование:
-
Kanban-доска. Визуальное представление задач, этапов разработки и прогресса по каждому направлению стратегии.
-
Визуализация процесса выполнения проекта. Используется, чтобы следить за тем, как выполняются проекты и перешли ли они временной рубеж относительно процента выполнения.
-
Gantt Chart. Создание графика выполнения ключевых задач и этапов реализации стратегии в течение определенного времени.
Командная работа и совместное решение:
-
Sticky Notes. Использование цветных стикеров для обозначения приоритетов, категорий или мнений по различным аспектам стратегии.
-
Круглый стол. Unidraw служит центральным инструментом для обсуждения идей, комментирования предложений и принятия совместных решений.
Визуализация результатов:
-
Сводная таблица. Ключевые выводы и решения, принятые во время стратегической сессии, структурируются на Unidraw с помощью табличной сортировки стикеров, а по ссылке на эту доску ими можно поделиться.
-
Наглядные графики. Представление данных о ключевых метриках, прогрессе реализации стратегии или результатах ее применения.
Unidraw часто используется при сессиях наставничества для визуализации при объяснении разных ситуаций, с которыми может столкнутся протеже.
Планирование и целеполагание:
-
Определение целей. Можно записать общие цели наставничества или конкретные задачи, которых хочет достичь подопечный за определенный период.
-
Создание Roadmaps. Визуализировать план действий с этапами развития и ключевыми мероприятиями, чтобы отслеживать прогресс и корректировать путь по мере необходимости.
Обсуждение проблем и выработка решений:
-
Mind Mapping. Используя его, наставник и подопечный могут вместе проанализировать проблему, разложить ее на составляющие части и генерировать варианты решения.
-
Sticky Notes. Каждому из вариантов решения может быть присвоен цветной стикер с кратким описанием плюсов и минусов. Это помогает сделать сравнение и выбор лучшего решения более интерактивным.
Обмен знаниями и опыт:
-
Sharing Knowledge. Можно записывать ключевые фразы из обсуждений, ссылки на полезные ресурсы или выводы из опыта наставника. Это поможет подопечному запомнить информацию и применять ее в будущей работе.
Отслеживание прогресса:
-
Kanban-доска. Помогает визуализировать текущее состояние работы над задачами и прогресс в достижении целей наставничества.
-
To Do, In Progress, Done — этапы для каждой задачи.
Сбор обратной связи:
-
Можно создать раздел для сбора обратной связи от подопечного о ходе наставничества, что поможет наставнику улучшить свою работу и сделать ее более эффективной.
Unidraw может использоваться для массы других задач. Еще один список мы спрятали тут:
-
Построение Road Map по задачам. Поделиться ссылкой со всеми участниками достаточно просто, а в рамках коллективных обсуждений можно выявить слабые места выбранного плана.
-
Обучение и тренинги. Для проведения онлайн-обучения позволяет создать визуальную часть контента с путем его прохождения и постепенным открытием для студентов.
-
Репетиторство. За счет возможности рисования карандашом, сохранения шаблонов, вставки картинок и рисования примитивов репетитор может онлайн объяснять студенту предметы, при этом сохранить все материалы в кабинете и возвращаться к ним при необходимости.
-
Бизнес-процессы. Сделать визуализацию схем бизнес-процессов, рисуя не только BPMN-схемы, но и более простые визуализации для объяснения сути поставленных задач и архитектуры и дизайна процессов.
-
Mockup. Unidraw используется как простая версия Figma, в которой на схемах можно объяснить построение концепции дизайна. Во многих случаях, если у команд уже есть свой фреймворк для дизайна, схемы расположения нужных блоков бывает достаточно, а Unidraw — хороший, простой инструмент с низким порогом вхождения в инструмент для вашего бизнеса.
-
CJM, исследования. Построение пути клиента — один из хороших аналитических инструментов для бизнеса и выявления слабых мест бизнес-процесса. Записывая на стикерах по этому пути примечания, выявленные в рамках исследования действий клиента, можно легко объяснить проблемные места коллегам из команды.
-
Описание структуры, управление персоналом. На Unidraw легко визуализировать организационный дизайн, что повышает прозрачность в компании для коллег, особенно за счет возможности коллективного обсуждения этой схемы. Такой подход нивелирует риски конфликтов при реструктуризации организации.
-
OKR. Визуализация общих целей и обсуждение их с командой в рамках одной доски позволяет сохранять не только сами цели, но и артефакты обсуждения, проблемы, связанные с достижением целей.
-
Архитекутра ПО, Domain-Driven Design. Unidraw используется для визуализации архитектуры программного обеспечения, проведения сессий по DDD. За счет бесконечного пространства схемы архитектуры и DDD могут быть нарисованы в рамках одной доски, что с использованием ссылок на доске и поиска позволяет легко производить навигацию по всей схеме.
Оставлю ссылку на открытую доску kanban-метрик, чтобы можно было посмотреть, как все выглядит в работе.
Голосование за новые фичи
С ростом внутренней пользовательской базы количество запросов на изменения, связанные с работой, стало обретать сильное влияние. Используя оценки, пожелания и вопросы, мы изменили свой Road Map в достижении этих целей. При этом бэклог задач явно рос быстрее роста возможностей команды, что привело нас к решению расширять команду, а также выбору новых фич с учетом существующего функционала.
Одним из запросов было добавление новой работы механики стрелок, желание сделать более простой интерфейс, добавление картинок в большом количестве и сразу по несколько, добавление жирного, наклонного текста и ссылок, которые можно вставлять прямо в текст.
А вот возможность создавать объекты мы отодвинули в бэклог, потому что, используя Hotkeys, пользователи получали возможность быстро создавать нужные элементы и без визуального контроля для этих целей. Такие удобные возможности мы не откладываем насовсем, а лишь на некоторое время в пользу наиболее востребованных функций.
Отмечу, что запретов на использование других приложений у нас в компании не было, а высокий Retention (выше 65%) вместе с ростом MAU дает команде большой импульс к дальнейшему развитию продукта.
Наши планы
Наша задача — сделать максимально комфортной совместную работу людей.
Модуль презентации будет доделан. Мы будем его добавлять, потому что есть внутренняя потребность.
Будем расширять историю с мобильной версией, потому что у нас очень много пользователей с мобилки. Но и ставим в план какие-то базовые вещи: добавить реакции, сложные виджеты, доступ по ссылке без регистрации, рисование через нажатие на точку от объекта.
Мы стараемся слышать наших пользователей и улучшать продукт вместе с ними, поэтому запустили телеграм-канал. Пользуйтесь и оставляйте обратную связь по доработкам!
Автор: DrWells