Русский
Русский
English
Статистика
Реклама

Saas-сервис

Как мы делали поддержку виджетов для приложений в МоемСкладе

21.03.2021 04:16:09 | Автор: admin

Всем привет! В эфире Маркетплейс МоегоСклада. В прошлый раз мы рассказывали о том, как мы запустили маркетплейс приложений в SaaS-сервисе МойСклад. Сегодня продолжим о том, как мы даем возможность приложениям расширять пользовательский интерфейс сервиса. Наверное, многие сталкивались в десктопных приложениях с подобными плагинами, которые при подключении добавляют в приложение какие-то свои кнопочки, пункты меню и даже целые наборы новых окон и диалогов, а также встраивают свои собственные UI-блоки в существующие экраны. А как сделать такое в SaaS-сервисе, UI которого работает в браузере?

Зачем вообще нужно встраивание в UI?

На старте Маркетплейса для приложений общего назначения единственный доступный способ интеграции приложений с МоимСкладом это интеграция по данным через общее JSON API. Через это API серверные части вендорских приложений могут получать и изменять пользовательские данные. Таким образом, на старте у нас была возможность только интеграции бэкендов приложений и МоегоСклада между собой. Добавить кнопочку или виджет на форму редактирования приложения не могли.

Изначально было очевидно, что этого не достаточно для предоставления конечным пользователям максимального удобства в использовании приложений. С другой стороны, внешним разработчикам и интеграторам приходилось колхозить свои механизмы в UI у них был выбор или непосредственно встраиваться в HTML веб-приложения МоегоСклада через плагины браузера или делать отдельные интерфейсы (UI) на своей стороне, во многом дублирующие функциональные возможности экранов в МоемСкладе (например, списки документов с фильтрами).

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

В общем, уже на старте было понятно, что UI-плагины это must have фича, которую надо делать.

Для начала на самом старте мы сделали простейшую возможность приложению встраивать свой iframe на отдельной вкладке. Этого позволяло закрыть такие базовые сценарии как, например, настройка приложения пользователем после установки. Но хотелось большего.

И вот пришло время занятся UI-плагинами для приложений уже по-серьезному.

Виджеты. Начало

Мы начали с того, что сформулировали общее видение возможных вариантов встраивания, зафиксировали базовые технические требования и посмотрели как обстоит дело в других SaaS-сервисах.

Первой фичей мы решили сделать поддержку виджетов на экранах редактирования сущностей и документов. Виджет представляет собой прямоугольный блок в UI, содержимое которого определяется приложением.

Пример виджета на экране редактирования контрагента:

Основной сценарий работы с виджетами выглядит так:

  1. Разработчик приложения указывает в дескрипторе приложения в какие места он хочет вставить виджеты

  2. Пользователь МоегоСклада устанавливает это приложение

  3. Пользователь заходит в то место, в которое приложение встраивает свой виджет

  4. Система отображает обычный интерфейс МоегоСклада для этого места со встроенным в него виджетом приложения

Из важных технических требований мы определили следующие:

  • Изоляция виджетов. Виджеты не должны иметь техническую возможность сломать верстку основной страницы. Как понятно, это ограничивает гибкость встраивания, но зато позволяет оставить за собой (в бОльшей степени) контроль за стабильностью работы UI (очень важно для наших пользователей) и его удобством (UX).

  • Отсутствие дергания при загрузке страницы. При открытии экрана с виджетами не должно быть дергания элементов на экране. То есть, например, виджеты должны открываться на экране сразу в нужном размере, а не скакать на экране при подгрузке в них кода и контента.

  • Однократная загрузка/инициализация кода виджета. Учитывая, что UI МоегоСклада это SPA, то хотелось бы воспользоваться преимуществами этого и для виджетов: загружать код виджета и строить DOM-дерево виджета один раз за время жизни вкладки браузера, тем самым ускоряя работу UI в целом по сравнению с полной загрузкой виджета с нуля при очередном открытии формы редактирования документа с виджетом. Тем более, что для наших внутренних компонентов и экранов у нас уже использовался подобный подход с кэшированием.

Как у других?

Для анализа мы выбрали несколько зарубежных SaaS-сервисов (Jira, Salesforce, Zendesk) и несколько наших российских (amoCRM, Битрикс24, InSales). Задача была посмотреть с технической точки зрения как устроено там и учесть этот опыт в нашем решении вопроса.

