Микрофронты для всех. Как мы построили платформу UIF, и что под капотом

Привет, на связи Павел Востриков, архитектор веб-направления в «Лаборатории Касперского». Сегодня я расскажу про User Interface Framework (UIF) — нашу внутреннюю платформу интеграции веб-приложений, которая позволяет проводить разработку микрофронтов и микросервисов разными командами, делает удобным переиспользование кода и увеличивает гибкость подхода, чтобы разные команды могли варьировать технологии под свои нужды.

image

Мы начали разрабатывать UIF еще в 2016 году, когда само понятие Micro-Frontends только входило в обиход. Платформа родилась из-за отсутствия на рынке готовых инструментов. А со временем стала одним из наших самых эффективных решений, существенно сократив нескольким продуктам time-to-market и стоимость разработки, и даже научилась автогенерировать UI!

Эта непростая диаграмма


Какие проблемы вообще могут возникнуть при создании множества приложений и страниц для веб-приложения? Если обобщать, их три:

  1. Нужно быстро и недорого создавать новые продукты.
  2. Нужно сохранять для этих продуктов единый стиль UI/UX.
  3. Нужно легко интегрировать веб-приложения друг с другом.


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

image
image

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

Однако саму UIF минималистичной не назовешь.

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

UIF делится на две сферы: low-code и code-based. Первая включает тулсет, не требующий кода, интерактивные формы и документацию. Во второй содержатся компоненты, сервисы и скаффолды.

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


Начнем с лоукода. В нашем тулсете многое можно сделать, не написав ни строчки на JavaScript.

С помощью Mnemon мы прогоняем тесты без кода, просто записав пользовательские действия. Для дебага интеграционных составляющих и форм используем отдельного девтул-детектива — Colombo. А Domain CLI позволяет в пару кликов генерировать типовые сценарии-скаффолды.

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

Здесь хранится дизайн системы и библиотека UI-компонентов — от простых атомов-кнопок до сложных «организмов» вроде стандартного пользовательского соглашения. Библиотека обширная, ее хватает на создание разнообразных страниц и приложений. А благодаря унифицированному дизайну элементов все эти страницы потом успешно вписываются в нашу экосистему.

В наших сервисах и приложениях полно экранов, управляющих теми или иными фичами. Это так называемые формы: визарды, соглашения, другие подобные скрины. Они в UIF и на нашей диаграмме выделены в собственный слой, и их чуть более полутора тысяч. Естественно, с помощью UI Builder их тоже можно создавать.

Итак, сейчас у нас в приложениях несколько тысяч уникальных экранов с типовым UI. Держать их все в html-верстке и в ней же вносить изменения — трата времени, сил и денег. К тому же с таким количеством экранов у разных разработчиков обязательно появятся неоднородности в UI. Элементы будут единые, а вот расположение и назначение — разные. Поэтому мы создали фичу, уникальную для UIF: автогенерацию UI.

По сути, это интерфейс, который позволяет накидать скелет той или иной страницы в дизайнерском режиме буквально drag&drop«ом, прописав логику на JavaScript. Готовый скелет в JSON«е отправляется в ядро UIF. А на его основе автоматически создается полноценный интерфейс. UI так создавать быстрее, это уже помогло нам в сжатые сроки разработать целое семейство проектов. И таким образом неоднородностей удается избежать.

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

Кроме того, разработчикам нравится работать с кодом. А визуальные элементы у них не в фаворе. Если у них есть выбор, они всегда выберут код. Сейчас мы активно инвестируем в Developer Experience, чтобы дать разрабам возможность управлять формами из кода. Наш девелопер будет просто заходить в файл с кодом, говорить: «Мне нужно пять инпутов подряд, каждый инпут смотрит на такую модель данных, а данные отправляет сюда», — и получать необходимый результат.

Многие, наверное, задаются вопросом:, а зачем вообще такой оверхед? Почему нельзя просто взять %name% и делать UI? Ну, давайте рассмотрим такой вариант, чисто гипотетически.

Итак, выбрал ты библиотеку или фреймворк, выбрал код-стайл, настроил линтинг, настроил pre-commit-хуки, сконфигурировал сборку, выбрал решение по хранению данных, выбрал решение по передаче данных, разобрался с проблемами больших файлов, транспонировал эти же решения на middle-tier, настроил горизонтальное масштабирование и связанные с этим stateless-механики, выставил bulk- и rollback-операции для сложных запросов, сформировал инфраструктуру для взаимной интеграции со смежной командой, выделил общую логику для упрощения работы в точках интеграций, настроил на ci проверку и прогон unit-тестов, smoke-e2e-тестов, on-demand-скриншотинг, научился собираться и в on-prem и в cloud, поддержал OAuth, научился работать в мультибэкендовом межсервисном режиме, сформировал integrated- и standalone-поставку, собрал фидбек со смежных команд, упростил подходы, выстроил интеграцию с дизайн-системой, поддержал темизацию, написал проверку 3pc, перевыбрал часть библиотек, вспомнил, что забыл задокументировать, задокументировал, понял, что остались еще проблемы, выстроил слой мониторинга, научился снимать тепловые карты с продукта… И остался, конечно, полностью в силах еще поддерживать проект, быстро писать business/presentation-логику и актуализировать технологии.


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

Библиотека Касперского


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

Конечно, когда мы только начинали работу с UIF, ничего подобного у нас не было. Впервые платформу задействовали в разработке Kaspersky Endpoint Security Cloud. Это облачный продукт безопасности, каждый пользователь которого работает одновременно с двумя-тремя сотнями устройств. Его разрабатывала небольшая на тот момент команда, решение было компактное.

image
image

Но когда мы подошли к следующему проекту, Kaspersky Security Center Web Console, все резко усложнилось. Это решение было рассчитано на энтерпрайз, бизнес, большое производство.

Разработкой KSC Web Console занялись четыре команды — host application и три продуктовых. Отсюда разногласия в UI, деплой по частям и другие прелести распределенной разработки.

image
image

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

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

UIF все популярнее в «Лаборатории Касперского». Сейчас платформу используют 25 продуктовых команд, а до конца года их может стать уже больше тридцати. И мы тоже на месте не стоим: например, добавляем к теории практику — скоро в монорепе появится режим песочницы. Можно будет работать с отдельными плагинами и сервисами без ограничений. Уверены, это поможет нашим разрабам находить новые пути и решения.

Заглядываем под капот


Перейдем к code-based-сфере. В 2016-м готовых решений, которые бы полностью из коробки решали эти задачи, просто не было. Технологии фронтенд-разработки — React, Vue, Angular — отлично подходили для создания отдельных приложений, но не могли обеспечить единые правила интеграции и взаимодействия различных программ внутри одного большого приложения-хоста. Webpack Module Federation еще не существовало, то есть настроить деплой микрофронтендов тоже было проблемно.

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

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

Итак, самое важное, фундамент платформы — наш стек. На фронтенде мы используем React, TypeScript, Redux + Immutable.js + адаптер для слоя форм, styled-components и D3. На бэке пользуемся Node.js, Express, socket.io, и все это контейнеризовано.

Каждое решение здесь на своем месте. Наша основная идея — чем проще это использовать в продукте, тем лучше. Почему, например, React, а не Angular, Vue или Svelte, Stencil и Lit? Потому что React так же хорош, как и остальные решения. Плюс adoption в сообществе. Плюс необходимость в выборе единого решения для унификации процессов. При этом есть продуктовые команды, которые исторически пишут на Angular, и технической возможности перейти «здесь и сейчас» на React просто нет. Решение простое и эффективное: для interop такого вида используются веб-компоненты в качестве «клея» между Angular и React.

Зачем D3 с надстройкой react-force-graph? Потому что пользователям нужны содержательные и стильные графики, которые к тому же быстро отрисовываются.

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

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

Плагины и скаффолды


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

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

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

Наш секретный элемент


На диаграмме он не отражен, но без него UIF никогда не смогла бы работать нормально. Это, конечно, наша команда.

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

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

Кроме того, мы активно взаимодействуем с нашими не-UIF-разработчиками. Перенимаем у них экспертизу. Вовлекаем в процесс. Объясняем, как у нас все работает. Нашим командам всегда есть с кем расти.

А еще UIF — это ведь про гибкость и свободу. Когда мы отдаем задачу команде разработки, она вольна самостоятельно выбирать, какие технологии использовать в рамках контракта. К примеру, нам нужно через state management описать правила игры в большом приложении. Мы объясняем разработчикам, что нужно сделать, а уж использовать им при этом Redux или MobX — их дело.

Заключение


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

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

© Habrahabr.ru