🔥

Тред (Николай Говоров)


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

Последние четыре года так или иначе двигаюсь в сторону микро-фронтэндов. Тема сейчас в тренде, но при этом до сих пор много вопросов по корректному использованию и корректным подходам, нет best pratice, нет устоявшихся решений, кто хочет, так и пляшет.

Самый упоминаемый блог micro-frontends.org на тему микро-фронтов, автор @naltatis

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

Микрофронты могут дать возможность каждой команде разрабатывать их решение, на привычном для них стеке: хоть самописном, хоть react, angular, vue или svelte, или что-то другое. Самое главное, что абсолютно независимо от других команд.

Хотя вот с angular были, например, проблемы. Не уверен, что его (по крайней мере до 6й версии точно) нормально можно использовать как микрофронт. Всё из-за zone.js. Т.е. В рамках одного окна несколько angular приложений конфликтуют друг с другом. Поправьте, если это изменилось.

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

С упаковкой микрофронтов в веб-компоненты не игрался пока, но возможно, например, @v_hadoocken сможет об этом рассказать подробнее.

Должен быть сильный скачок, когда Webpack module federation полностью все повсеместно внедрят, но технология пока сырая, какие там проблемы будут тоже пока не ясно.

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

У меня готового рецепта в виде репозитория с кодом, к сожалению нет, есть проприетарные решения, которые я разрабатывал для проектов и компаний, они все за все эти годы сильно развивались, но так и не приобрели какого-то статуса “готового решения”.

Микро-фронты конечно не панацея. Почти все решения, которые я могу себе вообразить, можно сделать без них, даже если над решением работают много команд. Но есть определенные ситуации, когда это решение сэкономит много сил и нервов, а ещё сильно упростит CI/CD.

Первое на что мы попадаем в случае использования микрофронтов - инфраструктура. Теперь нам нужно разворачивать не одно приложение, а по сервису на каждое. А если ещё и dev/test/demo окружения + автодеплой веток для PR, так вообще где-то закрывается в шкафу один маленький devops

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

Третья - SSR (серный пре-рендеринг страниц). Тут вообще всё супер неоднозначно: тут и различный рендер в зависимости от роли пользователя и возможность предподгрузки при SSR основной SPA и ещё куча другого гемороя.

В 2020м при использовании микрофронтов нормальный SSR сделать врядли получится не подставив компанию на финансовые потери в виде трат на оплату времени разработчикам на R&D.

Интересный момент в закреплении решения “должен ли микро-фронт работать как standalone приложение или нет”. Плюсы есть у обоих решений, но я после опыта с различными подходами всё же за вариант, когда - да, должен работать как standalone.

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

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

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

Одна из проблем с которой столкнулись и так и не выработали однозначного решения - это back-for-frontend паттерн, т.е. обязательное использование api gateway, или другими словами использование единого эндпоинта для всех запросов для каждого микрофронта или всего приложения.

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

Ещё становится весело, когда каждый микросервис работает со своим протоколом. Т.е. представим: у нас есть переиспользуемые компоненты, например компонент “таблица”. Но данные от всех микросервисов приходят в абсолютно разном виде.

А бывает даже не только в разном виде, но и в разной спецификации: rest, jsoapi, graphql и т.п. Т.е. мы должны на клиенте получить данные, обработать, привести к единому виду и скормить в компонент. Тут, чтобы не перегружать клиент, поможет BFF, который отдаст всё в готовом виде.

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

Самый очевидный пример, который у нас был: Два приложения, одно с BFF, другое без. У первого рендер на больших объемах данных на 0,5 сек быстрее, потому-что парсить данные не нужно, приходят от гейтвея в готом виде.

Вроде бы всего 0,5 сек, а глаз это видит, и в итоге заказчик выбирает решение, которое отрисовывает форму визуально быстрее, не понимая, что за этой быстрой отрисовкой идёт просадка, когда пользователей становится 100k+.

Поэтому вроде бы в back-for-frontend есть смысл, когда количество клиентов такое огромное, что инфраструктура подводит. С другой стороны при таком кол-ве клиентов уже можно и кластеризацию нормально сделать и поднимать несколько BFF.

Ещё один плюс back-for-frontend - отсутсвия гемора с проксированием. Проксирование в таком случае можно даже в риалтайме регулировать, просто обновляя гейтвей, пользователи ничего не заметят.

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

Для бизнеса микрофронты не понятны. Т.е. вот мы делали монолит, зачем нужны микросервисы на бэке мы поняли, а зачем нам иметь несколько фронт приложений, если можно иметь одну SPA собирающуюся из npm модулей, “зачем нам это всё?”.

“А ещё и нет best practies, значит подход сырой, значит точно нам это не нужно”, - так отвечают почти все. При всех плюсах и минусах микрофронтов, действительно нельзя сделать однозначного решения в одну или другую сторону, по крайней мере на проектах с DAU меньше 100k человек.