На что мы обращали внимание при анализе:

  1. Что собой представляет само приложение: SPA ли это как у нас или что-то другое?

  2. Как устроено взаимодействие виджетов и хост-окна (хост-окном называем родительское окно, куда встраивается iframe с виджетом), как разработчик указывает куда именно встраивать виджет, есть ли SDK для разработчиков (в части встраивания в UI)?

  3. Обеспечивается ли изоляция виджетов, откуда загружается код виджетов?

  4. Каким образом передается информация о текущем контексте в виджет. Под контекстом понимаем информацию о текущем пользователе, открытом экране и открываемом/редактируемом объекте или объектах.

Подробное изложение особенностей реализации в каждой системе тянет на отдельную статью. Здесь приведем некоторые общие выводы, которые мы сделали по результатам анализа.

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

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

  1. Содержимое виджета загружается в iframe с того же домена, что и сам сервис (что обычно требует размещения клиентского кода на серверах сервиса, хотя это не обязательно можно просто проксировать). И если при этом в атрибуте sandbox iframea указать ключевое слово allow-same-origin, то в этом случае есть возможность доступа к DOMу виджета из хост-окна и наоборот. Кто-то из сервисов использует это, например, для передачи контекста открытия виджету через JavaScript-переменную. Нам такой вариант изоляции не подходит (слабоват).

  2. Содержимое виджета загружается в iframe с домена вендора (или отсутствует указание allow-same-origin) в этом случае обеспечивается наиболее полная изоляция, при которой отсутствует доступ к DOM-дереву хост-окна из виджета и наоборот. Это как раз нужный нам уровень изоляции. В этом случае взаимодействие хост-окна с виджетом возможно только сообщениями через postMessage, что, конечно, менее прямолинейно, чем прямые JavaScript-вызовы между хост-окном и виджетом. Тем не менее, если завернуть на стороне виджета вызовы postMessage и прием сообщений в удобное JS SDK то это не будет практически ничем отличаться от прямых JavaScript-вызовов.

И большинство проанализированных сервисов имеют такое JS SDK. У нас тоже были планы сразу начать делать такое JS SDK и предоставлять вендорам API взаимодействия в его терминах, но ограниченность ресурсов и насущная потребность выкатить виджеты на прод внесли свою корректировку и мы решили начать делать наше API на голом postMessage и сериализуемых JavaScript-сообщениях.

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

Что касается описания параметров встраивания виджетов (например, куда встраивать и прочие требуемые системой параметры) для этого обычно используется JSON-структура (манифест). Мы здесь пошли немного другим путем и применяем XML технические параметры интеграции приложений с МоимСкладом разработчики описывают в виде XML-дескриптора (являющегося аналогом JSON-манифеста). Почему мы предпочли XML в эру повсеместного распространения JSONa об этом расскажем ниже.

XML-дескриптор приложения

Сразу приведем пример дескриптора приложения, чтобы было понятно, о чем далее пойдет речь:

<ServerApplication xmlns="http://personeltest.ru/aways/online.moysklad.ru/xml/ns/appstore/app/v2"                                 xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"                                 xsi:schemaLocation="http://personeltest.ru/aways/online.moysklad.ru/xml/ns/appstore/app/v2                          https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">    <iframe>        <sourceUrl>https://example.com/iframe.html</sourceUrl>        <expand>true</expand>    </iframe>    <vendorApi>        <endpointBase>https://example.com/dummy-app</endpointBase>    </vendorApi>    <access>        <resource>https://online.moysklad.ru/api/remap/1.2</resource>        <scope>admin</scope>    </access>    <widgets>                <entity.counterparty.edit>                        <sourceUrl>https://example.com/widget.php</sourceUrl>                        <height>                                <fixed>150px</fixed>                        </height>            <supports>                <open-feedback/>                <save-handler/>            </supports>            <uses>                <good-folder-selector/>            </uses>                          </entity.counterparty.edit>        </widgets>    <popups>        <popup>            <name>somePopup</name>            <sourceUrl>https://example.com/popup.php</sourceUrl>        </popup>        <popup>            <name>somePopup2</name>            <sourceUrl>https://example.com/popup-2.php</sourceUrl>        </popup>    </popups></ServerApplication>

