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

Инструкция

Интеграция Netsparker с AD через Keycloak

16.12.2020 14:07:22 | Автор: admin

Привет, Хабр!

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

Забегая вперед, стоит отметить, что аналогичные шаги помогут настроить интеграцию с AD не только Netsparker, но и иных приложений, которые не имеют собственных средств взаимодействия с Active Directory.

Netsparker это коммерческий динамический сканер веб-приложений, который позволяет обнаруживать большое количество уязвимостей в реальном времени и при этом располагает широким набором средств для интеграции с различными инструментами разработки и сборки. Это позволяет осуществлять поиск уязвимостей еще до того, как приложение выходит в производственную среду.
Подробнее: https://www.netsparker.com/

Keycloak решение с открытым кодом, которое способно выступать промежуточным звеном между приложением и сторонним аутентификационным сервисом. Это часто необходимо в случаях, если требования к аутентификации превосходят возможности приложения или имеющаяся инфраструктура позволяет сделать бесшовную аутентификацию между всеми используемыми сервисами (SSO).
Keycloak позволяет интегрировать ваши приложения с внешними системами аутентификации пользователей, может выступать в качестве посредника для использования social login сервисов и многое другое.
Подробнее: https://www.keycloak.org/

Проблема

По умолчанию в Netsparker есть несколько вариантов внедрения Single Sign-On: с Google Cloud, PingIdentity, Okta, Azure AD, ADFS, а также базовая интеграция при помощи SAML2.0.

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

Проблема: Netsparker не работает напрямую с ADПроблема: Netsparker не работает напрямую с AD

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

Общая схема выглядит так:

Схема интеграции Netsparker с AD через KeycloakСхема интеграции Netsparker с AD через Keycloak

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

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

Приступим.

Экспорт конфигурации Netsparker SSO

Первый шаг. Чтобы включить Single Sign-On в Netsparker необходимо сделать следующее:

  1. Войти в Netsparker под административным пользователем и открыть Settings Single Sign-On.

  2. Поставить флажок Enable для включения поддержки SSO.
    (!) Опция Enforce to authenticate ... нужна для того, чтобы запретить пользователям без прав администратора вход напрямую в Netsparker с использованием пароля.
    Остальные поля мы заполним чуть позже данными из Keycloak.

    Экран настройки Netsparker SSOЭкран настройки Netsparker SSO


    После включения функции SSO на странице входа в Netsparker появится дополнительная ссылка для доступа через внешний сервис.
    Вот так это будет выглядеть для неаутентифицированного пользователя:

    Экран входа в Netsparker для неаутентифицированного пользователяЭкран входа в Netsparker для неаутентифицированного пользователя
  3. Справа на закладке SAML скачиваем базовый XML с метаданными Netsparker.
    Этот XML содержит настройки SAML-клиента (в нашем случае им является Netsparker), которые понадобятся для конфигурирования Keycloak, например Client Identifier, SAML Service URL.

    Сохранение SAML мета-данных NetsparkerСохранение SAML мета-данных Netsparker

На данном этапе с Netsparker'ом всё. Переходим в Keycloak.

Конфигурация Keycloak

  1. Заходим в панель администратора Keycloak и создаем новый Realm с названием, например, Netsparker.
    Realm это раздел, в котором будет храниться вся конфигурация, касающаяся конкретно нашего приложения (Netsparker), включая настройки синхронизации с AD, собственная база пользователей и т. п.

    Экран добавления Realm'аЭкран добавления Realm'а
  2. Теперь необходимо в этом Realm прописать нашего клиента (Netsparker), который будет пользоваться услугами Keycloak.
    Переходим на закладку Clients, нажимаем Create, импортируем XML, который сохранили из Netsparker.

    Экран добавления клиента KeycloakЭкран добавления клиента Keycloak

    Данные формы подгрузятся из файла, поэтому нажимаем Save.

  3. В открывшемся экране настроек клиента сразу сохраняем себе в блокнот данные сертификата (закладка SAML Keys).

    Данные сертификата клиента KeycloakДанные сертификата клиента Keycloak
  4. Возвращаемся на закладку Settings и вносим следующие изменения:

    Client Signature Required ставим в положение OFF, т. к. Netsparker пока не передает данные о своем алгоритме подписи, и поэтому SAML-запрос получается некорректным.
    Valid Redirect URIs модифицируем URL и заменяем часть строки адреса ?spid на *. Это поле задает шаблон для адресов, на которые Keycloak разрешено осуществлять перенаправление браузера. Это сделано для того, чтобы злоумышленник не мог подставить адрес подконтрольного ему сервиса.

    Настройки клиента KeycloakНастройки клиента Keycloak


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

  5. Нажимаем Save и возвращаемся в Netsparker.

Конфигурация Netsparker

Теперь на стороне сканера добавляем данные о провайдере аутентификационных данных (сокращенно IdP), в нашем случае это Keycloak.

  1. Донастроим то, что мы начали настраивать на первых шагах.
    Снова открываем страницу Netsparker Settings Single Sign-On и прописываем идентификатор IdP и URL для SAML-запросов.

    У Keycloak эти значения стандартные:
    IdP Identifier:
    https://<домен-где-установлен-Keycloak>/auth/realm/<наш-Realm>
    SAML Endpoint:
    https://<домен-где-установлен-Keycloak>>/auth/realms/<наш-Realm>/protocol/saml
    X.509 Certificate:
    Сертификат в base64, который мы сохранили из Keycloak.

    Настройка SSO в NetsparkerНастройка SSO в Netsparker
  2. Сохраняем конфигурацию, и на данный момент у нас уже есть базовая возможность пользоваться аутентификацией Keycloak.

    При нажатии на Sign in via your Identity Provider открывается промежуточная форма ввода email пользователя из Netsparker, из которой уже осуществляется переход на форму входа Keycloak. Пользовательские данные, вводимые на этой форме либо проверяются в базе пользователей Keycloak, либо прокидываются дальше на AD (мы посмотрим оба варианта).

    После успешного входа в Keycloak нас должно перенаправить обратно в Netsparker уже в аутентифицированном состоянии.

    Процесс входа в NetsparkerПроцесс входа в Netsparker


    Но чтобы это произошло, надо сперва сконфигурировать пользователей.

Создание пользователей вручную

Netsparker

Для начала заведем тестового пользователя в Netsparker для проверки интеграции.

  1. В Netsparker открываем Team New Team Member, заполняем поля Name, Email и проставляем какие-нибудь разрешения (те, что на снимке, выбраны просто для примера):

    Экран создания пользователей в NetsparkerЭкран создания пользователей в Netsparker
  2. Активируем пользователя, кликнув на код подтверждения на странице Invitations.

    Список "приглашенных" пользователейСписок "приглашенных" пользователей
  3. На открывшейся странице вводим пароль для созданного пользователя и нажимаем Create an account.
    Этот пароль будет использоваться, только если пользователь решит войти в Netsparker не через SSO, а через обычную форму входа:

    Экран регистрации нового пользователя NetsparkerЭкран регистрации нового пользователя Netsparker

Keycloak

На данный момент войти в Netsparker через SSO не получится, т. к. в базе Keycloak в нашем Realm еще нет ни одного пользователя и Keycloak не сможет его аутентифицировать.

Исправим это:

  1. Заходим в Keycloak Manage Users, нажимаем Add user, вводим данные пользователя и сохраняем:

    Экран добавления пользователя в KeycloakЭкран добавления пользователя в Keycloak

    Здесь важно указать Username в виде email-адреса и поставить Email Verified в положение On, чтобы можно было бесшовно перейти от Keycloak к Netsparker.

  2. После сохранения появляется страница деталей пользователя. На ней в закладке Credentials необходимо установить пароль этому пользователю. Он при необходимости может отличаться от пароля в Netsparker:

    Создание пароля для пользователя KeycloakСоздание пароля для пользователя Keycloak

    Ставим Temporary в положение Off и устанавливаем пароль.

Промежуточная проверка интеграции

Теперь можем убедиться, что наша интеграция Netsparker+Keycloak работает:

  1. Открываем страницу входа в Netsparker и выбираем Sign in via your Identity Provider.

  2. Вводим почтовый адрес нашего тестового пользователя и попадаем на страницу входа в Keycloak.

  3. Указываем аутентификационные данные созданного пользователя.

    Экран входа в KeycloakЭкран входа в Keycloak
  4. Если всё прошло успешно, Keycloak перенаправит нас на главную страницу Netsparker под нашим тестовым пользователем.

    Перенаправление из Keycloak в NetsparkerПеренаправление из Keycloak в NetsparkerОсновной экран сканера NetsparkerОсновной экран сканера Netsparker

Промежуточный итог
Итак, на данный момент у нас есть возможность входить в Netsparker, вводя данные пользователя в Keycloak. Следующий шаг и реализация начальной цели связать аутентификацию Netsparker c аутентификацией на AD. При необходимости мы также можем синхронизировать базу данных пользователей Keycloak с базой Active Directory.

Следующий этап настройки: Keycloak + ADСледующий этап настройки: Keycloak + AD

Дорога в AD

Теперь сделаем следующий шаг и настроим аутентификацию пользователей Active Directory через Keycloak по LDAP. Для этого нам потребуется функция User Federation.

  1. Открываем Keycloak User Federation и в списке провайдеров выбираем ldap.

    Выбор провайдера аутентификации в KeycloakВыбор провайдера аутентификации в Keycloak
  2. Дальше настройка может отличаться в зависимости от конкретной структуры AD, но я опишу на базовом примере, что нам потребуется.

    В окне Add user federation provider заполняем поля:
    Vendor: Active Directory.
    Connection URL: путь к вашему серверу.
    Например ldap://172.16.2.23:389.
    Users DN: путь навигации к записям пользователя.
    Например CN=Users,DC=cx,DC=local.
    Bind DN: путь к записи администратора AD.
    Например cn=cxadmin,cn=users,dc=cx,dc=local.
    Bind Credential: пароль учетной записи администратора.
    Например ваш валидный пароль :)

    (!) Если мы хотим, чтобы данные из AD сперва синхронизировались в локальную базу Keycloak, ставим переключатель Import User в положение On.

    Опция импортирования пользователейОпция импортирования пользователей

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

  3. Дальше необходима небольшая манипуляция с данными из AD. Так как Netsparker требует в качестве имени пользователя его email-адрес (помните ремарку в начале?), нам надо убедиться, что во-первых из AD придут только пользователи с почтовым адресом и, во-вторых, что имя пользователя будет содержать этот адрес, а не иной параметр.

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

    Custom User LDAP Filter: (&(objectCategory=person)(mail=*)(objectClass=user)).
    Username LDAP attribute: mail.

    Сохраняем форму, и в итоге наш экран настройки должен выглядеть так:

    Сводная страница настроек LDAP провайдераСводная страница настроек LDAP провайдера
  4. Теперь сделаем так, чтобы при синхронизации пользователей AD они автоматически получали email в качестве имени пользователя. Для этого открываем закладку Mappers:

    Настройка mapper'овНастройка mapper'ов

    И в mapperе Username заменяем атрибут cn на mail.

    Настройка отображения email адреса на имя пользователяНастройка отображения email адреса на имя пользователя
  5. Сохраняем настройки.

(!) Если мы настраивали синхронизацию базы Keycloak с AD, мы можем проверить эту настройку, нажав Synchronize all users. Если всё прошло успешно, то на вкладке Users у нас появятся наши пользователи из AD'a:)

Проверяем, что всё работает

Можем убедиться, что наша настройка верна, войдя под учётной записью из AD в Netsparker.

  1. Проверяем, что в Netsparker есть пользователь с таким почтовым адресом (Manage Team). Какой у него пароль неважно, так как аутентификация будет происходить на стороне AD.

    Искомый пользователь NetsparkerИскомый пользователь Netsparker
  2. Открываем страницу Netsparker SSO и вводим email-адрес пользователя AD.

    Промежуточный экран входа в Netsparker SSOПромежуточный экран входа в Netsparker SSO
  3. На странице входа Keycloak вводим данные пользователя AD с паролем.

    Экран входа в KeycloakЭкран входа в Keycloak
  4. Нам должна открыться страница Netsparker для этого пользователя.

    Основной экран Netsparker для аутентифицированного AD-пользователя AlexОсновной экран Netsparker для аутентифицированного AD-пользователя Alex

Настройка автоматического создания пользователей

Вручную заводить новых пользователей зачастую неудобно, поэтому в Netsparker есть возможность упростить заведение новых учётных записей, которая называется auto provisioning. С ее помощью устраняется необходимость вручную добавлять нового пользователя: если его нет в базе данных Netsparker, то такой пользователь будет создан автоматически при попытке входа с верными данными своей учётной записи AD.

Дальше нам будет необходимо сделать небольшие изменения в конфигурациях Keycloak и Netsparker. Так как auto provisioning требует, чтобы сессия инициировалась Identity Provider'ом, давайте его и настроим:

Keycloak

  1. Открываем настройки нашего клиента Keycloak Clients наш клиент.

  2. Нам потребуется внести изменения в три поля:
    Valid Redirect URIs (опционально): можно оставить как было, а можно ограничить перенаправление конкретным клиентом (который задаётся параметром spid). Для этого копируем из настроек SSO Netsparke'а полный URL SAML 2.0 Service URL.
    IDP Initiated SSO URL: необходимо задать URL, который мы хотим использовать для нашего конкретного клиента (Netsparker), чтобы явно указать, что должно использоваться SSO, вызываемое со стороны IdP. Например netsparker. После этого пользователи смогут входить конкретно в Netsparker, используя URL из подсказки.
    Assertion Consumer Service POST Binding URL: URL, куда Keycloak будет отправлять SAML-данные для входа в Netsparker. Указываем здесь SAML 2.0 Service URL из настроек Netsparker'a.

    Дополнительная настройка клиента KeycloakДополнительная настройка клиента Keycloak
  3. Сохраняем настройки.

Настройка mappers

Чтобы Keycloak формировал SAML-запрос в виде, необходимом Netsparker'у, необходимо добавить в него несколько обязательных полей (FirstName и LastName). В этом нам поможет mapper, который автоматически назначит полям SAML соответствующие поля из пользовательской записи.

Для этого открываем Keycloak Clients Mappers и создаем mapper, нажав на Create.

Дополнительная настройка mapper'овДополнительная настройка mapper'ов

Содержимое полей mapper задаем как на картинке ниже:

Настройка SAML-mapper'а для имени пользователяНастройка SAML-mapper'а для имени пользователя

Аналогично создаём mapper для фамилии:

Настройка SAML-mapper'а для фамилии пользователяНастройка SAML-mapper'а для фамилии пользователя

Итоговый список должен выглядеть так:

Список mapper'овСписок mapper'ов

Netsparker

Последнее, что нам нужно сделать донастроить Netsparker, чтобы он создавал пользователей и принимал запросы на это действие от Keycloak.

  1. Открываем Netsparker Settings Single Sign-On.

  2. В поле SAML 2.0 Endpoint указываем URL из Keycloak из подсказки поля IDP Initiated SSO URL.

  3. Выбираем опцию Enable Auto Provisioning и сохраняем настройки.

    Настройка автоматического создания пользователей в NetsparkerНастройка автоматического создания пользователей в Netsparker

Финальная проверка

Теперь проверим как это всё работает.

  1. Прежде всего теперь на странице Netsparker Team можем удалить пользователя AD, которого мы создавали вручную.

    Удаление пользователяУдаление пользователя
  2. В Keycloak завершаем все сессии, чтобы они нам не мешали: Keycloak Manage Sessions Logout all.

  3. Открываем страницу Keycloak для SSO (напомню, Target IDP initiated SSO URL это ссылка вида:
    https://yourdomain.com/auth/realms/netsparker/protocol/saml/clients/netsparker).

  4. Вводим данные пользователя из AD.

  5. Если всё прошло успешно, в Netsparker будет создан соответствующий пользователь с минимальными правами и для него будет установлена новая сессия.

    Основной экран Netsparker для пользователя, автоматически созданного при входе через ADОсновной экран Netsparker для пользователя, автоматически созданного при входе через AD

Что дальше?

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

Если была выбрана опция auto provisioning, необходимо от имени административного пользователя выдать необходимые разрешения созданному пользователю, чтобы тот мог работать с Netsparker.

Для простоты лучше первый раз для создания пользователя входить через Target IDP initiated SSO URL и уже впоследствии аутентифицироваться либо по этому же URL, либо осуществлять вход через привычную страницу Netsparker Login.

Еще один нюанс в данный момент выход пользователя из Netsparker не приводит к выходу пользователя из Keycloak. Поэтому, когда в следующий раз мы решим войти при помощи SSO, нас сразу перебросит в Netsparker под последним аутентифицированным пользователем. Это можно решить, например, уменьшив длительность сессии пользователя в Keycloak. Тогда его SSO-сессия будет автоматически уничтожена после указанного промежутка времени.
Настройка осуществляется в Realms Netsparker Tokens:

Настройка длительности SSO сессииНастройка длительности SSO сессии

Также пользователь может вручную закончить свою сессию на собственной странице учётной записи Keycloak по ссылке вида: https://keycloak.yourcompany.com/auth/realms/netsparker/account
После этого для входа в Netsparker потребуется снова аутентифицироваться в Keycloak и можно будет осуществить вход под другим пользователем.

Заключение

Мы рассмотрели в деталях, как можно аутентифицировать пользователей Netsparker через Active Directory с использованием промежуточного решения Keycloak. В принципе, такой же процесс может быть применён и для других приложений, которые не работают с Active Directory напрямую, но поддерживают SAML для описания деталей аутентификации.
Keycloak позволяет достаточно гибко настраивать и дополнять систему аутентификации, комплексно закрывая этот аспект безопасности для приложений, используемых в организации.

Подробнее..

Что делать, если у вас почта в домене tut.by?

03.06.2021 14:23:54 | Автор: admin

18 мая 2021 года был заблокирован почтовый сервис mail.tut.by. Я предлагаю оставить политические/правовые и этические нюансы данного события и поговорить о практических.

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

Из немногочисленных сообщений в сети складывается впечатление, что компаниям TUT.by и hoster.by сейчас совсем не до спасения почтового сервиса. В целом, это вполне понятно, с учетом того, что речь идет о вполне реальных перспективах лишиться бизнеса в принципе и отхватить срок.

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

Шаг 1: попробуйте получить доступ к почте с помощью mail.yandex.by

Почта tut.by хостилась на почтовом сервисе от компании Яндекс. Это значит, что есть неплохие шансы того, что вы еще сможете получить к ней (возможно временный) доступ:

  1. Перейдите по адресу https://mail.yandex.by/

  2. Попробуйте авторизоваться с помощью вашего логина и пароля для почту tut.by

Если у вас получилось залогиниться - у вас есть возможность спасти (сохранить локально\распечатать\переслать на другой ящик) важные письма. После чего переходим к шагу 2.

Если нет - селяви. Пока (а может и вообще) ничего сделать нельзя, и Яндекс на встречу идти не планирует, упорно отправляя к "администратору домена tut.by", которого больше нет. В этом случае переходим к шагу 3.

Шаг 2: Настройте переадресацию на другой почтовый ящик

Настройте переадресацию на другой почтовый ящик - так, в случае последующей потери доступа к ящику tut.by вы сможете получать важные письма.

Внимание! К сожалению, переадресовывать письма из папки "Спам" не получиться. Для них придется создать отдельное правило.

Скоро я опубликую краткую видео-инструкцию, как это сделать.

Шаг 3: Постарайтесь найти все сервисы, привязанные к данному ящику

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

Шаг 4: Сообщите корреспондентам о смене почтового ящика

На данный момент неизвестно, насколько временный доступ к почте через mail.yandex.by, а, соответственно, как долго будет работать переадресация. Также есть риск неавторизованного доступа к вашей почте tut.by.

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

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

Что будет с ящиком в будущем?

Что в итоге произойдет с ящиком tut.by в Яндексе сказать трудно. Скорее всего, когда придет срок оплаты за пользование почтовым сервисом, и оплата не пройдет - ящик превратиться в тыкву, а с ним слетят все подписки на сервисах Яндекса, и могут стать недоступными другие подписки. И конечно, вы перестанете получать важные письма.

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

Подробнее..

NVMe Namespaces возможности и подводные камни

03.03.2021 16:23:30 | Автор: admin

Уверен, многие слышали про NVM Express, или просто NVMe. Изначально для меня это были просто быстрые диски. Потом я осознал, что это интерфейс для подключения этих дисков. Затем стал понимать NVMe как протокол для передачи данных по PCIe-шине. И не просто протокол, а протокол, разработанный специально для твердотельных накопителей!

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

Так что же такое NVMe? Рассмотрим подробнее.

Началось все с SATA-интерфейса. На самом деле до него существовала масса других интерфейсов SCSI, UltraSCSI, ATA, PATA и прочие, но это уже дела давно минувших дней. В этой статье мы рассмотрим только актуальные сейчас интерфейсы.

Скорость передачи данных по SATA-интерфейсу достигает 560 Мбайт/с, чего с лихвой хватает для HDD-дисков, производительность которых варьируется от 90 до 235 Мбайт/с (есть отдельные прототипы, скорость которых достигает 480 Мбайт/с). Но вот для SSD-дисков этого недостаточно, уже сейчас их производительность достигает от 3000 до 3500 Мбайт/с. SAS-интерфейс также не подойдет, его максимальная скорость всего лишь 1200 Мбайт/c.

Для того, чтобы реализовать весь потенциал твердотельных накопителей, великие умы решили использовать PCIe-интерфейс. Сейчас он позволяет передавать данные со скоростью от 8 до 32 Гбайт/c. Чтобы унифицировать подключение SSD к PCIe-интерфейсу, была разработана спецификация NVMe. Точно так же, как в свое время была создана спецификация для подключения USB-Flash-накопителей.

Полностью разбирать NVMe мы не будем. В этой статье я хочу поделиться с вами сильно заинтересовавшей меня особенностью NVMe Namespaces, или Пространства имен.

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

Ближе к NVMe


NVMe в Linux


Начну издалека. К изучению и поиску информации о пространствах имен меня побудил вопрос: Почему NVMe-диски в Linux называются именно так?

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

root@thinkpad-e14:~$ ls -l /dev/ | grep -E "nvme"crw-------  1 root    root    241,   0 окт 25 22:04 nvme0brw-rw----  1 root    disk    259,   0 окт 25 22:04 nvme0n1brw-rw----  1 root    disk    259,   1 окт 25 22:04 nvme0n1p1brw-rw----  1 root    disk    259,   2 окт 25 22:04 nvme0n1p2brw-rw----  1 root    disk    259,   3 окт 25 22:04 nvme0n1p3

Здесь перечислены все NVMe-устройства, подключенные к рабочей машине. Рассмотрим блочное устройства /dev/nvme0n1p1. Часть nvme, как ни странно, применяется для NVMe-устройств. Число, идущее следом, обозначает порядковый номер контроллера диска, который отвечает за все операции, производимые с накопителем. Заключительная часть p1 указывает на номер раздела на диске. И наконец, часть, которая заслуживает нашего внимания, n1. Это и есть номер пространства.

Для простоты можно также провести некоторую аналогию с обыкновенными SSD:

/dev/sda аналог /dev/nvme0n1
/dev/sda1 аналог /dev/nvme0n1p1

Обратите внимание на устройство /dev/nvme0. Это NVMe-контроллер. Он является символьным устройством. Таким образом, мы можем обращаться к нему, отправляя определенные команды, чем мы и воспользуемся далее.

Namespace vs Partition


У вас может возникнуть вопрос: чем namespace отличается от partition? Отбросим все возможности и преимущества NVMe Namespace. Partition это раздел диска на уровне хоста. Namespace же является разделом на уровне контроллера. То есть Namespace является неким логическим пространством, с которым хост работает как с блочным устройством.

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

Параметры NVMe-контроллера


Всеми операциями с данными занимается специальный NVMe-контроллер. Помимо этого, в своей памяти он хранит метаданные о себе и внутреннем устройстве информации: серийный номер, модель, всевозможные настройки диска, пространств, закрепленных за ним, формат данных и так далее.
Предлагаю рассмотреть их под микроскопом. Для этого я отправил контроллеру специальную команду, в ответ на которую он вернул метаданные. Позже я объясню, как это сделать, а сейчас взгляните на них. Так как данных достаточно много, я не стал вставлять их целиком, но вы обязаны знать, что те параметры, о которых я буду говорить далее, на самом деле существуют:

{  "vid" : 5197,  "ssvid" : 5197,  "sn" : "00000000000000",  "mn" : "00000000000000000000000000",  "fr" : "7L1QFXV7",  "rab" : 2,  "ieee" : 9528,  "cmic" : 0,  "mdts" : 9,  "cntlid" : 5,  "ver" : 66304,  "rtd3r" : 100000,  "rtd3e" : 8000000,  "oaes" : 512,  "ctratt" : 0,  "rrls" : 0,  "crdt1" : 0,  "crdt2" : 0,  "crdt3" : 0,  "oacs" : 23,  "tnvmcap" : 256060514304,  "unvmcap" : 0,  ...}

Метаданные хранятся в контроллере в виде последовательности байтов в порядке от старшего к младшему, поэтому далее я буду придерживаться следующего формата записи:
[интервал в байтах (формата Big-Endian)] / название параметра / расшифровка.

Пример для лучшего понимания. Следующая запись означает, что с 71 по 64 байт хранится значение параметра fr, который расшифровывается как firmware revision:

[71:64] / fr / firmware revision.
[23:4] / sn / serial number. Содержит серийный номер контроллера.
[63:24] / mn / model number. Содержит номер модели, или part number.
[71:64] / fr / firmware revision. Содержит номер ревизии прошивки контроллера.
[257:256] / oacs / optional admin command support. Указывает на наличие дополнительных команд и функций контроллера. Состоит он из 16 бит, каждый из которых отвечает за определенную команду. Если бит равен 1, то контроллер дает возможность:

  • [15:10] зарезервированы;
  • [9] получить статус LBA;
  • [8] получить доступ к дорбелл буферу (Doorbell Buffer Config);
  • [7] управлять виртуализацией (Virtualization Management);
  • [6] использовать команды NVMe-Mi Recieve и NVMe-Mi Send (NVMe Management Interface);
  • [5] использовать директивы (Directives);
  • [4] использовать команды для самопроверки (Self-Test Commands);
  • [3] управлять пространствами имен (Namespace Management);
  • [2] обновлять прошивку контроллера (команды Firmware Commit и Firmware Download);
  • [1] форматировать пространства имен (NVM Format);
  • [0] поддержка команд протокола безопасности (Security Send, Security Receive).

В данной статье мы затронем только те функции, которые относятся к пространствам имен, а именно Namespace Management и NVM Format. Если вас интересуют подробности о других функциях, можно обратиться к спецификации NVM Express Revision 1.4.

Параметры NVMe-пространств


Теперь рассмотрим метаданные NVMe-пространств:

{  "nsze" : 500118192,  "ncap" : 500118192,  "nuse" : 233042000,  "nsfeat" : 0,  "nlbaf" : 0,  "flbas" : 0,  "mc" : 0,  "dpc" : 0,  "dps" : 0,  "nmic" : 0,  "rescap" : 0,  ...  ]}

