Коллаборативные приложения позволяют пользователям удобно взаимодействовать друг с другом в едином окне. Однако реализация таких решений сопряжена со сложностями — нужно обеспечить удобство интерфейса и сохранение всех значимых изменений так, чтобы в проекте не возникало конфликтов.
Денис Сарипов, Software Engineer в Yandex, рассказал о том, в чем заключается проблематика коллаборативных приложений, и какие архитектурные паттерны в них используются, чтобы обеспечить согласованность изменений и стабильность системы.
Что такое коллаборативные приложения
Коллаборативные приложения — это программные решения, которые обеспечивают одновременное взаимодействие нескольких пользователей в едином цифровом пространстве. То есть изменения, внесенные одним участником, синхронно отображаются у остальных. Чтобы обеспечить такую механику, в приложениях используется облачная инфраструктура, механизмы синхронизации и контроля версий.
Коллаборативные приложения часто используются для рабочих задач, обеспечивая синхронное взаимодействие нескольких специалистов при создании одного продукта. Вот несколько примеров:
- Figma — облачная платформа для проектирования интерфейсов и графического дизайна. Использует модель многопользовательского редактирования в реальном времени, поддерживает векторные и растровые форматы, а также инструменты для прототипирования.
- Google Docs — текстовый редактор, интегрированный в экосистему Google Workspace. Поддерживает совместное написание и редактирование документов, создание комментариев и просмотр истории изменений.
- Canva — веб-приложение для создания графического контента. Обеспечивает доступ к библиотекам шаблонов и элементов дизайна, поддерживает командную работу в режиме реального времени.
Также к коллаборативным приложениям можно отнести многопользовательские онлайн-игры — взаимодействие игроков в них реализуется через сетевую архитектуру (клиент-сервер или peer-to-peer). В играх синхронизируются игровые состояния, поддерживаются голосовые и текстовые чаты в реальном времени, а также взаимодействия персонажей.
Проблематика коллаборативных приложений
Ключевой вызов коллаборативных систем заключается в необходимости совмещать интерактивность — то есть быструю реакцию на действия пользователя — с устойчивостью к конфликтам при одновременном редактировании. Пользователи должны видеть изменения в реальном времени, и чтобы при этом работа других участников не мешала их собственному процессу.
Вот с какими неудобствами могут столкнуться пользователи при взаимодействии с коллаборативными приложениями:
- Конкурирующие изменения
Несколько участников могут редактировать один и тот же фрагмент (например, абзац текста в Google Docs или элемент интерфейса в Figma) — и при внесении конкурирующих изменений могут потеряться правки другого пользователя.
- Оптимистичные изменения
Когда пользователь вносит изменения в проект, они отображаются мгновенно, но «под капотом» система отправляет их в фоновом режиме на сервер и резолвит конфликты других пользователей. Но бывает, что на сервере происходит сбой, и изменения не синхронизируются с ним — это необходимо отображать в интерфейсе.
- Перегруженный интерфейс
Если система визуализирует все вносимые в реальном времени изменения, и пользователей достаточно много, то интерфейс может стать перегруженным и медленным из-за моментальной отрисовки правок и разрешения конфликтов. Разрешение конфликтов каждого из юзеров может значительно увеличивать нагрузку каждого из клиентов в определенные промежутки времени.
Также это может вызвать большую нагрузку на архитектуру и сбои в работе. Если приложение не обладает высокой стабильностью и отказоустойчивостью, это приведет к несохраненным изменениям — и, как следствие, задержкам в редактировании проекта.
- Наличие разных возможностей доступа и необходимость приватных изменений
В команде может быть несколько ролей — например, дизайнер, проджект-менеджер и клиент. Первому необходим полный доступ к драфту, второму — только возможность комментирования, а третьему — просмотр. Если все пользователи будут обладать равными правами, возникает риск некорректных изменений или даже удаления критически важных данных. Также не все изменения требуют общего доступа. Например, пользователь может создавать драфт в Canva и дорабатывать его, чтобы потом выложить в общий доступ для редактирования. Если система не поддерживает настройки приватности, может возникнуть путаница — над какими именно элементами можно работать командно, а какие еще будут редактироваться владельцем.
Таким образом, проблематика коллаборативных приложений сводится к поиску компромисса: дать каждому пользователю ощущение присутствия команды и коллаборативной работы, но при этом иметь отзывчивый интерфейс, получать ожидаемый результат при конфликтных изменениях и сохранять устойчивость системы. Решение этих задач зависит от выбранных архитектурных паттернов, алгоритмов синхронизации и продуманного интерфейса.
Архитектурные паттерны для коллаборативных приложений
Чтобы справиться с указанной проблематикой, при построении архитектуры коллаборативных приложений используются следующие паттерны.
- Operational Transform (OT). Этот алгоритм позволяет при получении команды трансформировать все последующие команды — если это необходимо. OT используется для согласования в редактировании данных — например, при правке текстового документа в Google Docs. При применении OT приложение отображает изменения не по порядку, как обычно, а с учетом намерений каждого пользователя и протокола взаимодействия.
- CRDT (Conflict-free Replicated Data Types). Это типы данных, которые можно реплицировать на множество узлов и обновлять параллельно, без координации между узлами. Главная идея CRDT состоит в том, что все изменения ассоциативны, коммутативны и идемпотентны. Это значит, что независимо от порядка операций и количества их повторов результат у всех участников будет одинаковым. В отличие от OT, при использовании CRDT можно построить систему без единого источника правды, однако ресурсоемкость здесь выше.
- Coarse Grained подход. Этот паттерн обозначает использование постоянных (lock, локи) или временных (lease, лизы) блокировок во время редактирования элемента. Coarse-Grained Lock — так называемая грубая блокировка, которая накладывает ограничения на сам объект, связанные с ним элементы и даже иногда на всю систему. Подход Fine-Grained Lock блокирует только мелкие единицы данных — например, текстовую строку. Coarse-Grained Lease — это арендная блокировка, которая выдается на крупный ресурс целиком (например, на всю базу данных или на кластерный узел). Она исчезает самостоятельно через заданный период.
- Merge-later (ветвление и последующее слияние). При применении этого паттерна изменения каждого пользователя сначала собираются в отдельной версии системы, а затем объединяются с общим проектом. Паттерн применяется на различных репозиториях, где важно контролировать версии кода (например, Git, GitHub), а также в приложениях с возможностью офлайн-редактирования (например, Google Docs). Для разрешения конфликтов между одновременными изменениями могут использоваться дополнительные паттерны — например, OT или CRDT.
- Приоритет по времени изменения или по роли редактора. Это наиболее простой паттерн, при котором предпочтение в редактировании отдается по приоритету. С его применением система становится более стабильной и требует меньше ресурсов, но в ней могут возникнуть конфликты — например, при внесении одновременных изменений двумя редакторами с одинаковыми правами доступа.
Простые паттерны (coarse-grained подход, приоритетный подход, merge-later) имеет смысл применять, если для функционирования приложения доступно ограниченное количество ресурсов, или над проектом работает небольшая команда, и одновременные конфликтующие правки крайне редки. При планах на предстоящее масштабирование приложения оптимальнее использовать более сложные подходы — OT и CRDT.
Сравнение OT и CRDT
Эти два подхода действуют по одному принципу — изменения в проект вносятся на основе намерений всех пользователей и учитывают каждое действие для формирования единого согласованного результата. Однако у них есть определяющее отличие. Если в OT существует единый источник правды, на основе которого обрабатывается и принимается каждое изменение, то CRDT настроен так, что в принципе избегает конфликтов, и источник правды здесь не нужен.
| OT | CRDT | |
|---|---|---|
| Принцип работы | Каждое изменение в проекте применяется с учетом его порядка, контекста и намерения пользователя. | Система учитывает изменения каждого пользователя и производит слияние всех операций, чтобы пользователи получили единый результат. |
| Серверы | Обычно требует наличия централизованного сервера, на котором происходят все операции. | Действия совершаются в децентрализованной сети, координация между узлами не обязательна. |
| Ресурсоемкость | Затрачивается меньше ресурсов на процессор и память клиента, но больше нагрузки на сервер. Однако на сервере обрабатываемая нагрузка легко увеличивается, поэтому проблем не возникает. Но здесь нужно больше временных ресурсов разработчиков для оценки корнер-кейсов различных конфликтов и их обработки. | Меньше ресурсов уходит на обработку проблемы, так как паттерны изначально созданы, чтобы избегать конфликтов. При этом много клиентских ресурсов уходит на содержание medata (алгоритмы генерации ID, дополнительные свойства сущностей) . Также изначальный дизайн архитектуры сложнее, и труднее добиться точности разрешения конфликтов. |
| Масштабируемость | Хорошо работает в системах с несколькими десятками или сотнями редакторов, где необходимо принимать во внимание каждое изменение. | Подходит для крупных или быстро масштабируемых систем с тысячами и миллионами пользователей, где нужно сохранить консистентность проекта. |
| Использование | Централизованные системы или системы, нуждающиеся в точном разрешении конфликтов. | Распределенные системы или системы, в которых не нужно детальное разрешение конфликтов. |
Таким образом, CRDT применяется там, где небходима распределённая система или точность разрешения конфликтов не высока (чем точнее, тем сложнее проектируется система). А OT используется для систем с обязательной централизацией и максимально точным разрешением конфликтов.
Заключение
Выбирая архитектурные паттерны для проектирования коллаборативных приложений, необходимо в первую очередь ориентироваться на задачи. Так, простые паттерны хуже справляются с конфликтующими изменениями — но это не значит, что от них следует отказываться. Если ресурсоемкость вашего приложения не так велика, а количество пользователей небольшое, то лучше сделать выбор в пользу простых решений, чтобы не перегружать систему.
При выборе паттернов важно учитывать:
- количество ресурсов;
- необходимость офлайн-доступа;
- число одновременно взаимодействующих пользователей;
- прогнозы масштабирования;
- наличие различных прав доступа.
Исходя из этого, можно выбрать наиболее подходящие паттерны, которые помогут выполнять поставленные задачи и поддерживать стабильность системы.
Также можно объединять подходы. Например, в Figma используется и OT, и CDRT, так как для сохранения консистентности проекта здесь нужна не distributed system, а сервер как источник правды. При этом нет необходимости в высокой точности, так как намного меньше случаев редактирования одного и того же текста, как это часто бывает в Google Documents.


