Итак, почему же мы выбрали именно XML, а не JSON? Основной наш поинт был в том, что для XML есть стандартизованный широко распространенный формальный способ описания схемы XML Schema. Для JSON тоже есть аналоги например, JSON Schema. Но для JSON-схем (в отличие от XML-схем) нам были не совсем понятны их текущий статус развития, уровень поддержки в библиотеках и прочих инструментах, таких как IDE. Также мы не знали, насколько гибкие JSON-схемы функционально. Все это требовало дополнительного анализа, в то время как опыт работы с XML-схемами у нас уже был. В итоге мы решили не тратить ресурс на изучение возможностей JSON-схем, расценив, что сама по себе форма текста XML или JSON особой разницы для наших целей не имеет, а гибкости XML-схем нам должно хватить до определенного уровня.

Какие же преимущества дает нам наличие формальной схемы описания дескриптора? Основных два:

  1. Наличие формальной схемы позволяет нам использовать автоматические библиотечные валидаторы, снижая трудозатраты на разработку. Конечно, в любом случае мощность декларативного языка описания схем ограничена, и мы изначально были готовы к тому, что часть логики валидации где-то нам придется писать самим. Но чем больше можно описать в самой схеме тем меньше валидаций дописывать нам.

  2. Имея поддержку code completion для схемы в IDE мы по сути получаем на халяву UI для редактирования дескрипторов вендорами. Это позволяет нам использовать контекстно-зависимые структуры в дескрипторе (об этом ниже), максимизируя преимущество первого пункта без ущерба для удобства написания дескриптора вендором.

Вот, например, Intellij IDEA нам подсказывает, какие вообще точки расширения доступны для виджетов:

Так выглядит в IDE точка расширения только с поддержкой протокола open-feedback (что такое протоколы - расскажем ниже):

А так выглядит точка расширения с более полным набором доступных протоколов:

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

Модель описания виджетов в XML-дескрипторе

Приложения могут встраивать виджеты в разные места (точки расширения) системы. Например, у нас пару десятков (или даже больше) типов документов. Для каждого типа документа свой экран редактирования и это отдельные точки встраивания. Хотелось бы добавлять новые точки расширения итеративно, так как каждая новая точка расширения требует разработки и тестирования. Оптимально было бы в первую очередь сделать и зарелизить точки расширения, наиболее востребованные вендорами. И уже потом доделывать остальные. Или может даже отложить доделку в пользу более приоритетных продуктовых задач. Хорошо бы иметь возможность на уровне схемы дескриптора задавать какие точки расширения есть в наличии на сейчас.

В разных точках расширения виджетам может быть доступен разный функционал. Другими словами, каждая точка расширения теоретически может иметь свой набор параметров. Здесь примерно такая же ситуация, как с точками расширения если мелкие фичи достаточно легко добавлять сразу во все точки расширения, то крупную фичу, затратную в разработке, стоит сначала сделать и запустить для одной точки, посмотреть для начала как она взлетит, получить обратную связь от вендоров, возможно что-то доработать и потом уже масштабировать на всю систему. Или, например, в каких-то точках расширения может быть специфичный только для этих точек функционал, который просто не применим в других местах. Хорошо бы иметь возможность на уровне схемы дескриптора для конкретной точки расширения описывать доступный в ней функционал.

Учитывая два вышеизложенных соображения мы остановили свой выбор на следующей структуре описания, в которой имя точки расширения является XML-тегом:

<widgets>    <some.extension.point1>...</some.extension.point1>    <some.extension.point2>...</some.extension.point2></widgets>

Вместо, например, такой возможной:

<widgets>    <widget location="some.extension.point1">...</widget>    <widget location="some.extension.point2">...</widget></widgets>

Выбранный вариант позволяет нам явно и просто определять в XML-схеме свои собственные структуры (подсхемы) для каждой точки расширения по отдельности. Если для каких-то точек расширения подсхемы одинаковые то эти точки расширения в схеме могут ссылаться на один и тот же тип. С учетом этого, а также возможности наследования для сложных типов в XML-схеме, мы эффективно избавляемся от дублирования кода в самой XML-схеме.

О каком функционале в точках расширения идет речь и зачем вообще это выносить в дескриптор? Почему бы просто для каждой точки расширения в документации не указать, что может делать виджет, какой функционал ему доступен и какие параметры он может задать для виджета в этой точки расширения?