[7:0] / nsze / namespace size. Это максимальный размер пространства в логических блоках. В данном случае 500118192 512-байтных блоков, что, кстати, и указано в выводе blockdev:

root@thinkpad-e14:~$ sudo blockdev --getsz /dev/nvme0n1500118192

[15:8] / ncap / namespace capacity. Это количество логических блоков, выделенных пространству для хранения данных в текущий момент.

[23:17] / nuse / namespace use. Это количество логических блоков, занятых данными в текущий момент.

Обратите внимание, что параметры nsze и ncap равны. Какой смысл указывать максимальный объем и объем, который выделен в текущий момент? Значит ли это, что в текущий момент может быть выделено меньше, чем доступно? Да!

Дело в том, что пространства имен поддерживают технологию Thin Provisioning. Это означает, что пространству выделяется только часть от указанного объема. Другая часть будет оставаться в общем пуле и выделяться этому или другим пространствам по требованию: при заполнении выделенного объема или при достижении критического порога. В общем, эта технология позволяет эффективнее использовать ресурсы для хранения данных. Подробнее и нагляднее с этой технологией можно ознакомиться в этой статье.

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


ncap и nsize будут указывать на одно общий объем пространства. В случае с использованием тонкого распределения на диске пространство будет выглядеть так:


Здесь nsze указывает на максимальный объем, ncap на выделенный, а nuse в обоих случая показывает только то, что занято. Когда значение nuse достигнет значения ncap, то ncap увеличится, но не больше, чем nsze.

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

[24:24] / nsfeat / namespace features. Этот параметр особенно интересен. Он указывает на наличие дополнительных особенностей пространства. Состоит он из 8 бит (перечислены они тоже в Big Endian), каждый из которых отвечает за определенную функцию. Если значение бита равно 1, то функция активна, 0 нет:

  • [7:5] зарезервированы;
  • [4:4] поддержка дополнительных полей для оптимизации ввода-вывода;
  • [3:3] отключение переиспользования поля NGUID;
  • [2:2] поддержка делоцированных и незаписанных блоков (Context Attributes);
  • [1:1] поддержка дополнительных полей для атомарной записи (Atomic Operations);
  • [0:0] поддержка тонкого распределения.

[26:26] / flbas / formatted lba size. Этот параметр указывает на структуру LBA. Также состоит из 8 бит:

  • [7:5] зарезервированы;
  • [4:4] при значении 1: указывает, что метаданные будут храниться в конце блока; при значении 0: метаданные передаются отдельным буфером;
  • [3:0] позволяет выбрать один из 16 возможных форматов LBA.


[29:29] / dps / end-to-end data protection type settings. Указывает на тип сквозной защиты данных. Состоит из 8 бит:

  • [7:4] зарезервированы;
  • [3:3] указывает на тип передачи метаданных;
  • [2:0] указывает на наличие защиты данных и ее тип.

[30:30] / nmic / namespace multi-path and Namespace Sharing Capabilities. Это поле указывает на поддержку функций, связанных с мультидоступом к пространствам имен:

  • [7:1] зарезервированы;
  • [0:0] значение 1 указывает на то, что данное пространство является публичным (public namespace) и может связываться с несколькими контроллерами, а значение 0 на то, что пространство является приватным (private namespace) и привязывается только к одному.

На этом можно завершить краткий обзор параметров. Их количество огромно, что позволяет очень тонко настроить пространства имен под различные задачи, которые мы рассмотрим в конце статьи. Подробное описание каждого параметра можно изучить в спецификации NVM Express Revision 1.4.

Публичные и приватные пространства


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

Одним из этапов создания пространства является его закрепление за NVMe-контроллером. Доступ к пространству и будет осуществляться через тот контроллер, за которым оно закреплено. Но пространство может быть закреплено не только за одним контроллером приватное, но и за несколькими контроллерами публичное.

Если приватное пространство можно назвать обычным, так как из него ничего интересного слепить нельзя, то публичное пространство позволяет использовать такую возможность, как namespace multi-path.

Взаимодействие с NVMe


Приступим к вопросу взаимодействия с NVMe-устройствами: как посылать различные команды контроллеру, создавать пространства имен, форматировать их и т. д. Для этого в мире Linux существует утилита nvme-cli. С ее помощью и можно выполнять данные операции.

nvme list


Чтобы вывести список NVMe-устройств, не обязательно обращаться к devfs подобным образом:

root@thinkpad-e14:~$ ls /dev/ | grep "nvme"nvme0nvme0n1nvme0n1p1nvme0n1p2nvme0n1p3

Или использовать lspci, чтобы узнать что же такое подключено к машине:

root@thinkpad-e14:~$ lspci | grep -E "NVMe|Non-Volatile"07:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a809

Достаточно использовать команду nvme list:

root@thinkpad-e14:~$ nvme list -o json{  "Devices" : [    {      "NameSpace" : 1,      "DevicePath" : "/dev/nvme0n1",      "Firmware" : "9L1QFXV7",      "Index" : 0,      "ModelNumber" : "SAMSUNG MZALQ256HAJD-000L1",      "ProductName" : "Non-Volatile memory controller: Samsung Electronics Co Ltd Device 0xa809",      "SerialNumber" : "00000000000000",      "UsedBytes" : 38470483968,      "MaximumLBA" : 500118192,      "PhysicalSize" : 256060514304,      "SectorSize" : 512    }  ]}

В качестве примера я вывел информацию в формате JSON. Как вы можете наблюдать, здесь выводится не просто список устройств, а еще и различная информация о них. Думаю, что часть атрибутов (например, DevicePath или ModelNumber) в комментариях не нуждаются, поэтому обращаю внимание только на некоторые:

  • Index номер контроллера;
  • UsedBytes используемый объем пространства в байтах;
  • PhysicalSize максимальный объем пространства в байтах;
  • SectorSize формат LBA, или логического блока, минимального адресуемого блока данных;
  • MaximumLBA максимальное количество логических блоков.

nvme id-ctrl, nvme id-ns


Ранее в статье, чтобы получить метаданные об устройстве, я отправлял контроллеру команду Identify. Для этого я использовал команду nvme id-ctrl для идентификации контроллера:

root@thinkpad-e14:~$ nvme id-ctrl /dev/nvme0

И nvme id-ns для идентификации пространства:
root@thinkpad-e14:~$ nvme id-ns /dev/nvme0n1

Обратите внимание, что необходимо указать устройство контроллер или пространство имен.

nvme create-ns, nvme delete-ns


Создание пространств имен проходит в несколько этапов. Сначала его нужно сформировать. Для этого используется команда nvme create-ns:

root@thinkpad-e14:~$ nvme create-ns /dev/nvme0 --nsze 1875385008 --ncap 1875385008 --flbas 0 --nmic 1 --dps 0create-ns: Success, created nsid:1

Аргументы, которые указываются этой команде, вам уже знакомы. Мы их рассмотрели в разделе Параметры NVMe-пространств.

Для удаления пространства используется команда nvme delete-ns:

root@thinkpad-e14:~$ nvme delete-ns /dev/nvme0n1          delete-ns: Success, deleted nsid:1

nvme attach-ns, nvme detach-ns


Второй этап создания NVMe-пространств привязка к контроллеру сформированного пространства. Для этого необходимо использовать команду nvme attach-ns:

root@thinkpad-e14:~$ nvme attach-ns /dev/nvme0 --namespace-id 1 --controllers 1attach-ns: Success, nsid:1

Данной командой мы привязываем пространство с идентификатором 1 к контроллеру /dev/nvme0. Также обратите внимание на аргумент --controllers. Здесь перечисляются идентификаторы NVMe-контроллеров, к которым можно привязать пространство. Этот аргумент опционален и используется при создании публичных пространств.

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

root@thinkpad-e14:~$ nvme attach-ns /dev/nvme0 --namespace-id 1 --controllers 0                            NVMe Status:CONTROLLER_LIST_INVALID: The controller list provided is invalid(211c)

Чтобы отвязать пространство, используется команда nvme detach-ns:

root@thinkpad-e14:~$ nvme detach-ns /dev/nvme0n1 --namespace-id 1 --controllers 1detach-ns: Success, nsid:1

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

nvme reset


После привязки пространства к контроллеру, как правило, его можно использовать для работы. Однако случается так, что контроллер не может увидеть пространства. В таком случае его необходимо перезапустить использовать команду nvme reset.

nvme format


В случае если необходимо изменить формат LBA у пространства, на помощь приходит команда nvme format:

root@thinkpad-e14:~$ nvme format /dev/nvme0n1 --lbaf 0Success formatting namespace:1

Аргумент --lbaf указывает на формат LBA.

Однако эту команду также можно использовать и для безопасной затирки данных на NVMe-накопителе:

root@thinkpad-e14:~$ nvme format /dev/nvme0n1 --ses 1 -rSuccess formatting namespace:1

Аргумент --ses указывает на уровень затирки:

  • 1 удалить все данные;
  • 2 удалить зашифрованные данные.

Аргумент -r указывает на то, что контроллер будет перезапущен после безопасной затирки.

Применение


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

Spare Area


Начнем с довольно обычной практикой использования. Spare Area, или Резервная область, была придумана еще до NVMe. Это специальное пространство на твердотельном накопителе, которое используется самим контроллером для внутренних операций и недоступно хосту.

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


Соответственно, если мы уменьшим общий объем пространств, то оставшийся объем уйдет в пользу резервной области.

Если вы хотите узнать больше про резервную область, можете обратиться к этой статье.

Шифрование и изоляция



NVMe-диски поддерживают самошифрование по спецификации OPAL. Более того, для каждого пространства имен используются различные ключи шифрования.

Также контроллер предоставляет возможность защиты от записи. Существует три уровня:

  • только для чтения до следующей перезагрузки;
  • только для чтения до следующей перезагрузки после отключения функции защиты от записи;
  • только для чтения на протяжении всей работы.


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

Multiple Using


Как упоминалось ранее, пространства являются разделами на уровне контроллера, которые видны конечному хосту как отдельное устройство. А можно ли разделить NVMe-накопитель большого объема не несколько приватных пространств, каждое из которых затем выделить разным хостам? Можно! А с использованием сетевого протокола NVMe-oF (NVMe Over Fabrics) выделить эти пространства можно не только виртуальным хостам, но и физическим.

При таком использовании накопителя схема разделения будет выглядеть следующим образом:


NVMe-контроллер позаботится о том, чтобы пространства были изолированы друга от друга: данные будут храниться в отделенных друг от друга областях накопителя, у каждого хоста будет собственная очередь для ввода-вывода. Тем не менее, spare area, или резервные области, по-прежнему будут общими.

Namespace Multi-path и Namespace Sharing


Namespace Sharing, или Public Namespaces, подразумевает под собой возможность совместного доступа одного или нескольких хостов к пространству через два и более контроллеров.


Для чего это необходимо? На рисунке показана схема использования публичных пространств. Да, интересно: мы можем обратиться к пространству NS B через контроллер NVMe Controller 1 и NVMe Controller 2. Но я не вижу в этом какой-то полезности пока схема не будет выглядеть следующим образом:


Здесь мы видим, что контроллеры находятся на совершенно разных хостах и у нас есть несколько независимых путей к данным: через хост-контроллеры Host A (синие контроллеры) и Host B (фиолетовые контроллеры). Теперь это можно использовать для резервирования или для наращивания производительности: если синий путь будет сильно нагружен, то мы пойдем по фиолетовому.

Такой подход позволяет организовать высокопроизводительные и высоконадежные гибкие программно-определяемые СХД из обычных серверных платформ с использованием NVMe-oF.

Итог


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

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

Послесловие


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

  • Диски Samsung 970 EVO/970 EVO Plus с прошивками 2b2qexe7/2b2qexm7 не реализуют команды reset и format;
  • Диски Samsung 970 EVO/970 EVO Plus с прошивками 2b2qexe7/2b2qexm7 не реализуют управление пространствами при помощи команд create-ns, дelete-ns, detach-ns, atach-ns;
  • Диски Samsung PM991 с прошивкой 9L1QFXV7 имеют баг, из-за которого перезагрузка контроллера при помощи команды reset приводит к ошибке;
  • Диски Samsung PM991 с прошивкой 9L1QFXV7 имеют баг, из-за которого форматирование пространства при помощи команды format приводит к ошибке;
  • Диски Samsung PM991 с прошивкой 9L1QFXV7 не реализуют управление пространствами при помощи команд create-ns, delete-ns, detach-ns, atach-ns.

Я уверен, что диски из корпоративного сегмента лишены этих проблем, однако не всем по силам приобрести такие железки, поэтому подробно изучайте диски и мануалы по ним при покупке. А если есть возможность изучить диски до покупки и посмотреть параметры NVMe-контроллера, обязательно воспользуйтесь ею.

Полезные источники


  1. SSD: устройство, компоненты и принципы работы
  2. A Quick Tour of NVM Express
  3. NVMe 1.4 Specification
  4. NVMe Namespaces
  5. Base NVM Express Part One
  6. NVMe Command Line Interface (NVMe-CLI)
  7. NVMe Over Fabrics
  8. Также по теме

Подробнее..

Дизайнеру приложений как создать и передать в разработку тёмную тему

16.07.2020 12:18:27 | Автор: admin


В конце 2019 года зарелизили iOS 13 и Android 10 с поддержкой автопереключения на тёмную тему. Мы решили добавить её в приложение Ростелеком Ключ под iOS и Android, над которым работали в тот момент. В процессе не обошлось без сложностей. Рассказываем о нашем опыте, чтобы вы в аналогичной ситуации сэкономили время и нервы.

Зачем делать тёмную тему


Может показаться, что это всё на волне хайпа. Но не только :)

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

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

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

В нашем случае приложение РТ Ключ кросс-платформенный сервис для управления устройствами на территории дома: домофонами, шлагбаумами, камерами видеонаблюдения во дворе и в подъезде. Жители домов используют его как днём, так и ночью.

Справедливо заметить, что тёмная тема также помогает экономить заряд (для некоторых типов экранов: OLED/amoled да, LCD нет). А в долгосрочной перспективе она может замедлить развитие близорукости.

Как перейти на тёмную сторону: пошаговая инструкция


Если вы совсем ничего не знаете о тёмной теме, то можно начать знакомство со статей в Human Interface Guidelines для iOS и в Material Guide для Android. Там подробно разобрано, как цвета и слои взаимодействуют друг с другом в ночном режиме. Перейдём к нашим советам:

1. Приведите в порядок макеты и соберите UI kit

UI kit серьёзно ускоряет работу дизайнера и разработчиков. Обычно мы собираем его сразу после утверждения визуальной концепции на примере нескольких основных экранов приложения. В UI kit входят:

  • Цветовая палитра стилей для обычного состояния элементов, состояния при нажатии, цвета для неактивных элементов, инпутов в фокусе и так далее.
  • Текстовые стили.
  • Все элементы интерфейса (кнопки, поля ввода, элементы списков, блоки с заголовками и так далее) в различных состояниях и ситуациях в виде master components.
  • Сет иконок в черном цвете.
  • Иллюстрации.

UI kit нашего приложения можно рассмотреть в Figma.

Все последующие экраны собираем уже из готовых компонентов. Но при экспорте макетов из Sketch в Figma наш UI kit серьёзно пострадал: пришлось его обновить, заново назначить цветовой стиль для каждого элемента и пересобрать экраны из компонентов.

Все последующие экраны собираем уже из готовых компонентов. Но при экспорте макетов из Sketch в Figma наш UI kit серьёзно пострадал: пришлось его обновить, заново назначить цветовой стиль для каждого элемента и пересобрать экраны из компонентов.

2. Договоритесь о названиях цветов

Чтобы дизайнерам, iOS и Android-разработчикам было проще общаться между собой, цвета мы решили назвать универсально для обеих платформ. В прошлой версии UI kit цветовые стили мы обозначили незатейливо по номерам: C1, C2, C3 Это было не слишком удобно: при обсуждении все называли цвета не по цифрам, а по оттенкам: фиолетовый, оранжевый, чёрный и т. д.

Однако с появлением тёмной темы использовать оттенки в наименовании цветов стало невозможно: например, белый цвет фона в светлой теме сменился на тёмный. Значит, нужно было придумать новый принцип наименований.

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

  • Назначение цвета или элемент, на котором он используется.
  • Приоритетность использования (опционально).
  • Состояние элемента, если это применимо (опционально).


Слева наименования для цветов кнопки в обычном состоянии, при нажатии на iOS, цвет Ripple в Android и неактивная кнопка на обеих платформах. Справа имена для текстов на различных поверхностях

В общем, если в вашем проекте ещё нет UI kit, а вместо цветовых стилей назначены обычные цвета, пора причесать макеты.

3. Подберите цвета для тёмной темы

Катя Рокитян, дизайнер Redmadrobot:
Чтобы не тратить драгоценное время, мы не прорабатывали все макеты в тёмной теме, а выбрали только несколько экранов с принципиально различающимися компонентами. С их помощью мы подбирали удачные цвета и добавляли их в палитру. Затем разработчики обновляли цвета в коде приложения, готовили для нас тестовую сборку, а мы изучали, как тёмная тема смотрится живьём. Если выявляли ошибки, правили макеты и палитру.

3.1. Фоновый цвет

Начать перерисовку макета стоит с фонового цвета: он занимает большую часть экрана. В гайдах Material Design советуют брать за основу нейтральный тёмно-серый (#121212). Он, в отличие от черного, оставляет простор для построения глубины экрана.

Фоновый цвет должен хорошо сочетаться с цветом интерактивных элементов: кнопок, иконок и т. д. У нас в светлой палитре для интерактивных элементов использовался фирменный фиолетовый цвет Ростелекома #7700ff. В дальнейшей работе отталкивались от него.

Нейтральный тёмно-серый плохо смотрелся с брендовым фиолетовым, поэтому мы последовали советам гайдлайнов Material Design. Ребята рекомендуют наложить поверх нейтрального фонового серого #121212 фирменный цвет с 8% непрозрачности.


Нейтральные и брендированные цвета фона в тёмной теме

Помимо основного фона у нас встречаются карточки с небольшим подъемом над поверхностью. В Material Design рекомендуют в тёмной теме создавать элевацию элементов за счёт осветления фона: чем ближе карточка к пользователю, тем светлее.

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



3.2. Создание базовой палитры

В Material Design рекомендуют при создании брендированной тёмной темы заменять цвета на менее насыщенные аналогичного оттенка. В качестве фирменного цвета для РТ Ключ мы использовали фиолетовый.

При попытке осветлить его по рецепту Material Design его оттенок стал розоватым. Оригинальный фирменный цвет выглядел синее, поэтому мы вручную изменили его оттенок.


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

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

Navbar и крупные кнопки в осветленной фиолетовой версии особенно сильно отвлекали внимание от контента, а если мы снижали яркость, линейные иконки терялись на тёмном фоне.


В исходной светлой теме насыщенный фиолетовый цвет одинаково хорошо смотрится на крупных блоках с белым текстом и на тонких линейных иконках на светлом фоне. А на тёмном фоне всё не так

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


Заменили один фиолетовый на три так намного лучше

Помимо фиолетового мы использовали оранжевый, желтый, бирюзовый и красный. Оранжевый для call to action элементов, желтый для уведомлений, бирюзовый для подтверждения операции, красный для ошибок.

Когда мы осветлили эти четыре цвета по совету Material Design, серьезно изменилась контрастность приложения по сравнению со светлой темой. Пришлось отступить от гайдов: оранжевый, бирюзовый и красный мы не осветлили, а затемнили. Жёлтый оставили неизменным, поскольку при затемнении он грязнил.



3.3. Особенности палитры iOS

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

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


Оттеночный цвет (tint) в темной теме

В iOS заложена возможность менять цвет интерактивных элементов при нажатии. Это полезно, так пользователю сразу понятно, отреагировало приложение на его действие или нет.

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

3.4. Особенности палитры Android

В Android при нажатии на интерактивный элемент от точки прикосновения к нему расходится волна. Этот эффект называет ripple. По умолчанию ripple немного затемняет исходный элемент, а мы хотели его, наоборот, осветлять.

Your browser does not support HTML5 video.

Ripple в Android приложении

Также в Android есть особенности отрисовки status bar и navigation bar. Status bar строка состояния, где отображаются уведомления, уровень сигнала, заряд батареи и время. Navigation bar панель, где располагаются кнопки назад, домой и недавние приложения.

С появлением смартфонов с крупными дисплеями, доходящими до самого края устройства, челками и дырками под камеру, в Material Design представили концепцию edge to edge. Её суть в том, что служебные элементы не должны съедать полезную площадь, и как можно большее место на экране должен занимать полезный контент.

Для этого в Android доработали поддержку прозрачных status bar и navigation bar. Дело в том, что эти панельки не на всех телефонах имеют одинаковую высоту. И если до начала поддержки edge to edge мы назначали им прозрачный фон, на некоторых устройствах они некрасиво накладывались на контент экрана. Теперь в материальных компонентах появились системные отступы: разработчики могут определять размер status bar и navigation bar и задавать соответствующий отступ для контента. Поэтому раньше в Material Design рекомендовали выбирать непрозрачный фон для status bar и navigation bar, а теперь наоборот.

Однако важно учитывать, что не во всех поддерживаемых версиях Android можно назначить цвет иконок в системных компонентах:

  • до 6.0 иконки в status bar и navigation bar всегда белые;
  • с версии 6.0 можно задать, белыми или черными будут иконки в status bar, но navigation bar будет вести себя так, как в предыдущих версиях.
  • с версии 8.1 можно выбрать цвет иконок как в status, так и в navigation bar.

Чтобы избежать странных наложений на контент в Ключе, мы поступили так:

  • в старых версиях Android до 6.0 для обеих панелек задали черный фон с 50% прозрачности на нем хорошо смотрятся белые иконки;
  • с 6.0 и до 8.1 navigation bar остается с полупрозрачным черным фоном, а status bar полностью прозрачный;
  • с версии 8.1 фон обеих панелек полностью прозрачный.

Если вы по каким-то причинам не готовы к такой поддержке edge to edge, лучше сделать status bar и navigation bar универсальными. Поддержка edge to edge:

3.5. Проверьте контрастность элементов

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

Лучше всего проверять контрастность с помощью тестирования: открыть интерфейс на смартфоне, используя Figma Mirror или аналогичный софт, выйти на яркое солнце (тёмная тема предназначена для использования в темноте, но людям ничто не помешает использовать её на свету).

Также будет полезно попросить посмотреть на приложение людей с нарушениями зрения (близорукостью, дальнозоркостью, дальтонизмом). Но если такой возможности нет, контрастность можно проверить на сайте contrast-ratio или с помощью плагина в Figma.

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


Для тёмной темы приходится делать отдельные версии иллюстраций и анимаций в тёмных цветах

Как передавать в разработку

Мы работали в связке Figma + Zeplin. Это может показаться странным, но мы всей компанией перешли на Figma из Sketch в конце лета 2019, прямо перед началом работы нам тёмной темой. И чтобы сэкономить время на адаптацию разработчиков к новому инструменту, продолжили работать с Zeplin. И тут он преподнес нам несколько сюрпризов.

В палитре Zeplin нельзя создать цветовые стили с одинаковыми HEX. Поэтому нам пришлось незначительно, практически незаметно для глаза, менять HEX у фиолетового цвета в светлой теме.
Даниил Субботин, iOS-разработчик Redmadrobot subdan:
Обнаружилось, что ни один инструмент дизайнера, в том числе Zeplin, не поддерживает темную тему и поэтому не позволяет иметь несколько цветовых палитр в одном проекте. Пришлось искать пути обхода. Например, мы создали два проекта: один со светлой палитрой, а другой с тёмной.


1. Особенности iOS dev


Следующий сюрприз, который нам преподнес Zeplin: из него можно экспортировать только одну палитру в Xcode-проект. Либо светлую, либо тёмную. При попытке экспортировать цвета тёмной палитры Zeplin просто заменял ими все светлые. Мы стали переносить цвета вручную, копируя HEX-значения. То же самое делали и с изображениями.

Даниил Субботин, iOS-разработчик Redmadrobot subdan:
После долгих мучений я написал утилиту, которая выгружает обе цветовые палитры прямо в Xcode-проект, используя Zeplin API. Это сильно упростило жизнь. Дизайнер сообщает, что добавил новый цвет или изменил старый, я запускаю скрипт, и все изменения автоматически подтягиваются в проект

2. Особенности Android dev


На Android тёмная тема доступна на всех версиях ОС (мы тестировали начиная с пятой). Но переключать её в системе можно только на 10-м Android, поэтому стоит добавить в приложение возможность переключать её вручную.

Владислав Шипугин, android-разработчик Redmadrobot shipa_o:
Мы добавили следующие варианты выбора темы: всегда светлая, всегда тёмная, выбирается в зависимости от режима энергосбережения (9-я версия андроида и ниже), переключается в зависимости от настроек системы (10-я версия андроида и выше). Но важно учесть, что выбранная пользователем тема приложения в системе не сохраняется. Нужно запоминать её внутри и активировать при каждом запуске приложения


В Android есть своя система цветов для материальных компонентов (кнопок, app bar, текстовых полей и т. д.). Гайдлайны Material Design о цвете.

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

Как поддерживать и развивать


С тех пор как мы проработали тёмную тему, у нас добавилось несколько новых функций, появились планшетные пользователи, а продуктовый офис в Ростелекоме задумался о том, чтобы выпустить приложение РТ Ключ в виде white label для застройщиков в их фирменных цветах.

Оля Сартакова, арт-директор Redmadrobot:
Мы поняли, что текущую версию дизайна, разработанную для запуска MVP, пора переосмыслить как структурно, так и визуально. Мы полностью переработали структуру приложения с учетом тех функций, которые должны появиться в ближайшие два года, добавили дашборд для быстрого доступа к самым популярным функциям, избавились от ярких фирменных элементов в оформлении (вроде уголка на главном экране и цветного nav bar). А вот грамотная работа над цветовой системой позволила практически полностью сохранить её при тотальном редизайне приложения.

Вторая версия дизайна приложения в той же цветовой палитре:


Даниил Субботин, iOS-разработчик Redmadrobot subdan:
К моменту запуска второй версии мы безболезненно переехали на Figma, я адаптировал утилиту, которую изначально написал для Zeplin, под Figma. Теперь мы обновляем цвета, иконки и картинки в Xcode и Android Studio в один клик


Скачать нашу утилиту можно здесь.

Выводы: как у нас, только лучше


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

  • Соберите UI kit.
  • Продумайте систему наименования цветов или воспользуйтесь нашей.
  • Подберите брендированный фоновый цвет.
  • Подберите оттенок для основного и второстепенных фирменных цветов.
  • Если ваше приложение кроссплатформенное, составьте список отличий цветовых схем iOS и Android. А также проверьте, не нужно ли добавить в приложение на Android ручную настройку тёмной темы.
  • Проверьте контрастность выбранных цветов.
  • Подготовьте иллюстрации и анимации для тёмной темы.
  • Обновите UI kit.
  • Воспользуйтесь нашей утилитой для передачи элементов в разработку.

Полезные материалы


Чтобы ещё глубже погрузится в тёмную тему:


И немного полезностей для разработчиков:

Подробнее..

Connected! Самое главное о дизайне VPN-приложения

10.02.2021 18:20:17 | Автор: admin

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

Так получилось, что VPN-клиенты я делал намного чаще, чем пользовался ими по прямому назначению. В 2020 году почти каждый месяц я стабильно получал предложение о создании быстрого, удобного и безопасного. Одни предлагали два сервера, оба из которых платные. Другие давали выбор из 50 стран и возможность подключаться сразу к 4. Несмотря на разный подход, у этих приложений одинаковые паттерны.

Ниже я постарался описать все самое важное, не заостряя внимание на деталях.


Privacy, разрешения

Стандартная процедура, без которой мы не можем предоставить свои услуги. Даем ее сразу после Splash screen. Чем быстрее пользователь разберется с процедурой и забудет о ней, тем раньше он воспользуется приложением. Поэтому мы делаем привычный Agree внизу экрана и нативный Allow, который отпушит в настройки и вернет назад.

Я также слышал, что Privacy принимается пользователем в момент скачивания и все эти экраны не нужны. Тем не менее, VPN-приложений без них я еще не видел.

Кнопка

Большая, заметная. Пользователь пришел к вам, чтобы нажать именно на нее. Креативные решения взамен пользовательского опыта придется окупать очень выгодными условиями встроенной покупки. В остальном, стоит ее разметить не в центре, проигнорировать акценты, не выделить и все человек тормозит, закрывает и переходит в то приложение, которое с ним на Ты. Лучше сделать стандартный круг (часто) или кнопку (редко) снизу, учесть и показать состояния, дать возможность отмены подключения.

Статус подключения. С одной стороны, это элементарно и понятно. Если подключено, напиши подключено, выдели цветом кнопку. Однако, я часто натыкался на приложения, которые отображают статус индикатором сбоку или интересной иллюстрацией, смысл которой известен только дизайнеру и заказчику. Помните, что далеко не все power users.

Одно слово и противоположный цвет. Все довольны, всем понятно.

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

Список серверов

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

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

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

Время подключения.Встречал почти так же редко, как и информацию о скорости, однако в отличие от нее, практического применения таймеру я так и не нашел. Ни личный опыт, ни опросы, ни диалог с коллегами не дали мне ответ на вопрос: Эм, я подключен уже 3 минуты. Что дальше?. Жить это не мешает, но и толка от этого нет. Расскажите, что Вы думаете на этот счет, мне интересно.

Карта

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

Встроенная покупка

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

Другое

Настройки, поддержка, Q&A, восстановление покупок и далее по списку. Все, что сделает жизнь пользователя немного легче. Встречается в 90% VPN-приложений. Остальные 10% вполне обходятся без этого.

Пожалуйста

Не грузите пользователя всеми возможными разрешениями, особенно теми, что вообще не относятся к VPN. Не делайте экран подписки первым, особенно, если его нельзя закрыть. Если можно без обязательной регистрации, сделайте без нее. Старайтесь объяснить пользователю свои функции грамотным дизайном, а не постоянными всплывающими пояснениями. Учитывайте пользовательский опыт платформы.

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

В заключение

Это основное, что важно знать про дизайн VPN-приложения. Мы не учитываем красивый фирменный стиль, правильные анимации и приветливый UI. Это тоже важно, и для многих пользователей может стать определяющим в выборе. У нас Starter pack. Реализовав этот список, приложение можно отправлять в App Store и Google Play.

Подробнее..

Пошаговая инструкция как отправить данные в Amplitude с помощью Google Tag Manager

10.02.2021 12:04:06 | Автор: admin

Что это

Самая подробная инструкция по передаче событий с сайта в сервис продуктовой аналитики Amplitude с помощью Google Tag Manager.

Инструкция написана аналитиками Adventum, digital-агентства и эксклюзивного партнера Amplitude в России и СНГ.

Для кого

  1. Для продакт-менеджеров и аналитиков, которые хотят внедрить Amplitude на сайт,

  2. Для разработчиков, которые будут внедрять Amplitude на сайт,

  3. Для всех, кто слышал об Amplitude и хочет передавать данные о событиях на сайте в эту систему.

Зачем

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

Чтобы события с сайта быстро попадали в Amplitude, вам поможет Google Tag Manager (GTM) платформа, которая дает возможность управлять JavaScript и HTML-тегами сайта, настроить сбор данных путем добавления кода GTM.

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

Содержание

  1. Создайте аккаунты в Amplitude и GTM
    1.1 Создание проекта в Amplitude
    1.2 Создание проекта в GTM

  2. Добавьте код GTM на сайт

  3. Добавьте тег для инициализации Amplitude JavaScript SDK

  4. Создайте реестр событий и свойств пользователя

  5. Три способа настройки GTM для передачи событий в Amplitude
    5.1 Способ 1
    5.2 Способ 2
    5.3 Способ 3

  6. Настройте GTM для передачи свойств пользователя

  7. Настройте GTM для передачи User ID

  8. Проверьте отправку событий и свойств

  9. Файлы контейнеров из статьи

1. Создайте аккаунты в Amplitude и GTM

Создание проекта в Amplitude

Если вы до этого еще не передавали данные через эти системы, создайте аккаунты в Amplitude и GTM.

Чтобы создать аккаунт в Amplitude, на главной странице нажмите Explore Product:

Укажите почту для регистрации:

Выберите сферу вашей деятельности:

Укажите имя, название компании и нажмите Explore demo now:

Перейдите в настройки:

И нажмите Create Organization:

Укажите название компании, url и нажмите Create:

Далее можно указать сферу деятельности команды в компании или пропустить этот шаг, нажав на крестик в углу.

Если вы собираете данные от жителей Европейского союза (ЕС), то вам нужно будет заполнить Data Processing Agreement (DPA) Соглашение о защите персональных данных (в соответствии с правилами Общего регламента по защите данных (GDPR)).

Если не собираете нажмите We Dont Need a DPA:

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

Чтобы создать проект в настройках, перейдите на вкладку Projects и нажмите Create Project:

Введите имя проекта и нажмите Create:

Готово вы создали проект. Теперь нужно создать проект в Google Tag Manager и приступить к настройке.

Создание проекта в GTM

Зайдите на главную страницу GTM и нажмите Start for free.

Для входа используйте аккаунт Google или создайте при регистрации, если ранее его не настраивали.

Нажмите Создать аккаунт:

Введите название аккаунта и выберите страну.

Затем укажите название контейнера, платформу, и нажмите Создать. После этого нужно согласиться с условиями использования Диспетчера тегов Google.

Предварительные действия завершены. Теперь у вас есть аккаунты в Amplitude и GTM. Приступим к настройке передачи событий.

2. Добавьте код GTM на сайт

ID вашего контейнера GTM находится в верхнем правом углу.

Контейнер GTM это небольшой фрагмент кода на JavaScript, который добавляется на страницы сайта.

Чтобы внедрить GTM на своем сайте, выполните следующие действия:

1. Скопируйте приведенный ниже код JavaScript, замените GTM-XXXX идентификатором своего контейнера и добавьте код на все страницы сайта как можно ближе к открывающему тегу <head>.

<!-- Google Tag Manager --><script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-XXXX');</script><!-- End Google Tag Manager -->

2. Скопируйте следующий фрагмент и вставьте его на все страницы сайта сразу после открывающего тега <body>, заменив GTM-XXXX идентификатором контейнера.

<!-- Google Tag Manager (noscript) --><noscript><iframe src="http://personeltest.ru/aways/www.googletagmanager.com/ns.html?id=GTM-XXXX"height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><!-- End Google Tag Manager (noscript) -->

3. Добавьте тег для инициализации Amplitude JavaScript SDK

Для передачи событий будем использовать Amplitude JavaScript SDK. Добавим тег для инициализации SDK.

В Amplitude нужно зайти в Sources & Destinations:

И нажать Add Data Source:

Далее выберите JavaScript SDK и нажмите Next:

Целиком скопируйте код SDK в появившемся окне:

Перейдите в GTM и на главной странице аккаунта нажмите Добавить новый тег:

Сверху укажите название тега: tagAmplitudeSDK. Приписка в начале названия позволит легче находить тег в интерфейсе GTM.

Нажмите на иконку конфигурации тега:

В появившемся списке выберите Пользовательский HTML:

И вставьте скопированный в Amplitude код JS SDK:

После этого нажмите на иконку триггера:

И установите триггер All pages, чтобы код SDK инициализировался при загрузке каждой страницы сайта:

Нажмите Сохранить:

Amplitude периодически дорабатывает JS SDK и публикует новые версии. Не забывайте проверять наличие новых версий SDK и обновлять код в теге, это поможет предотвратить ошибки при передаче данных. Актуальную версию смотрите на странице JavaScript и узнавайте об изменениях в релизах.

Далее нужно добавить:

  • тег для отправки событий просмотра страниц,

  • теги для отправки событий и свойств пользователя,

  • триггеры (условия, при котором активируются теги),

  • переменные (объекты для формирования названий событий и значений свойств).

Как это сделать, рассказываем ниже.

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

4. Создайте реестр событий и свойств пользователя

Событие действие, которое пользователь выполняет в продукте (запускает игру, добавляет товар в корзину) или действие, связанное с пользователем (push-уведомления).

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

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

У Amplitude есть руководство по таксономии событий. В нем описываются принципы нейминга, выбор событий для отслеживания и лучшие практики.

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

Вариант реестра может выглядеть так:

События:

Категория события

Название события

Описание

Свойства события

1

conversions

conversionStep_[registration]_success

Успешная регистрация пользователя

registration_type = {{тип регистрации: вк или email}}

2

conversions

conversionStep_[purchase]_main_page_view

Просмотр главной страницы

3

conversions

conversionStep_[purchase]_item_view

Просмотр карточки товара

item_id = {{id товара}},

item_price = {{цена товара}}

4

conversions

conversionStep_[purchase]_add_to_cart

Товар добавлен в корзину

item_id = {{id товара}},

item_price = {{цена товара}}

5

conversions

conversionStep_[purchase]_success

Успешная покупка

purchase_sum = {{сумма покупки}},

item_amount = {{количество товаров в покупке}}

6

actions

makeActions_[favorite]_add

Товар добавлен в избранное

item_id = {{id товара}},

itemprice = {{цена товара}}

Свойства пользователя:

Название свойства

Описание

Пример значений

1

age

Возраст пользователя

23

2

gender

Пол

мужской

3

favoritesamount

Количество товаров в избранном

4

4

registrationdate

Дата регистрации в iso формате

2015-04-20

Реестр событий может быть оформлен в разном формате. Можно добавить столбцы, которые будут давать дополнительную информацию о событиях и свойствах пользователя. Главное, чтобы реестр был понятным и позволял любому сотруднику, который будет работать с данными, быстро сориентироваться в событиях, которые отправляются в Amplitude.

5. Три способа настройки GTM для передачи событий в Amplitude

Мы описываем 3 способа настройки GTM для передачи событий в Amplitude, выберите подходящий для вашего продукта:

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

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

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

Способ 1

Уровень данных (dataLayer) хранит и передает информацию с вашего сайта в Google Tag Manager.

Чтобы отправить данные в dataLayer, используют метод push.

В этом способе рассмотрим отправку пуша следующего вида:

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e1',        'event_cat': 'registration',        'event_name': 'success',        'event_param': {'registration_type': '{{тип регистрации}}'}    });</script>

event:

addEvents_makeConversions действия в рамках определенной воронки,

addEvents_clickLinks клики по ссылкам, ведущим на внешний домен,

addEvents_viewErrors ошибки,

addEvents_useNavigations клики по навигационным элементам,

addEvents_makeActions все прочие действия.

Для простоты можете делить события на addEvents_makeConversions и addEvents_makeActions.

event_id идентификатор события согласно инструкции (в примере d-v1-e1: версия инструкции (v - version) 1, номер события (e - event) 1),

event_cat категория события,

event_name название события,

event_param параметр для передачи свойств.

Согласно реестру событий нам нужно отправлять следующие пуши:

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e1',        'event_cat': 'registration',        'event_name': 'success',        'event_param': {'registration_type': '{{тип регистрации}}'}    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e2',        'event_cat': 'purchase',        'event_name': 'main_page_view',        'event_param': ''    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e3',        'event_cat': 'purchase',        'event_name': 'item_view',        'event_param': {            'item_id': '{{id товара}}',            'item_price': '{{цена товара}}'        }    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e4',        'event_cat': 'purchase',        'event_name': 'add_to_cart',        'event_param': {            'item_id': '{{id товара}}',            'item_price': '{{цена товара}}'        }    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e5',        'event_cat': 'purchase',        'event_name': 'success',        'event_param': {            'purchase_sum': '{{сумма покупки}}',            'item_amount': '{{количество товаров в покупке}}'        }    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'event_param': {            'item_id': '{{id товара}}',            'item_price': '{{цена товара}}'        }    });</script>

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

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

<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'event_param': {            'item_id': null,            'item_price': '{{цена товара}}'        }    });</script>

