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

Вступление

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

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

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

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

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

Что такое микрофронтенд?

Возможно, вы уже слышали этот термин «микрофронтенд» - несмотря на то, что он впервые был использован еще в 2015 году, особенно в 2019 году он стал еще одним модным ИТ-словом в Интернете. Он достаточно популярен, чтобы привлечь внимание самых известных наших коллег-программистов, одним из которых является Дэн Абрамов, который в мае 2019 года написал в Твиттере, что не понимает концепции. Этот твит вызвал долгую и изнурительную дискуссию в Твиттере, а также послужил справочником для множества статей, сообщений в блогах, видеороликов влогах или выступлений на конференциях. Неудивительно, что изначально дискуссия была очень ожесточенной, многие известные эксперты высказали свое мнение, были подняты и обсуждены многие важные вопросы.

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

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

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

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

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

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

Почему мы делаем микрофронтенды?

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

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

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

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

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

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

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

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

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

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

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

Насколько микро такое микрофронтенд?

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

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

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

Возможность повторного использования

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

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

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

Право собственности

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

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

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

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

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

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

Чистый размер

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

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

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

На практике

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

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

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

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

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

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

продолжить чтение

использованная литература