Рассмотрим на примере:

<document.customerorder.edit>    <sourceUrl>https://example.com/widget.php</sourceUrl>    <height>        <fixed>150px</fixed>    </height>    <supports>...</supports>    <uses>...</uses></document.customerorder.edit>

Здесь sourceUrl и height являются общими параметрами для всех виджетов. Параметр sourceUrl задает откуда будет загружен код виджета в iframe, а height описывает высоту блока виджета (как вы помните, у нас есть требование про отсутствие дергания поэтому начали мы с поддержки только фиксированный высоты для виджета, которую пока нельзя изменять, а ширина у нас одинаковая для всех виджетов по дизайну UI).

Если мы захотим сделать поддержку динамической высоты (определяемой виджетом при открытии страницы с ним) в какой-то специфичной точке расширения (где, например, дёргание страницы несущественно), то мы сможем на уровне схемы дескриптора сделать так, что указывать <height><dynamic/></height> можно будет только для этой точки расширения. И вендор уже на этапе написания дескриптора будет знать это работает только здесь. Это снижает риск того, что вендор не уследит, сделает виджет в расчете на <dynamic/> и обнаружит, что оно не работает в требуемой точке расширения на более позднем этапе разработки при тестировании или отладке.

С supports и uses ситуация интересней. Об этом далее.

Протоколы и сообщения

Для описания интерфейсов взаимодействия МоегоСклада с виджетами мы используем понятия протоколов и сообщений (на самом деле модель описания API чуть сложнее, но в рамках данной статьи опустим второстепенные детали):

Рассмотрим на примере следующего описания виджета в дескрипторе:

<document.customerorder.edit>    <sourceUrl>https://example.com/widget.php</sourceUrl>    <height>        <fixed>150px</fixed>    </height>    <supports>        <open-feedback/>        <save-handler/>        <change-handler>            <expand>agent</expand>            <expand>positions.assortment</expand>        </change-handler>    </supports>    <uses>        <good-folder-selector/>    </uses></document.customerorder.edit>

Итак.

Протокол это конкретный набор спецификаций взаимодействия приложения, расширяющего UI МоегоСклада и МоегоСклада, как платформы. Протокол может включать в себя в общем случае разные типы взаимодействия, например такие как HTTP и обмен сообщениями по postMesssage. В протокол может входить несколько сообщений.

Протоколы мы делим на несколько типов.

Основной протокол это протокол, который обязательно должен поддерживать виджет/плагин определенного типа (зависит от типа плагина). Не требует явного объявления виджетом. Например, для виджетов основной протокол включает в себя указание параметров sourceUrl и height, загрузку кода виджета в iframe по HTTP с передачей контекста текущего пользователя и отправку хост-окном postMessage-сообщения Open с указанием идентификатора открываемой пользователем сущности или документа.

Пример встраивания виджета в DOM-дерево страницы МоегоСклада:

Пример сообщения Open:

{  "name": "Open",  "messageId": 12345,  "extensionPoint": "entity.counterparty.edit",  "objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c",  "displayMode": "expanded"}

Дополнительный протокол это дополнительный (к основному) протокол, который может поддерживать плагин. Требует явного объявления в теге supports в дескрипторе (в блоке плагина). Перечень доступных дополнительных протоколов зависит от точки расширения.

В нашем примере выше в теге supports для виджета указаны три дополнительных протокола. Посмотрим на них подробнее.

оpen-feedback (протокол без параметров) поддержка виджетом этого протокола означает, что при открытии экрана редактирования система закрывает виджет заглушкой и убирает заглушку, отображая содержимое виджета, только при явном получении сообщения OpenFeedback от виджета. Это нужно для того, чтобы виджет успел перерисовать свое содержимое для вновь открываемого объекта. Иначе вследствии кэширования виджета пользователь может какое-то время видеть состояние для объекта, который пользователь открывал до этого.

Заглушка выглядит как простая рамка с таким же серым фоном как и сама страница:

Пример сообщения OpenFeedback:

{  "name": "OpenFeedback",  "correlationId": 12345}  

save-handler (протокол без параметров) если виджет указывает поддержку этого протокола, то хост-окно при нажатии пользователем кнопки Сохранить отправляет виджету сообщение Save.