Теперь создайте тег, который будет отправлять эти события в Amplitude. Для начала добавьте нужные для тега переменные и триггер.

Для создания триггера в раздел Триггеры и нажмите Создать:

В появившемся окне введите название DL_event_addEvents и нажмите на иконку настроек триггера:

В появившимся списке выберите Пользовательское событие:

Введите в поле Имя события addEvents и поставьте галочку напротив Использовать регулярные выражения. Это позволит GTM определить события, которые вы отправляете в dataLayer (если в параметре event будет содержаться addEvents, то триггер сработает).

В условиях активации триггера оставьте Все специальные события, нажмите Сохранить, и триггер добавится.

Чтобы создать переменные, зайдите в раздел Переменные и нажмите Создать:

Кликните на иконку конфигурации переменной:

В появившемся окне нажмите Переменная уровня данных (datalayer variables), так как вы будете отправлять события и параметры через dataLayer.push.

Введите имя переменной, используя формат varDL_{{название переменной}}.

В поле Имя переменной уровня данных впишите {{название переменной}}.

Для параметра event_cat переменная будет выглядеть так:

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

Имя переменной в GMT

Имя переменной в dataLayer

varDL_event_cat

event_cat

varDL_event_name

event_name

varDL_event_param

event_param

Добавьте таблицу поиска, которая будет формировать название события:

  • зайдите в раздел Переменные и нажмите Создать.

  • в появившемся окне введите название LT_Amplitude_event, нажмите на иконку конфигурации переменной и в появившемся списке выберите Таблица поиска.

Установите входную переменную {{event}} и добавьте 5 строк. Эта таблица поиска будет определять тип события и составлять название, используя переменную категории (varDL_event_cat) и названия (varDL_event_name). Вам нужно для каждого типа событий добавить строку в таблице поиска:

Входные данные

Результат

addEvents_viewErrors

viewErrors_[{{varDL_event_cat}}]_{{varDL_event_name}}

addEvents_makeActions

makeActions_[{{varDL_event_cat}}]_{{varDL_event_name}}

addEvents_makeConversions

conversionStep_[{{varDL_event_cat}}]_{{varDL_event_name}}

addEvents_useNavigations

useNavigations_[{{varDL_event_cat}}]_{{varDL_event_name}}

addEvents_clickLinks

clickLinks_[{{varDL_event_cat}}]_{{varDL_event_name}}

Чтобы не возникла ошибка при отправке события, если в таблице поиска не найдено соответствующее значение, установите галочку напротив Установить значение по умолчанию и введите значение по умолчанию (not_set).

Нажмите Сохранить.

Триггер и переменные добавлены. Теперь переходим к созданию тегов.

На вкладке Обзор нажмите Добавить новый тег:

Назовите новый тег tagWA_Amplitude_Events, затем нажмите иконку конфигурации тега и выберите в списке Пользовательский HTML (так же, как делали при добавлении AMPLITUDE JS SDK).

Код состоит из двух функций:

Функция mainTagFunction отправляет события в Amplitude и обнуляет значение event_param в dataLayer. Обнуление нужно потому, что метод push только добавляет данные в dataLayer. Если не обнулить event_param после отправки пуша, в параметры следующего события попадут параметры из предыдущего. Такое еще может произойти, если вы случайно отправите событие без передачи event_param.

Функция amplitudeSdkSearch проверяет, инициализировался ли Amplitude JS SDK. Если SDK инициализирован, вызывается функция mainTagFunction. Если не добавить эту функцию, может произойти такая ситуация: код SDK еще не загрузился, а пуш события уже отправлен, тогда событие не отправится в Amplitude.

<script>(function(){  var amplitudeCounter = 0;  function mainTagFunction() {  try {    amplitude.getInstance().logEvent('{{LT_Amplitude_event}}', {{varDL_event_param}});    dataLayer.push({'event_param': ''});  } catch (e) {} }    function amplitudeSdkSearch() { if (window.amplitude) mainTagFunction();    else {      if (amplitudeCounter < 50) {         setTimeout(amplitudeSdkSearch, 100);         amplitudeCounter++;      }    }}   amplitudeSdkSearch();})();</script>  

Затем выберите для тега триггер DL_event_addEvents:

Нажмите Сохранить и тег добавится в контейнер.

Так же добавьте тег tag_Amplitude_SDK.

Amplitude периодически дорабатывает JS SDK и публикует новые версии. Не забывайте проверять наличие новых версий SDK и обновлять код в теге, это поможет предотвратить ошибки при передаче данных. Актуальную версию смотрите на странице JavaScript и узнавайте об изменениях в релизах.

Настройка GTM завершена.

Недостаток этого метода: если вы хотите внести изменения в передаваемые свойства, например, добавить к событию дополнительное свойство, нужно обращаться к разработчикам. Они дополнят в отправляемом пуше значение event_param, либо в GTM вам нужно будет парсить всю переменную, что не очень удобно.

Если вы хотите передавать свойства событий в другие системы, например, Google Analytics, то понадобится дополнительно настраивать GTM, либо отправлять свойства в dataLayer в другом виде.

Варианты отправки событий, лишенные этих недостатков, будут описаны в способе 2 и 3.

Cпособ 2

Используя данный способ, не получится передавать значения параметров в виде массивов.

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

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

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e0',        'event_cat': 'example',        'event_name': 'success',        'property1': 'value1',        'property2': 'value2'    });</script>

Этот пуш отличается от пуша из первого способа тем, что вы передаете свойства события как отдельные пары ключ-значение, а не в event_param.

Согласно реестру событий необходимо будет отправлять следующие пуши:

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e1',        'event_cat': 'registration',        'event_name': 'success',        'registration_type': '{{тип регистрации}}'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e2',        'event_cat': 'purchase',        'event_name': 'main_page_view'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e3',        'event_cat': 'purchase',        'event_name': 'item_view',        'item_id': '{{id товара}}',        'item_price': '{{цена товара}}'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e4',        'event_cat': 'purchase',        'event_name': 'add_to_cart',        'item_id': '{{id товара}}',        'item_price': '{{цена товара}}'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e5',        'event_cat': 'purchase',        'event_name': 'success',        'purchase_sum': '{{сумма покупки}}',        'item_amount': '{{количество товаров в покупке}}'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_id': '{{id товара}}',        'item_price': '{{цена товара}}'    });</script>

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

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

<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_id': null,        'item_price': '{{цена товара}}'    });</script>

Также можно просто не прописывать это свойство в пуше, но тогда нужно при создании переменной для этого свойства в GTM установить значение по умолчанию :

<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_price': '{{цена товара}}'    });</script>

Создайте переменные уровня данных.

Согласно реестру событий, необходимо добавить следующие переменные:

Имя переменной в GMT

Имя переменной в dataLayer

varDL_event_cat

event_cat

varDL_event_name

event_name

varDL_registration_type

registration_type

varDL_item_id

item_id

varDL_item_price

item_price

varDL_purchase_sum

purchase_sum

varDL_item_amount

item_amount

После добавления этих переменных, переходим к созданию таблиц поиска.

Добавьте таблицу поиска LT_Amplitude_event.

После этого добавьте таблицу поиска LT_Amplitude_params, которая будет передавать значения свойств событий.

В разделе Переменные нажмите Создать, введите название LT_Amplitude_params, выберите тип переменной Таблица поиска.

Важно изменить входную переменную на {{LT_Amplitude_event}}: таблица будет получать названия событий и передавать соответствующие им свойства.

Далее добавьте в таблицу строки:

  • в поле Входные данные будут названия событий,

  • в поле Результат будут свойства событий в формате {"название свойства 1": "{{название переменной 1 в gtm}}", "название свойства 2": "{{название переменной 2 в gtm}}"} . Важно использовать именно двойные кавычки (а не как в dataLayer.push одинарные), иначе свойства не будут отправляться.

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

Входные данные

Результат

conversionStep_[registration]_success

{"registration_type": "{{varDL_registration_type}}"}

conversionStep_[purchase]_item_view

{"item_id": "{{varDL_item_id}}", "item_price": "{{varDL_item_price}}"}

conversionStep_[purchase]_add_to_cart

{"item_id": "{{varDL_item_id}}", "item_price": "{{varDL_item_price}}"}

conversionStep_[purchase]_success

{"purchase_sum": "{{varDL_purchase_sum}}", "item_amount": "{{varDL_item_amount}}"}

makeActions_[favorite]_add

{"item_id": "{{varDL_item_id}}", "item_price": "{{varDL_item_price}}"}

Событие conversionStep_[purchase]_main_page_view не нужно добавлять в эту таблицу, потому что у него нет свойств.

Поставьте галочку напротив Установить значение по умолчанию и введите значение по умолчанию "" (две двойные кавычки). Так, если в пуше не будет свойств, ошибка при отправке события не возникнет.

Нажмите Сохранить, и таблица поиска добавится в контейнер.

Далее добавьте триггер DL_event_addEvents:

После этого добавьте тег tag_Amplitude_SDK.

Amplitude периодически дорабатывает JS SDK и публикует новые версии. Не забывайте проверять наличие новых версий SDK и обновлять код в теге, это поможет предотвратить ошибки при передаче данных. Актуальную версию смотрите на странице JavaScript и узнавайте об изменениях в релизах.

