Pull to refresh

Comments 34

В подобной архитектуре намного больше проблем, чем описано, и код, обслуживающий их, становится настолько сложным и трудноподдерживаемым, что приходится выделять отдельную команду. Участвовал в двух проектах с подобной схемой. В числе других проблем — отсутствие общих компонентов либо большая сложность в их интеграции (обновить шрифт в 10-20 микрофронтах? Поднять версию библиотек, подтянуть иконки? В монолите — час работы, в подобной системе — больше месяца, кроме шуток); подтягивание актуальных версий для локальной разработки (придется писать сложный cli-инструмент с резолвом конфликтов и менеджерингом гит-версий в каждом микрофронте); на поддержку root-обертки тоже нужна команда, со своим флоу поставок и разрастающимися версиями для поддержки обратной совместимости, что выливается со временем в катастрофическое торможение новых релизов; про SSR даже можно не думать; в каждом микрофронте свои подходы и устаревающие конфиги, которые тоже нужно синхронизировать; кратное увеличение времени CI/CD; в браузере общий DOM, соответственно общая раскладка, и если не пользоваться iframe то очень велика вероятность конфликтов стилей или лэйаута; дублирование полифиллов. Перечислять можно еще долго, но закономерный итог — замедление поставок и тонна багов от синхронизации. А что считается "достоинством"? "Свободная реализация компонентов системы разными командами", то есть тотальный зоопарк. Про "независимость поставок", который часто тоже служит аргументом, лучше и не упоминать — в реальности этого нет, наоборот, приходится часто лезть во все репозитории, разбираться в их коде и подходах, и править, влезая в циклы поставок других команд.


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

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

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

Поднять версию библиотек во всех микрофронтендах сразу? Зачем?

Обнаружилась критическая уязвимость, изменилась сквозная функциональность, потребовалась совместимость со свежей/старой/экзотической версией браузера.

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

2. Изменение сквозной функциональности — если это значимый кейс, то вероятно микрофронтенды неправильно организованы и оказались сильно связаны.

3. По поводу совместимости со свежей/старой версией браузера — обычно проблема не возникает сразу во всех микрофронтендах. Тут как раз двигать всех в светлое будущее может быть вредно.

PS: Понятно, что если микрофронтенды использованы без нужды и просто потому что это модный тренд, то всё будет плохо. Ну так и микросервисы можно использовать не по назначению.
  1. Вот это "подтягивание хвостов" только звучит как будто это осуществимо, на деле приходится обновлять компонент (селект к примеру) в библиотеке компонентов для реакта, вью, ангуляра, ставить задачи на все команды по подъему версии, причем они могут быть ниже приоритетом чем задачи от бизнеса, в итоге 5 из 10 микрофронтов обновились через неделю, еще два — через две, еще в трех эти задачи "потерялись" и остались в глубоком бэклоге. В итоге приложение несинхронизировано, баги остаются надолго, стили остаются разными. С десятью обновлениями или тем более редизайном получается такой треш, что смотреть на это все невозможно. Организационно это тоже не решить, так как у команд разные циклы поставок. В монолите же один апдейт и если используется TS, то он не даст оставить "хвосты", придется переводить сразу все — это займет больше времени на задачу, но сэкономит десятки человекочасов (считая время аналитиков, тестировщиков, разработчиков) по сравнению с микрофронтами. Не в идеальном мире живем, когда все всегда доводят задачи до конца.


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


  3. С этим не сталкивался, так как использую автоматический полифиллинг (babel preset-env), соответственно достаточно изменить browserslist в каждом микрофронте, но эту схему используют далеко не все и действительно может стать проблемой.



Микрофронты — не модный тренд, а метод обхода комплексного рефакторинга систем, чтобы можно было использовать легаси-части и постепенно их переводить на общую схему, имхо. А как по вашему, какое еще может быть у них назначение?

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


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


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


Тотальный зоопарк — да. Является ли это проблемой? Далеко не всегда.

Смотрите внимательнее, сейчас фокус покажу...


Приложение для чтения статей. Разрабатывается Аллой. Весит 60 кб.
Приложение для проведения презентаций. Разрабатывается Борисом. Весит 60 кб.
Галерея компонент. Разрабатывается Катей. Весит 140 кб.
Песочница для различных трансформаций. Разрабатывается Денисом. Весит 80 кб.



Приложение, включающее в себя вышеназванные и ещё немного. Разрабатывается Евгением. Безо всяких микрофронтендов. Весит 170 кб.


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

В том лоскутком одеяле прекрасно то, что никто и почти ничто не мешает какой-нибудь команде взять и начать использовать $mol.


Так были в проде backbone/marionette, knockout, react, vue, angular. ts, flow, coffescript, clojurescript(на счёт прода — не уверен).


Если бы у нас был бы вдохновитель $mol, а сам фреймворк был бы production ready в 2014-2016, то мы бы использовали.


А вес бандла — это не так важно в b2b.
Как-то я выпилил мегабайт неиспользуемого легаси во время рефакторинга. Это не повлияло ни на что.


А вообще, я думаю присоединиться к сообществу и попробовать.

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

На моем опыте был только один случай, когда приложение состояло из двухуровневых iframe — виджет встраивался в сайты, и в самом виджете было несколько фреймов из разных доменных зон, связанных по postMessage. Но и там сделал единую точку рендеринга, в которую ходили разные бэкенды за получением локализованного шаблонизированного html, соответственно "зоопарка" не было, просто такой мультифреймовый конструкт с большим оверхедом по доступу к данным соседних "микрофронтендов".


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

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

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

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

Касательно ресурсов: мы справляемся без дополнительной команды, прослойки делаем максимально тонкими и простыми, без нагромождений сложной логики.
CSS прекрасно можно заинжектить в shadowRoot с помощью constructable StyleSheets.
shadowRoot.adoptedStlyleSheets = ['adoptedCss1', 'adoptedCss2'], перезагрузки из кеша бразуера не будет, и плюсом это ссылка а не копия.
А если у вас только vue —  смотрите webpack 5 + Module Federation

Фонты через new FontFace().
куча времени и кода было бы сэкономлено )

Не взлетит, adoptedStyleSheets работают только в Chrome и его производных. Эта задача решается подключением внешнего файла стилей внутри shadowRoot, просто через тег link, как и в основном документе. Я обычно ещё инициализацию виджета запускаю в момент, когда стили полностью загружены, но это уже детали конкретной реализации. Стоит отметить, что инлайн стили внутрии shadowRoot могут нарушать CSP, поэтому лучше именно внешний файл.

adoptedStyleSheets это не только хром, к тому же есть полифил.
через тег линк — это прекрасно, но перформанс страдает это раз, количество копий css при большом количестве приложений это два, особенно если приложения пользуют один и тот же модуль, например от ui библиотеки и их надо кешировать.
Отсутствие возможности управлять css из хоста для всех приложений сразу ну итп.
adoptedStyleSheets это не только хром

caniuse.com/mdn-api_document_adoptedstylesheets — а кто еще? А еще покажите полифил который не ломает CSP.
но перформанс страдает это раз

Это как? Да, браузер должен сделать запрос, и да нужно дождаться загрузки… Но не вижу тут особых страданий, + кэш + prefetch.
и их надо кешировать

Это делает браузер. Ну или вы можете взять все под полный контроль в ServiceWorker.
Отсутствие возможности управлять css из хоста

Это не так, есть куча способов, начиная от реализации API через CSS-переменные и заканчивая тем-же сервис воркером…
Задачи у всех разные.

20 активных приложений будут иметь 20 копий css в памяти, загрузка каждого css из кеша браузера и парсинг займет ~200ms в зависимости от размера css. Ну и к тому же операция загрузки css асинхронная, а adoptedStyleSheets = нет.

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

Ну и нагородить, конечно же, можно всякого, но исходя из принципа — делать как можно проще — adoptedStyleSheets это хороший инструмент в умелых руках ))

Нативная поддержка в Safari и Firefox отсутствует, но видимо coming soon, ибо стандарт принят консорциумом и активно развивается.
но видимо coming soon, ибо стандарт принят консорциумом и активно развивается

Пока только черновик, к сожалению. То есть, говорить о использовании в продакшене — рановато, особенно если вы в ентерпрайз проекте. Разработчики LitElement, к примеру, эту проблему так и не решили, и если вы используете что-то подобное — будете вынуждены добавлять unsafe-inline в ваш CSP.
имелось ввиду не css

Тогда причем тут adoptedStyleSheets? В любом случае, у вас есть disconnectedCallback чтобы выгрузить все что вам нужно выгрузить.
делать как можно проще

Что может быть проще старого доброго
<link rel="stylesheet"...
?
ответ выше.
— асинхронность.
— задержка в ~200ms.
— нерациональное использование памяти.
— необходимость в куче дополнительного кода при необходимости изменить стили для всех активных приложений.

Jedem das seine.
Согласиться могу только с первым пунктом вашего списка, но да, каждому свое.
Микросервисная архитектура до сих пор не имеет хороших паттернов проектирования и поддержки. У кого-то http запросы, у кого-то amq. Каждый по разному решает как содержать разные версии. Хотя в помощь идут docker, kubernetes и прочий зоопарк. Микросервисная архитектура решает вопросы масштабирования как вычислений(1000 и более нодов на приложение), так и зоны отвественности. 100, 1000 и более разработчиков в одном котле становится нормой. Мне сложно представить фронтенд, который пилят 1000 разработчиков. Я не могу представить распределенный фронтенд. Верю в то, что с развитием скорости сети и серверных мощностей, фронтенд превратится в подобие рдп. Текущий технологии не позволяют хорошо изолировать код, до сих пор ресурсы пилят с оглазкой на медленный интернет. Фронтенд, в отличии от бекенда, варится в одном котле. Положил тухлый компонент к блюду и все блюдо в унитаз. Поэтому и существуют шеф повара, которые все проверяют и контролируют. Думаю ничто не мешает выделять в сторонние модули и компоненты, которые могут лежать в разных репозиториях, вести свои версии. А главный шеф повар будет проверять их перед добавлением в общий котел
Я не могу представить распределенный фронтенд

А виджеты от внешних сервисов можете представить? Почти тоже самое, но микрофронтенды — проще, потому что вы, как разработчик, имеете хорошее представление о общей оркестровке на самом верхнем уровне (лично знаете своего шеф-повара). И текущие технологии вполне позволяют сделать все необходимое (изоляцию) без использования тяжеловесных решений типа iframe, статья об этом, собственно.
Статья описывает воду. Где примеры того, как решается задачи ssr, как дружат версии библиотек(касаемо тех, которые сложно изолировать с помощью webpack). Как происходит предотвращение повторных загрузок одинаковых библиотек(для примера был опыт использования d3 + плагины, весили в сжатом виде 1мб). Как происходит подгрузка функционала, который должен быть загружен сразу, но не является базовой. Главное еще не только в том, что решается ли, а какими жертвами.
На шарике такое проходил, извращению не было границ)
Статью не я писал, поэтому не могу ответить на все ваши вопросы, но главное — там есть, это изоляция, композиция и контроль жизненного цикла (CustomElements + Shadow DOM). Остальное решаемо, если руки растут из правильного места.

в 5 вебпаке из коробки есть возможность пилить микрофронтенды — https://webpack.js.org/concepts/module-federation/


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

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

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

В очередной раз убедился, что не бывает единорогов на радуге. В крупных компаниях тоже берут и делают кашу из подходов/библиотек/фреймворков/кода. А потом, когда пытаешься к ним устроиться на работу, рассказывают, какая у них сложная архитектура и если ты не работал с «такой-то» библиотекой, то и иди вон ковыряйся в легаси. Йоп, ребят, да любой в первый день глаза сломает от увиденного, если лезть в недра.

Крупные компании/проекты когда-то были маленькими.
Веб развивается. Конкуренты не дремлют. Пользователям нужны новые фичи. Требования к продуктам меняются очень быстро.


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

Спасибо, что описали «как делать не надо». Очень странная стала разработка: когда у проекта нет времени на нормальный рефакторинг и упрощение легаси архитектуры — они решают её усложнить! Это же абсурд.

Вы пишите, что не можете сейчас обновлять билиотеки независимо и это минус, по-вашему. Да это никакой не минус! У вас вместо устаревания одной библиотеки теперь будут устаревать десять. И времени потом их обновить точно не будет. Когда что-то ломается — надо ремонтировать, а не накрывать платочком и ставить сверху новое.
Sign up to leave a comment.