Пример сообщения Save:

{  "name": "Save",  "messageId": 32109,  "extensionPoint": "entity.counterparty.edit",  "objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"}

сhange-handler (протокол с параметрами) на примере этого протокола, который на момент написания статьи еще находится в разработке, можно видеть, что есть возможность определять параметры для дополнительных протоколов (аналогично параметрам для основных протоколов). Виджет, объявляющий поддержку протокола change-handler, начинает получать от хост-окна данные о редактируемом пользователем объекте в режиме онлайн при изменении какого-либо атрибута объекта (например, при добавлении нового товара в заказ покупателя) хост-окно отправляет виджету сообщение Change с JSONом с данными объкета. С помощью параметров протокола expand вендор может дополнительно запросить замену ссылок на объекты аналогично тому, как это делается у нас в JSON API (в первом релизе change-handler будет без поддержки допольнительных параметров expand).

Сервисный протокол это протокол, который реализует хост-окно с целью предоставления плагину некоторого сервисного функционала. Перечень доступных сервисных протоколов зависит от точки расширения. Для использования сервисного протокола плагином требуется явное объявление указание сервисного протокола в теге uses в дескрипторе (в блоке плагина). Сервисы похожи на дополнительные протоколы, но отличаются своей узкой направленностью взаимодействия виджет -> хост-окно в режиме запрос-ответ.

Пример сервисного протокола good-folder-selector. Этот сервис виджетам приложений переиспользовать существующий в МоемСкладе селектор группы товаров с получением виджетом результата выбора пользователя. Работает это так:

1. Виджет отправляет хост-окну сообщение SelectGoodFolderRequest (например, при нажатии пользователем какой-либо кнопки в виджете):

{  "name": "SelectGoodFolderRequest",  "messageId": 12345}

2. Хост-окно открывает встроенный в МойСклад селектор:

3. Пользователь совершает выбор и хост-окно возвращает виджету результат в сообщении SelectGoodFolderResponse:

{  "name": "SelectGoodFolderResponse",  "correlationId": 12345,  "selected": true,  "goodFolderId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"}

Обязуя вендора статически указывать для виджета поддерживаемые дополнительные протоколы и используемые виджетом сервисы мы получаем следующие возможности и преимущества:

  1. Возможность указания вендором параметров протокола, если таковые у протокола имеются.

  2. С помощью XML-схемы дескриптора вендор может узнать в каких точках расширения какие протоколы поддерживаются, а мы можем статически провалидировать дескриптор на корректность при (при загрузке вендором дескриптора в систему).

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

  4. Зная, какой именно дополнительный и сервисный функционал используют виджеты мы можем оптимизировать работы хост-окна. Например, если виджеты на экране не используют change-handler, то хост-окно может вообще не инициализировать соответствующий функционал, экономя ресурсы компьютера пользователя (чтобы может быть важно для больших масштабных SPA-приложений типа нашего).