Тег для отправки событий и свойств будет отличаться от тега из первого способа: добавьте тег с названием tagWA_Amplitude_Events и триггером DL_event_addEvents, выберите тип тега Пользовательский HTML и добавьте этот код:

<script>(function(){  var amplitudeCounter = 0;function mainTagFunction() {  try {    var obj = JSON.parse('{{LT_Amplitude_params}}');    amplitude.getInstance().logEvent('{{LT_Amplitude_event}}', obj);  } catch (e) {} } function amplitudeSdkSearch() { if (window.amplitude) mainTagFunction();    else {      if (amplitudeCounter < 50) {         setTimeout(amplitudeSdkSearch, 100);         amplitudeCounter++;      }    }}   amplitudeSdkSearch();})();</script>

Он также содержит функцию amplitudeSdkSearch, которая проверяет, инициализировался ли Amplitude JS SDK.

Внутрь функцииmainTagFunction добавлена переменная obj, которая с помощью метода JSON.parse преобразовывает JSON обратно в объект. Это необходимо, потому что таблица поиска в GTM преобразовывает конечное значение в формат строки, а свойства события должны передаваться как объект. Именно из-за этой особенности таблицы поиска, используя второй способ, не получится передавать значения в виде массивов.

Нажмите Сохранить, и тег добавится в контейнер.

Способ 3

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

Пуши в dataLayer отличаются от пушей во втором способе тем, что в значениях свойств нужно будет добавить метод JSON.stringify:

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e1',        'event_cat': 'registration',        'event_name': 'success',        'registration_type': JSON.stringify('{{тип регистрации}}')    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e2',        'event_cat': 'purchase',        'event_name': 'main_page_view'    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e3',        'event_cat': 'purchase',        'event_name': 'item_view',        'item_id': JSON.stringify('{{id товара}}'),        'item_price': JSON.stringify('{{цена товара}}')    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e4',        'event_cat': 'purchase',        'event_name': 'add_to_cart',        'item_id': JSON.stringify('{{id товара}}'),        'item_price': JSON.stringify('{{цена товара}}')    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e5',        'event_cat': 'purchase',        'event_name': 'success',        'purchase_sum': JSON.stringify('{{сумма покупки}}'),        'item_amount': JSON.stringify('{{количество товаров в покупке}}')    });</script>
<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_id': JSON.stringify('{{id товара}}'),        'item_price': JSON.stringify('{{цена товара}}')    });</script>

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

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

<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_id': null,        'item_price': JSON.stringify('{{цена товара}}')    });</script>

Также можно просто не прописывать это свойство в пуше, но тогда нужно при создании переменной для этого свойства в GTM установить значение по умолчанию :

<script>    dataLayer.push({        'event': 'addEvents_makeActions',        'event_id': 'd-v1-e6',        'event_cat': 'favorite',        'event_name': 'add',        'item_price': JSON.stringify('{{цена товара}}')    });</script>

Добавьте следующие переменные:

Имя переменной в GMT

Имя переменной в dataLayer

varDL_event_cat

event_cat

varDL_event_name

event_name

varDL_registration_type

registration_type

varDL_item_id

item_id

varDL_item_price

item_price

varDL_purchase_sum

purchase_sum

varDL_item_amount

item_amount

Затем добавьте таблицу поиска LT_Amplitude_event:

Добавьте триггер DL_event_addEvents:

Добавьте тег tag_Amplitude_SDK.

Amplitude периодически дорабатывает JS SDK и публикует новые версии. Не забывайте проверять наличие новых версий SDK и обновлять код в теге, это поможет предотвратить ошибки при передаче данных. Актуальную версию смотрите на странице JavaScript и узнавайте об изменениях в релизах.

Затем добавьте тег для отправки событий tagWA_Amplitude_Events и триггер DL_event_addEvents, выберите тип тега Пользовательский HTML и добавьте код:

<script>(function(){  var amplitudeCounter = 0;function mainTagFunction() {  try {    var event_name = '{{LT_Amplitude_event}}';    if (event_name == 'conversionStep_[registration]_success') {      amplitude.getInstance().logEvent(event_name, {'registration_type': JSON.parse("{{varDL_registration_type}}")});        } else if (event_name == 'conversionStep_[purchase]_main_page_view') {       amplitude.getInstance().logEvent(event_name);           } else if (event_name == 'conversionStep_[purchase]_item_view') {       amplitude.getInstance().logEvent(event_name, {"item_id": JSON.parse("{{varDL_item_id}}"), "item_price": JSON.parse("{{varDL_item_price}}")});          } else if (event_name == 'conversionStep_[purchase]_add_to_cart') {       amplitude.getInstance().logEvent(event_name, {"item_id": JSON.parse("{{varDL_item_id}}"), "item_price": JSON.parse("{{varDL_item_price}}")});          } else if (event_name == 'conversionStep_[purchase]_success') {       amplitude.getInstance().logEvent(event_name, {"purchase_sum": JSON.parse("{{varDL_purchase_sum}}"), "item_amount": JSON.parse("{{varDL_item_amount}}")});          } else if (event_name == 'makeActions_[favorite]_add') {       amplitude.getInstance().logEvent(event_name, {"item_id": JSON.parse("{{varDL_item_id}}"), "item_price": JSON.parse("{{varDL_item_price}}")});    }  } catch (e) {} } function amplitudeSdkSearch() { if (window.amplitude) mainTagFunction();    else {      if (amplitudeCounter < 50) {         setTimeout(amplitudeSdkSearch, 100);         amplitudeCounter++;      }    }}   amplitudeSdkSearch();})();</script>

Нажмите Сохранить, и тег добавится в контейнер.

Код содержит функцию amplitudeSdkSearch, которая проверяет, инициализировался ли Amplitude JS SDK.

А функция mainTagFunction отправляет события со свойствами в Amplitude: он соотносит название события со свойствами, которые нужно передать вместе с этим событием.

Значения свойств передаются методом JSON.parse, это позволяет отправлять значения в виде массивов. Пример пуша с массивом в значении свойства:

<script>    dataLayer.push({        'event': 'addEvents_makeConversions',        'event_id': 'd-v1-e0',        'event_cat': 'purchase',        'event_name': 'example',        'property1': JSON.stringify(['value1', 'value2', 'value3']),        'property2': JSON.stringify('value4')    });</script>

При этом способе события передаются не через таблицу поиска, а указываются в коде тега tagWA_Amplitude_Events, поэтому необходимо перечислить все события в коде тега, используя else if. Это сделано потому, что если отправлять пуши из способа 3 с тегом из способа 2, то свойства события не будут отправляться, потому что из-за особенности работы таблицы поиска в ней не получиться использовать метод JSON.parse.

Для наглядности код в этом теге записан через else if. Но его можно записать в более лаконичной форме, используя объект JS.

6. Настройте GTM для передачи свойств пользователя

Отправка User properties

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

dataLayer.push будет выглядеть так:

<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up1',        'user_property_name': 'user_property1',        'user_property1': JSON.stringify('value1')    });</script>

Обратите внимание, что значение userpropertyname должно быть таким же, как и название свойства. Метод JSON.stringify в значении свойства нужен, чтобы передавать значения массивами. Вариант пуша с массивом в значении свойства будет выглядеть так:

<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up1',        'user_property_name': 'user_property2',        'user_property2': JSON.stringify(['value2', 'value3', 'value4'])    });</script>

Для нашего реестра событий необходимо будет отправлять следующие пуши:

<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up1',        'user_property_name': 'age',        'age': JSON.stringify('{{возраст}}')    });</script>
<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up2',        'user_property_name': 'gender',        'gender': JSON.stringify('{{пол}}')    });</script>
<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up3',        'user_property_name': 'favorites_amount',        'favorites_amount': JSON.stringify('{{количество товаров в избранном}}')    });</script>
<script>    dataLayer.push({        'event': 'addUserProperties',        'user_property_id': 'd-v1-up4',        'user_property_name': 'registration_date',        'registration_date': JSON.stringify('{{дата регистрации в iso формате}}')    });</script>

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

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

Имя переменной в GMT

Имя переменной в dataLayer

varDL_user_property_name

user_property_name

varDL_age

age

varDL_gender

gender

varDL_favorites_amount

favorites_amount

varDL_registration_date

registration_date

Добавьте таблицу поиска LT_user_properties_value, которая будет соотносить название свойства пользователя с его значением.

Установите входную переменную varDL_user_property_name, поставьте галочку напротив Установить значение по умолчанию и оставьте пустое поле.

Далее добавьте эти строки в таблицу:

Входные данные

Результат

age

{{varDL_age}}

gender

{{varDL_gender}}

favorites_amount

{{varDL_favorites_amount}}

registration_date

{{varDL_registration_date}}

Нажмите Сохранить, и переменная добавится.

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

  • зайдите в раздел Триггеры и нажмите Создать,

  • в появившемся окне введите название DL_event_addUserProperties и нажмите на иконку настроек триггера,

  • в списке выберите Пользовательское событие,

  • введите в поле Имя события addUserProperties и поставьте галочку напротив Использовать регулярные выражения,

  • в условиях активации триггера оставьте Все специальные события и нажмите Сохранить.

Создайте новый тег с названием tagWA_Amplitude_UserProperties, выберите тип Пользовательский HTML, установите триггер DL_event_addUserProperties и добавьте код:

<script>(function(){  var amplitudeCounter = 0; function mainTagFunction() {    var properties_value = JSON.parse('{{LT_user_properties_value}}');    var identify = new amplitude.Identify().set('{{varDL_user_property_name}}', properties_value);    amplitude.getInstance().identify(identify);}   function amplitudeSdkSearch() { if (window.amplitude) mainTagFunction();    else {      if (amplitudeCounter < 50) {         setTimeout(amplitudeSdkSearch, 100);         amplitudeCounter++;      }    }}   amplitudeSdkSearch();})();</script>

Он также содержит функцию amplitudeSdkSearch, которая проверяет, инициализировался ли Amplitude JS SDK.

ФункцияmainTagFunction с помощью метода JSON.parse преобразует JSON обратно в объект, что позволяет передавать значение свойства пользователя в том числе в виде массива. Далее она подставляет название и значение свойства и отправляет его в Amplitude.

Нажмите Сохранить, и тег добавится в контейнер.

7. Настройте GTM для передачи User ID

Отправка User ID

User ID это уникальный идентификатор для каждого авторизованного пользователя, который не должен присваиваться анонимным пользователям. Это опциональное свойство пользователя: его не обязательно передавать, но его использование позволяет Amplitude определять переход пользователя между разными платформами (web, iOS, Android) и объединять пользователей (используя Amplitude ID и Device ID), в случае если события были совершены анонимным пользователем, а позже он авторизовался.

Подробнее о принципе объединения пользователей Amplitude.

User ID не должен изменяться: например, лучше не передавать в качестве user ID адрес электронной почты пользователя, потому что он может изменить его, и тогда в Amplitude он отобразится как новый пользователь.

Для отправки user ID в Amplitude необходимо на каждой странице сайта до основного кода контейнера передавать:

<script>    dataLayer.push({        'event': 'setUserId',        'user_id': 'user_id_value'    });</script><!-- Код контейнера GTM -->

Соответственно нужно добавить переменную GTM varDL_user_id с именем переменной уровня данных user_id :

Создайте триггер DL_event_setUserId, который будет активировать тег передачи user ID:

  • зайдите в раздел Триггеры и нажмите Создать,

  • в появившемся окне введите название DL_event_setUserId и нажмите на иконку настроек триггера,

  • в списке выберите Пользовательское событие,

  • введите в поле Имя события setUserId и поставьте галочку напротив Использовать регулярные выражения,

  • в условиях активации триггера оставьте Все специальные события и нажмите Сохранить.

Создайте новый тег с названием tagWA_Amplitude_User_Id, выберите тип Пользовательский HTML, установите триггер DL_event_setUserId и добавьте код:

<script>(function(){  var amplitudeCounter = 0;function mainTagFunction() {    amplitude.getInstance().setUserId('{{varDL_user_id}}');}   function amplitudeSdkSearch() { if (window.amplitude) mainTagFunction();    else {      if (amplitudeCounter < 50) {         setTimeout(amplitudeSdkSearch, 100);         amplitudeCounter++;      }    }}   amplitudeSdkSearch();})();</script>

Он также содержит функцию amplitudeSdkSearch, которая проверяет, инициализировался ли Amplitude JS SDK.

ФункцияmainTagFunction отправляет user ID в Amplitude.

Нажмите Сохранить, и тег добавится в контейнер.

8. Проверьте отправку событий и свойств

Чтобы проверить правильность отправки события, можно установить расширение для браузера либо посмотреть событие в интерфейсе Amplitude.

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

Рассмотрим работу расширения для браузера Instrumentation Explorer на примере отправки событий при просмотре блога Amplitude.

Когда пользователь пролистывает страницу статьи из блога, отправляется событие blog: page scrolled. Если нажать на кнопку расширения Instrumentation Explorer, то можно посмотреть название, свойства отправленного события и проверить правильность отправки.

Теперь проверим отправку событий в интерфейсе Amplitude.

В отчете User Look-Up нажмите на поиск:

Нажмите кнопку Advanced:

Установите режим поиска по User Property IP address:

Узнайте свой IP адрес (например, на сайте https://2ip.ru/), нажмите на кнопку Select value(s), введите свой IP адрес, отметьте его галочкой и нажмите Apply:

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

В нижней части карточки пользователя можно посмотреть поток выполненных им событий.

Если выбрать одно из событий, вы увидите его параметры:

Здесь вы проверите, что событие отправилось с правильным названием и правильными параметрами.

Иногда при проверке собственных действий система не обнаруживает проблем с передачей событий и параметров. Поэтому после проверки собственных действий, зайдите в отчет Event Segmentation, выберите проверяемое действие и посмотрите его параметры.

Если вы выберите событие conversionStep_[login]_error и его параметр error, то увидите, что значение Password field is empty параметра error передается неправильно:

Если вы нашли ошибку, нужно ее описать, сделать скриншот и написать разработчикам.

9. Файлы контейнеров из статьи

Если вы захотите изучить контейнеры, на примере которых была написана эта статья, вы можете импортировать их в свой аккаунт GTM.

Чтобы это сделать, зайдите на вкладку Администрирование и нажмите Импортировать контейнер.

Выберите файл контейнера. Затем выберите Существующую рабочую область это пространство для работы с контейнером (если проводить аналогию с Google Analytics, можно сравнить ее с представлениями).

При создании аккаунта GTM по умолчанию добавляет рабочую область Default Workspace выберите ее для импорта файла контейнера:

Далее поставьте вариант импорта Переименовать конфликтующие теги, триггеры и переменные, чтобы в случае повтора переменных, триггеров или тегов они не удалились:

После этих действий GTM покажет, какие изменения будут внесены. Проверьте и нажмите Подтвердить:

Импорт завершен.

Файлы контейнеров:

Контейнер для первого способа (файл "Способ 1.json"):

- Тег с Amplitude JS SDK

- Тег и триггер для отправки событий

- Переменные

Контейнер для второго способа (файл "Способ 2.json"):

- Тег с Amplitude JS SDK

- Тег и триггер для отправки событий

- Тег и триггер для отправки свойств пользователя

- Тег и триггер для отправки user ID

- Переменные

Контейнер для третьего способа (файл "Способ 3.json"):

- Тег с Amplitude JS SDK

- Тег и триггер для отправки событий

- Переменные

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

Подробнее..

Иной подход к коммуникации удаленных команд

19.04.2021 20:16:49 | Автор: admin

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

Мир постоянно меняется. Раньше, чтобы в твоём доме была вода, нужно было совершить ряд действий. Сейчас же нам достаточно сделать одно - открыть кран. До появления современного водопровода было множество промежуточных версий, которые безусловно были лучше, чем просто носить воду в ёмкостях. Но они были хороши лишь для своего времени.

Но речь сегодня не об этом. В прошлой статье я рассказал, как моя идея превратилась в стартап с командой. В этой статье поговорим о том, как коммуницируют удалённые команды при разработке ИТ продукта, какие проблемы встречаются, как они решаются при помощи текущих инструментов и как наш стартап их решает.

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

Toolkit больше не нужен

Toolkit означает - в каждой команде свой хаос. Объясню почему. Когда формируется новая команда, каждый её юнит привносит свои знания. Со временем появляется набор инструментов и практик.

Когда приходит новый юнит, ему выдают много инструкций как мы тут работаем и много ссылок на различные инструменты/сервисы. Чтобы со всем этим разобраться, требуется не мало времени и усилий. При переходе в другую команду всё повторяется.

Один и тот же инструмент/сервис может использоваться сотнями способов. И один способ эффективнее другого. В просторах интернета может быть тысячи курсов и лекций по этому инструменту. Сколько нужно времени, чтобы новым юнитам хорошо разобраться в нём и подстроиться под текущую команду?

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

Живой пример

Frontend-разработчик Павел пришёл в новый коллектив. В прошлой команде дизайнер рисовал интерфейсы в Sketch (но у паши Винда и он использовал Lunacy), правки доносил через Google Docs, а бизнес логику показывал через Zoom.

А в новой команде используют Figma и Miro. Часть бизнес-логики показывают, через кликабельный прототип. Правки присылают в Телеграм, Slack, либо ставят в задачи в JIRA (но переписка как правило ведётся в мессенджерах).

Даже если в следующей команде будет такой же набор инструментов, всё равно их будут использовать немного по-другому. Паше придётся опять изучать очередной Toolkit по Miro и собирать очередные правки, раскиданные по мессенджерам и таск-трекерам.

Что, если Паша в прошлой команде работал в нашем инструменте, а в новой используют его же? Как Паша и команда выигрывают?

Обзор возможностей

Конкретика

Наш сервис решает ваши задачи конкретным способом, поэтому 1 раз изучив, можно использовать эти знания в любой команде. Тем более, что сервис будет интуитивно понятен всем, кто работал с PowerPoint, Miro и Figma.

Интерфейс модуля CaseTrackerИнтерфейс модуля CaseTracker

Накапливаемый опыт

Наш сервис в одном месте накапливает весь ваш опыт, который вы приобретали, работая над тем или иным ИТ продуктом. Этим опытом можно делиться с другими и конечно же обращаться к нему самому.

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

Всё в одном месте

На одной доске, с минимальным кол-ом кликов вы получаете максимум информации. К примеру, дизайнер отправляет правки по интерфейсу разработчику. Скрин экрана он загружает в слайд, внизу пишет описание, создаёт кейсы: что и куда нужно перенести или может просто поменять текст (на одном слайде может быть несколько кейсов).

Разработчик и дизайнер могут вести беседу по слайду и кейсу (как правило у второй стороны появляются уточняющие вопросы). И по итогу можно записать решение и поставить статус Готово.

Бизнес-логику теперь проще донести

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

Как водится, это видео полетит в мессенджер и там же будет по нему переписка. Либо в JIRA, в виде задачи, но опять же, часть вопросов будет в комментариях к задаче, а часть в переписке в мессенджерах или ещё хуже - при созвоне (половина забудется). И потом концов не соберёшь.

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

Обсуждения с командой

Если всё же есть время созвониться, то можно создать митинг-комнату, в которую в любой момент может зайти кто-то из команды (если роль позволяет). Для того, кто не успел, коллеги сделают запись. Эту запись можно так же комментировать и редактировать, как описано выше.

Итог

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

Пишите в комментариях: вы узнали себя в озвученных проблемных кейсах, наш сервис помог бы вам упростить взаимодействие с командой?

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

Для первой тысячи мы откроем premium-доступ на целый год бесплатно - после запуска MVP.

Для связи со мной Телеграм. Подробнее о сервисе в моём инстаграм.

Подробнее..

Как описать бизнес-процесс в формате нотации BPMN

18.12.2020 16:04:56 | Автор: admin

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

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

Следуйте этим пунктам и составление бизнес-процесса пройдет быстро и без критических ошибок:

  1. Получить список действий.

  2. Определить исполнителей

  3. Перевести действия в задачи.

  4. Вычислить финалы процесса.

  5. Назначить действия исполнителям.

  6. Описать условия (шлюзы).

  7. Описать внешние по отношению к процессу сущности.

  8. Переложить описания в нотации.

В этой статье я не планирую описывать элементы BPMN, для этого есть множество учебников и мануалов, в том числе, среди моих публикаций. Этой нотации посвящены такие материалы: Краткое описание BPMN с примером, Спецификация BPMN 2. Перевод официальной документации и др. По той же причине не ждите, что я покажу наглядно, как использовать все возможные элементы. Кроме того, здесь я не буду говорить об исполняемых бизнес-процессах. При их составлении есть свои правила, особенности, ограничения. Здесь пойдет речь о составлении бизнес-процесса в нотации BPMN, предназначенного для анализа работы.

Получить список действий

Первое, что вам нужно после того, как вы провели интервью с людьми, которые участвуют в процессе, это получить список действий.

Важно понимать, что сейчас вам нужны именно действия, а не задачи. Задачи будут на следующем этапе. Обычно люди описывают свою работу текстом, как есть. И описывают свою работу как они делают, и что они делают. И ваша задача на основе интервью составить последовательность действий.

Как из описания сделать список действий

Давайте разберемся подробнее, как это сделать максимально быстро и корректно:

  1. По итогам интервью составьте текстовое описание. Например:

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

Естественно, это может быть не одно и не два интервью, некоторые вещи вы можете взять из документации (инструкции, формы документов). Но основной источник все таки интервью, так как вы делаете работу для людей и они будут работать с ней.

  1. Уберите лишнее. Посмотрите на текст внимательно, избавьтесь от ненужных слов.

В приведенном примере убрать следует фразу которого нет на складе. Независимо от того, есть такой товар или нет, если возникает необходимость в товаре от поставщика, потребуетсяЗаявка на закупку.

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

  1. Выделите действия. В том же примере я выделил их подчеркиванием:

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

А как же вычислить действия? Обыкновенно - это глаголы. Все просто.

  1. Создается список действий.

В приведенном примере он выглядит так:

  1. Продавец создает документ Заявка на закупку

  2. Закупщик проверяет необходимость в закупке данного товара

  3. Если закупщик разрешает закупить товар

  4. Продавец информируется о разрешении закупить товар

  5. Закупщик создает документ Заказ поставщику

  6. Иначе заявка аннулируется с комментарием

  7. Продавец информируется об отказе в закупке.

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

Все же, почему действия, а не задачи? Все просто. Это самый понятный язык для людей, которые непосредственно выполняют работу. Они так думают, они так сами описывают свою работу. И ваш список с ними согласовывать также будет намного проще в таком виде.

Перевести действия в задачи

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

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

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

В BPMN такой возможности нет. Потому здесь задача должна быть самым простым действием. В этой нотации имеются подпроцессы (Sub-Process) или подзадачи (Sub-Task). Эти возможности мы будем рассматривать позже. Здесь и сейчас я говорю именно о задачах.

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

Назначить действия исполнителям

После того, как вы описали задачи, нужно определиться, кто будет их выполнять. На этом этапе исполнителей стоит назначать предварительно, например, простым карандашом на бумаге. На самом деле, вы еще не можете 100% определить, кто именно будет выполнять то или иное действие. Часть исполнителей очевидны, другие могут измениться по итогам работы над бизнес-процессом.

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

Эти задачи уже будут тем, что называется task, т.е. задачами в BPMN. Кроме того, обязательно нужно составить список исполнителей, он потребуется при работе в нотации.

Вычислить финалы процесса

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

Например, это может быть Если необходимости в товаре нет, закупщик аннулирует заявку и отправляет уведомление продавцу.

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

Описать условия (шлюзы)

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

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

Эти условия в BPMN называются шлюзами. Их обязательно нужно предусмотреть и описать.

Описать внешние по отношению к процессу сущности

При описании любого бизнес-процесса вы столкнетесь с двумя типами сущностей:

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

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

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

Переложить описания в нотации

Вы собрали необходимую информацию, остается перенести ее в графический вид.

  1. Задачи. Это прямоугольники с закругленными краями, внутри которых вы пишете название задачи.

  2. Шлюзы. Условия выглядят ромбами. Разместите их на диаграмме.

  3. Соедините между собой задачи и шлюзы стрелками.

  4. Укажите список исполнителей, а также исполнителя для каждой задачи.

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

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

Взаимодействие диаграммы и описания диаграммы

Когда мы на основе текстового описания создаем диаграмму, эта диаграмма взаимодействует с описанием. С одной стороны, графика создается на основе текстового описания. С другой, далее вы передаете эту диаграмму руководителю или заказчику, согласуете с ответственными сотрудниками, которые будут участвовать в процессе и т.д.

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

Например, вы предложили вариант диаграммы, где закупщик самостоятельно принимает решение о закупке товара или отклоняет заявку. Руководитель предложил разделить закупки по типам товаров или добавить согласование на уровне начальника отдела закупок в случае суммы, превышающей определенный порог. Все эти изменения вы вносите в диаграмму, после чего обязательно нужно изменить и/или дополнить текстовое описание.

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

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

Советы по описанию

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

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

  2. Не усложняйте. В BPMN есть возможность совмещать события и задачи (task). По возможности лучше избегать подобных решений, разделяйте их, делайте диаграмму максимально простой и читабельной.

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

  4. Старайтесь быть лаконичными. Избегайте больших текстов.

  5. Никогда не пользуйтесь в описании задач союзом и. Недопустимо называть задачу договориться о доставке и подготовить заказ к отгрузке. Это две отдельные задачи.

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

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

Подробнее..

Категории

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

  • Имя: Макс
    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