Про Inbox, веселые легаси и динамические микрофронты
Наш Альфа-Банк прекрасен. Мы его очень любим, но он такой большой-большой, разнообразный и сложный. Думаю, никого не удивил :) Наш ИТ-ландшафт содержит великое множество всякой «флоры и фауны», с которой необходимо считаться. То тут, то там, из глубоких Enterprise джунглей нам улыбаются и игриво подмигивают орды легаси-систем, каждая из которых живет своей собственной жизнью и поддерживается разными командами. Например, HR-вопросы — это SAP HCM, со своими потоками и фронтами, написанными на SAP UI5, Fiori, вопросы учета — SAP ERP, а есть ещё IBM Lotus Notes, системы документооборота и пр., и пр.
Для организации и упорядочивания различных бюрократических процедур, в банке есть такой инструмент, как электронная заявка. По задумке, он должен быть удобным: открываешь сервис, выбираешь тип, заполняешь, отправляешь. Нюанс в том, что есть примерно 1000 видов разных заявок, и в каждой родительской системе заявки создаются по своему, в разных местах, а согласуются своим инструментарием. Сотрудники страдают, а новые коллеги ужасаются, когда окунаются в этот зоопарк систем: непонятно куда бежать, что нажимать и как это всё работает.
Всем привет, меня зовут Олег Кругляков, я руководитель направления в одной из команд клиентского пути сотрудника Alfa People. В статье хочу поделиться опытом создания сервиса, который объединяет все эти заявки в одном месте без «беготни» по разным системам. При всем при этом, он весело работает в браузере и весело работает в мобильном приложении, нордически выдерживая единый дизайн. Ну, приятно, чего греха таить ?
Про клиентский путь замолвите слово
Однажды нам надоело бегать по джунглям и мы решили, что согласование всех заявок в банке должно быть в одном месте. Так появился сервис «Мои заявки». Его задача в том, что в какой бы системе сотрудник не создал заявку, проходить процесс согласования он должен в одном сервисе, всё должно выглядеть единообразно, в концепции единого дизайна, как и вся рассылка (письма) и уведомления (push-сообщения).
Проще говоря, вместо того, чтобы писать заявление на отпуск в одном сервисе, на посещение конференции в другом, на командировку в третьем, а в четвёртом на увольнение, когда устал от этого всего, ты используешь один сервис и больше никуда уходить не надо. Как «Госуслуги», но в корпоративном секторе.
Сначала мы подумали, что должно быть в сервисе:
Просмотр/согласование/отклонение/отправка на доработку/отмена заявки.
Просмотреть ранее созданные заявки и заявки, в согласовании которых сотрудник когда-то принимал участие.
Редактирование заявки (если предполагается бизнес-процессом).
Возможность для руководителя назначить себе заместителя на время отсутствия.
Поиск заявки почти по любым ее параметрам.
Фильтрация заявок.
Отправка уведомлений (почта, пуш).
Элементы приложения.
Так как наша команда ближе всего к HR направлению, то и начать мы решили с себя — заявок, которые формируются в SAP HCM и далее развивать сервис итерационно — от простого к сложному. Это хорошая возможность попробовать технологию на понятных нам процессах, силами исключительно собственных команд: разработчиков как фронта, так и бэка, без необходимости привлечения кого-то извне.
А что за «наша команда»? Мы — это специальная команда Alfa People. Работаем над тем, чтобы перевести рутинные операции в удобные и современные сервисы. В банке есть такой девиз как: «Люди — наш главный капитал». У нас он есть и мы его придерживаемся, и считаем, что сотрудники — такие же клиенты, только внутренние, и сервисы для них должны быть не хуже, чем для внешних.
Соответственно, мы и разработали сервис, в котором можно согласовать все заявки в банке, взаимодействуя с большим количеством внешних систем. Оно называется «Мои заявки», а мы его называем Inbox.
Inbox — это сервис внутри корпоративного веб-портала и мобильного приложения. Это frontend-приложение: основное приложение-обёртку делает одна команда, а всё, что открывается внутри в качестве микрофронтов — любая другая команда в банке. А чтобы все сервисы выглядели в одном стиле и деплоились как можно быстрее, была разработана дизайн-система и библиотека компонентов.
Стек:
Frontend на ReactJS.
BFF — Node.js (Nest.js).
Для переноса в мобильную версию используем WebView, что значительно ускоряет процесс, экономит ресурсы, не нужно обновлять версию мобильного приложения (что особенно вызывает определенные сложности в текущих реалиях на iOS).
Используем микрофронтенды (Module Federation) — на одном экране работаем сразу с несколькими отдельными приложениями, каждое из которых разрабатывает отдельная команда.
Сейчас расскажу что и как делали: про архитектуру Inbox, перенос в K8S, микрофронты, SAP и Mongo. Не переключайтесь.
Как и что делали по этапам
На первом этапе мы решили пропилотировать самое простое решение:
Переписали фронт нескольких заявок на ReactJS и разместили Inbox в SAP NetWeaver.
Оставили все данные и потоки на стороне SAP.
Настроили информирование с фронта мастер-системы об изменении статуса заявки для её движения по потоку.
Провели исследование (VOE), которое показало, что мы на правильном пути, получили очень высокую удовлетворенность пользователей. Особенно руководителям понравилось быстро согласовывать заявки из мобильного приложения, находясь при этом не за рабочим местом и в удобное для себя время. Поняли, что направление выбрано правильно и имеет смысл дальше вкладываться и развивать его.
Так выглядит перечень заявок, доступный пользователю для согласования.
В верхней части доступны табы для просмотра созданных заявок и уже отработанных. Пользователь может, не открывая тело заявки, согласовать её или отклонить (отправить на доработку).
У всех заявок есть признак, определяющий, возможно ли подобное поведение. Дело в том, что есть множество сложных заявок, в которых бизнес-процесс предполагает обязательный просмотр её тела при согласовании, а в отдельных случаях и редактирование.
На следующем этапе перенесли Inbox в соответствии с целевой архитектурой: выделили middle (BFF) слой на Node.js и разместили приложение под управление Kubernetes.
Но настоящим прорывом тут стало использование Webpack Module Federation, что позволило открывать заявки как самостоятельные приложения внутри Inbox.
Причем, как написанные на ReactJS, так и на SAP UI5 (в тот момент просто физически не могли переделать заявки на ReactJS, все команды были максимально загружены). Конечно, пришлось отступиться от концепции единого дизайна, но важно было максимально популяризировать сервис, а для этого нужно увеличить количество заявок, которые можно в нём согласовать.
Подход микрофронтендов позволил нам отвязать логику и бизнес-процесс внутри самой заявки от Inbox. По сути, он стал просто оберткой, инструментом, который позволяет открывать внутри себя любое приложение и взаимодействовать с ним по заранее оговоренным правилам.
На этом этапе приложение всё больше начинало походить на конструктор. Каждая команда, которая встраивала свою заявку, могла настроить перечень кнопок и действий, которые должны быть доступны пользователю при работе на том или ином этапе согласования, либо использовать настройки по умолчанию. Использование концепции микрофронтендов стало ключевым моментом для возможности дальнейшего развития сервиса.
Далее мы научили встраивать к себе заявки из других систем.
Верхнеуровнево архитектура стала выглядеть следующим образом.
Inbox выступает в качестве пассивной системы, которая лишь получает необходимые данные о новых заявках и любых изменениях в них.
При создании или изменении заявки родительская система должна была нам сообщить об этом, передав соответствующие данные, необходимые для построения реестра всех заявок конкретного пользователя.
При открытии Inbox он отдельным сервисом выгребал все записи у себя в БД и SAP HCM, оставалось только отрисовать их пользователю. А зная все метаданные по заявке, инициировать получение её тела из соответствующей системы вообще не проблема.
У данного решения есть очевидный плюс — минимальное количество прогоняемого по сети трафика. Но есть и минус — пользователь не всегда в режиме реального времени видят актуальный статус заявки.
Мидл слой разбился на множество микросервисов:
connector для общения с внешними системами;
сервисы для отправки и получения сообщений из Kafka;
сервис для агрегации информации по заявкам;
сервисы для общения с MongoDB и SAP HCM;
сервисы для отправки пушей и email уведомлений;
основной сервис-движок Inbox;
и пр.
Про генерацию фронта на лету и «старичка» JSON’а
Оставалась одна проблема — все заявки выглядели по-разному, а переделать их на React было просто нереально. И тогда начали появляться мысли об использовании подхода Server Driven UI, ведь мы бы смогли генерить любую заявку в целевом дизайне на лету.
Собственно, а какие основные предпосылки?
Заявки содержат много полей.
На поля завязана логика, они взаимосвязаны.
Изменение заявки всегда упиралось в долгую разработку.
Заявок около 1000 штук, невозможно делать и полноценно поддерживать каждую.
Стало очевидно, что необходимо решение, которое позволит все это поддерживать «не привлекая внимания санитаров» ?
При всем многообразии заявок все они состоят из одних и тех же частей, представленных на рисунке ниже. Основную сложность представляет именно тело заявки, которое может выглядеть как угодно, содержать любые компоненты и логику.
В качестве формата хранения информации о структуре заявки выбрали старый добрый JSON. В нем храним информацию о:
Компонентах, используемых в заявке, их состоянии и взаимном расположении.
Возможных ивентах на компонентах (click, contextmenu, mouseover/out, mousedown/up, submit, focus и др., плюс кастомные типа очистки, инициализации, условия, операции типа «сделать поле обязательным», «установить значение в поле», «скрыть/показать поля из списка»).
Внешних API для получения данных, изменения состояний, выполнения валидации введенных значений.
Правилах заполнения (типы и пр.) — это простые условия для быстрой валидации данных на фронте.
Конфигурации шагов при согласовании (если согласование представляет собой сложный процесс, где на каждом шаге предполагается свой особенный интерфейс).
Зависимостях между компонентами, например, когда изменение состояния одного меняет состояние другого.
Наборе кнопок и действиях при их нажатии.
При выборе заявки мы определяем её вид и смотрим, есть ли уже готовый фронт под неё в мастер-системе. Если есть, то подтягиваем его вместе с данными по соответствующему адресу.
Если нет, то ищем JSON-шаблон и, в соответствии с параметрами, указанными там:
на лету рендерим компоненты (туда же кладем и функции, которые отвечают за взаимодействие с пользователем — экшены);
отправляем запрос в мастер-систему для получения данных заявки.
Верхнеуровнево архитектура выглядит так:
Connector — набор сервисов, которые умеют:
Сходить в БД и получить JSON-шаблон заявки.
Распарсить JSON и получить из него разделы заявки, компоненты, состояние и их логику.
Сходить в мастер-систему и получить данные по заявке.
Склеить, сформировать структуру заявки и отрендерить её
Теперь для встраивания новой заявки в Inbox соседней команде достаточно лишь передать нам готовый JSON-шаблон, заполненный в соответствии с правилами.
Вот так работает наш Inbox. Надеюсь, наш опыт будет интересен и пригодится при решении подобных задач.
Подборка от редактора блога:
«А поговорить?»: как сделать голосового помощника в браузере
Семантическое версионирование и проблемы с зависимостями — коротко о lockfile
Взболтать, но не смешивать: как упаковать находки исследования, миксуя JTBD, CJM и компас персон
Также подписывайтесь на Телеграм-канал Alfa Digital — там мы постим новости, опросы, видео с митапов, краткие выжимки из статей, иногда шутим.