Альтернативой статического указания протоколов для виджета в дескрипторе могло бы быть динамическая регистрация при загрузке виджета (например, через какое-нибудь сообщение Init через postMessage, которое бы виджет отправлял при загрузке своего кода в iframe. Конечно, все вышеперечисленные пункты возможностей и преимуществ статического способа можно повторить и в динамическом, но это может потребовать больше ресурсов для разработки (нужно собирать метрики из браузера), больше ресурсов в рантайме (процессор, память на клиенте и сетевой трафик). При этом, ориентируясь только на динамические метрики, мы уже не так достоверно сможем определять что именно используют виджеты например, если где-то в уголке лежит редко используемое пользователями приложение, запускаемое раз в месяц (и которое запускалось последний раз месяц назад). Тем не менее, динамические метрики тоже полезны и хорошо дополняют статические в плане реальной картины происходящего на проде.

Как работают виджеты

Как это работает всё вместе и какие именно функциональные возможности есть у наших виджетов на текущий момент можно прочитать в документации. Дублировать это здесь наверное будет излишним.

Что дальше?

Что у нас есть еще на текущий момент и какие дальнейшие планы?

Из интересного хотелось бы отметить кастомные попапы. Это возможность виджету открыть большое попап-окно с содержимым, определяемым приложением. Попап-окно по завершению своей работы может вернуть результат виджету. Кастомные попапы являются основным протоколом аналогично виджетам. В открываемом попапе находится iframe, в который загружается код попапа аналогично коду виджета. Виджет взаимодействует с попапом используя postMessage-сообщения через посредничество хост-окна. Подробнее о кастомных попапах с примерами можно посмотреть в документации.

На момент написания статьи активно работаем над упомянутом выше протоколом change-handler. В планах дальнейшее развитие этого направления протокол update, который позволит виджетам обновлять данные редактируемого объекта в хост-окне.

Идеи на перспективу:

  • Завернуть голое взаимодействие через postMessage в удобное JavaScript/TypeScript Widget SDK для вендоров

  • Постепенное распространение поддержки виджетов и соответствующих протоколов на всех экранах МоегоСклада

  • Новые типы UI-плагинов (новые типы точек расширения) например, такие как:

    • Кнопки действий, пункты в выпадающих или контекстных меню

    • Столбцы в гридах

    • Кастомные вкладки

  • Стандартные модальные диалоги

  • Дальнейшее развитие возможности использования виджетами существующих интерфейсных объектов МоегоСклада

  • Взаимодействие между виджетами одного приложения

  • Навигация внутри UI МоегоСклада

  • Доступ к эндпоинтам RESP API через Widget SDK

Объем работы по расширению возможностей интеграции в UI нашего сервиса огромный мы планомерно двигаем наш SaaS-продукт в сторону гибкой, максимально расширяемой и удобной платформы для разработчиков приложений.

При этом МойСклад активно помогает вендорам с продвижением и продажей приложений рассказывает пользователям МоегоСклада о новых приложениях в email-рассылках и соцсетях, проводит совместные с вендорами вебинары для пользователей МоегоСклада, продвигает приложения баннерами внутри сервиса.

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

Подробнее..

Из песочницы Работа с enterprise как мы не сделали систему аналитики для SaaS сервиса

08.08.2020 16:12:48 | Автор: admin
Мы сильно обрадовались новому контракту и уже представляли, как логотип клиента приукрасит наше портфолио. Но все оказалось не так радужно. Расскажем, как мы работали с дочкой крупной российской IT-компании, и почему у нас не получилось сделать крутой проект.



О проекте


Продукт клиента SaaS в сфере B2B, который работает по формату абонентской платы. Пользователь регистрируется, проходит авторизацию, пополняет свой счет и использует сервис.
Наша задача помочь клиенту собрать аналитику. Для этого нужно было выстроить процессы колл-центра, внедрить CRM и свести сквозную аналитику по ключевым показателям.

Структура процессов


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

  1. Менеджеры отвлекались на ненужные этапы воронки продаж, и их работа никак не контролировалась;
  2. Отчеты по продажам ежедневно выгружались из админки вручную;
  3. Было мало конверсионных событий для сбора аналитики.

Далее сделали карту со структурой взаимодействия всех систем. В ней показано, по какой логике должны идти события, и на каких этапах собирается аналитика. Основные данные берем из CRM и соотносим их с данными по рекламе и конверсиям. Собираем в myBI, визуализируем в Power BI.

Воронки продаж


Продажи у клиента велись в Enybox CRM, их мы перенесли в amoCRM для удобства интеграции. Логику продаж получилось собрать в три воронки.


Три последовательные воронки

Первая воронка консультации. Нужна была, чтобы довести клиента до регистрации на платформе. Вторая воронка фиксация первых оплат. Далее пользователь подтверждал свою регистрацию. А мы, в свою очередь, отмечали момент оплаты и каждое новое пополнение.

Как должна была работать аналитика


Изначальные события Итоговые события
Форма обратной связи Форма обратной связи
Регистрация в сервисе Регистрация в сервисе
Первое пополнение
Тестирование (опционально при небольшом пополнении)
Повторные пополнения
Отказ от использования (прогрев через ОП)

Для нормальной работы системы аналитики нужно собирать все события = отмечать конверсионные действия. События уже попадали в систему аналитики, но изначально их было только два типа, что недостаточно для отчетов.

Отображение данных


Пример дашборда

После того, как собирались данные по конверсиям, нужно было сделать из них отчет. Основной инструмент визуализации данных Microsoft Power BI.

В момент конверсии на сайте генерировался отдельный ID для синхронизации рекламных систем и CRM. По этому ID мы связывали данные расходов и доходов. Так мы соотносили данные и могли строить по ним отчеты.

Юнит экономика. Retention



График rolling-retention'а сервиса с 1 по 12 месяц

Retention показывает, насколько пользователи вовлечены в приложение, и как часто они в него возвращаются. Но из-за того, что сервис работает в формате пополнений, пришлось поменять этот показатель на rolling-retention. Он показывает то же самое что и ретеншн, но подразумевает что все время, которое пользователь не пополнял кабинет, он тоже использовал сервис.

Конверсия в первое пополнение



Конверсия сильно зависела от количества новых клиентов и начала их оплат. Первые 9 месяцев мы получали примерно по 430 новых регистраций и по 90 оплат от новых пользователей ежемесячно. Конверсия в покупку в месяц регистрации составила 20%, по данным за 12 месяцев.

Помимо стандартных показателей


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

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

Что пошло не так


В самом начале инициаторы проекта отложили старт до осени (обратились весной). Такие пробелы в работе происходили не раз. Но мы не задумывались об этом и принимали как должное. Главными проблемами были коммуникация и бюрократия в процессах нашего клиента. Так можно изобразить весь временной отрезок работы над проектом:



Медленная разработка


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

Все менеджеры и разработчики на их стороне работали по двухнедельным итерациям. Но они постоянно ставили наш проект последним по приоритету и часто наши задачи не попадали в спринт.

Плохая коммуникация и отсутствие экспертизы


За время проекта менеджер со стороны клиента (стейкхолдер) поменялся пять раз. Наверное все знают то чувство, когда проект, над которым ты работаешь вдруг становится не интересен клиенту. Но даже это можно решить.

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

Представьте себе воронку продажи, как на рисунке выше. В одном из этапов менеджерам нужно узнать как дела у клиента. Как думаете, что произойдет с аналитикой конверсий такой воронки?

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


Факапы с нашей стороны


Мы не учли пропускную способность системы. На одно событие платформы в пике мы передавали до 10 запросов к amoCRM, чтобы выполнить логику бизнес-процессов.

100 000 ивентов в сутки * 10 запросов к amoCRM = 1 000 000 запросов в сутки

1 000 000 запросов в сутки / 10 запросов в секунду (ограничение амо) = 100 000 секунд = 27 часов

Итог: синхронизация никогда не закончится

Изначально выбрали amoCRM, так как проходи по лимиту запросов к системе. Но с течением развития проекта требования и функции увеличились и мы уперлись в лимит.
Мы выбрали неподходящий инструмент. AmoCRM физически не подходит для обработки большого количества запросов.
Также ошибка была в том, что мы разрабатывали все на GO, и за это отвечал один специалист. Когда он ушел, осталась гора legacy кода, который никто не смог бы разобрать. Но, к сожалению, или к счастью это не было нужно.

Опять все сломали


Этот кейс еще один пример проекта, который закопали в согласованиях и куче неоправданного менеджмента.

Нам не хватило экспертности в техническом плане. Клиенту устойчивости в управлении и желания довести проект до конца.

Но это опыт. Благодаря ему теперь подобные задачи выглядят максимально тривиально и мы уже воспроизвели подобное решение в рамках другого проекта.

Как можно было избежать неудачи


Чтобы не повторять таких кейсов в будущем, мы выделили аспекты, которые нужно соблюдать в работе с enterprise клиентами.

  1. Держать контакт с менеджером проекта: понимать его мотивацию; помогать ему защищать презентации перед руководителями. Делать все, чтобы стейкхолдер не потерял интерес к проекту.
  2. Соблюдать структуру коммуникации. Все важные чекпоинты проекта фиксировать по почте. Все обсуждения на встречах собирать в краткое резюме. Так специалистам со стороны клиента будет проще находиться в контексте действий. Не нужно будет каждый раз восстанавливать цепочку событий.
  3. Определять мотивацию специалистов со стороны клиента при старте работ. Если проект не стоит в их KPI и он изначально в низком приоритете завершить его будет практически невозможно.
  4. Думать наперед. Даже при разработке MVP нужно смотреть, на узкие места, которые могут возникнуть в будущем. Проект всегда расширяется и важно предусмотреть структуру, чтобы не переписывать весь код с нуля.



Автор статьи Фёдор Анисимов, маркетолог LAND PRO.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru