- не проектируются пути эвакуации через помещения, рассчитанные на одновременное пребывание более 50 человек;
- в качестве второго и последующего эвакуационного выхода и прохода принимают проходы через зал.
Мероприятия, направленные на совершенствование и модернизацию систем эвакуации зданий кинотеатров:
- использование современных систем оповещения при эвакуации (замена старых звуковых оповещателей на более новые и модернизированные (например, АС-10(ООПЗ-12));
- плановые проверки всех систем эвакуации;
- обучение персонала правилам эвакуации при помощи новых цифровых систем и оборудования;
- замена выработавших свой ресурс указателей эвакуации;
- выработка у персонала кинотеатров навыков работы с современными системами эвакуации;
- ежеквартальные проверки знаний персоналом работы с современным оборудованием для эвакуации;
- использование светодиодных указателей маршрута эвакуации;
- использование современных фотолюминесцентных эвакуационных средств.
Список литературы
1. Федеральный закон Российской Федерации от 21 декабря 1994 года № 69-ФЗ «О пожарной безопасности» (с изменениями и дополнениями от 22.12.20).
2. Федеральный закон Российской Федерации от 22 июля 2008 года № 123-ФЗ «Технический регламент о требованиях пожарной безопасности» (с изменениями и дополнениями от 27.12.2018).
3. СП 1.13130.2020 Системы противопожарной защиты. Эвакуационные пути и выходы.
4. СП 3.13130.2009 Системы противопожарной защиты. Система оповещения и управления эвакуацией людей при пожаре. Требования пожарной безопасности.
5. СП 52.13330.2016 Естественное и искусственное освещение. Актуализированная редакция СНиП 23-05-95* (с Изменением № 1).
6. ГОСТ 31565-2012 Кабельные изделия. Требования пожарной безопасности.
МИКРОСЕРВИСНАЯ АРХИТЕКТУРА НА FRONTEND
Сабиров Д.А.
Сабиров Данил Анварович - старший архитектор, Кампания WaveAccess, г. Санкт-Петербург
Аннотация: в статье рассматриваются эволюция архитектур построения веб-приложений, их преимущества и недостатки. А также более подробно реализация микросервисной архитектуры на Frontend.
Ключевые слова: веб-разработка, веб-приложения, Single Page Application, Frontend, Backend, микросервисная архитектура, Module Federation, Webpack, IFrame, пакетные менеджеры.
Эволюция архитектуры веб-приложений
Формально рождение Frontend можно связать с появлением в 2002 году патента US8136109B1 [1], в котором описывается концепция одностраничного веб-
15
приложения (Single Page Application). Но фактически Frontend стал набирать популярность только в начале 2010 годов с появлением таких Frantend-библиотек как Knockout и AngularJs. Спустя 10 лет рынок Frantend-разработки в плане разрабатываемых технологий можно назвать устоявшимся, и на нем доминируют следующие три фреймворка: Angular, React и Vue.js.
Прежде чем перейти к рассмотрению Single Page Application (в дальнейшем SPA), необходимо рассмотреть, как выглядело стандартное веб-приложение (см. рис. 1), а также в чём была необходимость разделения монолитного веб-приложения [2] отдельно на Backend и Frontend приложения, которые сейчас являются стандартами разработки.
Рис. 1. Трехзвенная архитектура монолитного веб-приложения
Как можно заметить, типовая архитектура монолитного приложения разбита на три уровня, поэтому она получила название "трехуровневая" или "трехзвенная". Давайте рассмотрим эти уровни:
1. Слой доступа данных (Data Access Layer, DAL) отвечает за работу с Базами Данных. Как правило, работа на этом уровне реализуется через паттерн проектирования Репозиторий [3]
2. Бизнес-слой (Business Layer, BL) инкапсулирует всю бизнес-логику приложения, а также является связующим звеном между слоями данных и представления.
3. Слой представления (UI Layer / Presentation Layer) ответственен за клиентскую часть, а именно, за то, что отобразится на клиентской стороне.
Для начала 2000-х гг. данная архитектура была вполне оправдана, поскольку принцип «тонкого клиента» [4], который обеспечивала данная архитектура, позволял отображать веб-приложение на браузерах персональных компьютерах (ПК), которые по мощности были в десятки раз слабее нынешних ПК. Однако дальнейший рост производительности ПК, который косвенно описывает закон Мура [5], с одной стороны, и повышение требований интерактивности и быстродействия к разрабатываемым веб-приложениям со стороны конечных пользователей с другой стороны, привели к тому, что на рубеже 2010-х гг. состоялся переход к концепции «толстого клиента» [6]. Для конечного пользователя принцип "толстого клиента" обеспечивала технология SPA, которая позволяет выполнять весь клиентский код в браузере. Как следствие такого перехода, серверная часть (Backend) избавляется от слоя представления полностью.
Теперь рассмотрим, как выглядит типовое веб-приложение, у которого есть отдельно серверная и клиентская часть.
Рис. 2. Структура веб-приложения, разделенного на серверную (Backend) и клиентскую
(Frontend) части
Какие отличия можно заметить на схеме, изображенной на рис. 2:
• Клиентская часть в виде index.html загружается один раз в браузер пользователя.
• Все ресурсы (js-скрипты, CSS-стили и различного рода ресурсы в виде иконок, вспомогательных json-файлов и прочего), необходимые для запуска SPA, загружаются в той последовательности, которая прописана в index.html разработчиками системы.
• Далее происходит инициализация и запуск SPA, которое изобразит конечное представление.
• Серверная часть лишилась слоя представления и вместо него реализует REST API, необходимое для общения с SPA.
• SPA общается с Backend с помощью HTTP-запросов: запрашивает, сохраняет, редактирует и удаляет данные. Как правило, общение происходит через json, но Restful-реализация Backend не ограничивает формат общения, поэтому можно реализовать любой удобный формат.
Если говорить о разработке, то подход разделения кода на две независимые части - Backend и Frontend - даёт большое преимущество в виде разделения команды на две независимые группы разработчиков. Если имеется хорошее техническое задание, то единственное, о чём необходимо договориться этим двум командам: о списке API и структуре передаваемых данных (Data Transfer Objects). Данные договоренности дают возможность вести параллельную разработку: например, группа Frontend-разработчиков может реализовывать клиентскую часть с помощью фиктивных сервисов общения с Backend, не дожидаясь того момента, когда Backend будет реализован. Либо, наоборот, Backend может реализовывать свою логику и тестировать REST API с помощью unit-тестов, а лучше также с помощью любой из утилит, позволяющей отправлять HTTP-запросы. Что же касается развертывания приложения, то данный процесс будет происходить параллельно для Backend- и Frontend-кода.
Микросервисная архитектура для Backend
Дальнейшей эволюцией разработки веб-приложений стала реализация микросервисной архитектуры для Backend, которая получила широкое распространение в 2014-2015 годах и к текущему времени является общепринятой практикой разработки больших приложений. На рис. 3 представлена упрощенная схема веб-приложения с данной архитектурой, где все микросервисы обращаются к единой Базе Данных, а между собой не общаются.
Рис. 3. Структура веб-приложения с микросервисной Backend- и монолитной Frontend-частью
Как можно заметить из данной схемы, серверная реализация разбивается на отдельные независимые части, каждая со своей бизнес логикой, слоем доступа данных и методами Rest api, а также своим веб-сервером.
Рассмотрим плюсы и минусы данной архитектуры веб-приложения. Плюсы:
• Разделение бизнес-логики.
• Параллельная работа команд.
• Независимое развертывание микросервисов.
• Масштабирование приложения: чтобы добавить новый микросервис, не нужно пересобирать остальные сервисы.
• Локализация ошибок на уровне того микросервиса, в котором она возникла.
Минусы:
• Как правило, необходимы специалисты DevOps для развертывания приложения.
• Общение между командами ограничивается уровнем той бизнес-логики, которую необходимо реализовать той или иной команде. Как следствие, разработчики все хуже себе представляют логику работы приложения в целом.
• Общение между сервисами становится более сложным и может быть источником потенциальных проблем.
• Отладка ошибок может быть сложнее, чем при монолите.
Итак, самым слабым местом данной архитектуры становится монолитный Frontend, т.к. оно не позволяет воспользоваться одним из тех преимуществ, ради которых задумывалась данная архитектура, а именно, независимым развертыванием микросервисов.
Проиллюстрируем данную проблему: допустим, ведется параллельная разработка нескольких функциональных возможностей веб-приложения. Работа ведётся параллельно несколькими командами серверных разработчиков (каждая работает над своим микросервисом), а также командой Frontend-разработчиков. Все изменения планируется развернуть для конечного пользователя в конце текущего месяца. За несколько дней до назначенной даты выясняется, что один из микросервисов ведёт себя нестабильно, и в назначенный срок не получится реализовать заданный функционал. Однако к тому моменту весь Frontend уже был реализован и передан на тестирование. Возникает проблема: если серверный микросервис можно просто не выкладывать, то откатить изменения в монолитном Frontend зачастую очень сложно и трудозатратно, и бывает проще дождаться реализации недоделанного микросервиса. В конечном счете, монолитный Frontend при развертывании "тянет" за собой автоматически развертывание и всех микросервисов Backend.
Микросервисная архитектура для Frontend
Логичным продолжением развития веб-приложений стало разделение Frontend также на отдельные микросервисы. Данный тип проектирования стал набирать популярность совсем недавно - около 2-3 лет назад. Связано это с желанием масштабировать веб-приложения, в которых, как мы уже выяснили, Frontend являлся узким местом.
Мартин Фаулер [7] дал следующее определение микросервисной реализации Frontend:
Архитектурный стиль, при котором независимо доставляемые клиентские приложения объединяются в единое целое.
Рис. 4. Структура веб-приложения с микросервисной архитектурой как на стороне Backend,
так и на стороне Frontend
На рисунке выше хорошо видно, что, клиентское приложение разбивается на отдельные N+1 Frontend приложения: где N приложений предназначены для работы с соответствующими N-сервисами Backend, а N+1-ое приложение является основным (корневым) клиентским приложением, которое подгружает все остальные приложения.
Может показаться, что выбор данной архитектуры для разработки очевиден. Однако не стоит спешить, поскольку у данного подхода, помимо ярко выраженных преимуществ, имеются свои недостатки.
Плюсы:
• Независимое и более гибкое развертывание: такая архитектура позволяет публиковать приложение отдельными частями по мере готовности каждой из них
• Разделение разработчиков на отдельные группы, каждая из которых работает над своим микросервисом, реализующим свою отдельную логику
• Возможность масштабирования: легко добавить новую команду разработчиков для реализации нового микросервиса
• Возможность построения гетерогенной системы: поскольку каждый из сервисов является самодостаточным, он может быть реализован на любом фреймворке/библиотеке
• Независимое тестирование: каждый микросервис является отдельным приложением, а значит и тестировать их можно независимо друг от друга
Минусы:
• Наличие основного приложения, которое должно загрузить все остальные микросервисы. Помимо этого, оно будет реализовывать роутинг и аутентификацию
• Сложность взаимодействия между микросервисами: поскольку приложение представляет собой совокупность отдельных приложений, то необходимо реализовать механизм общения между ними
• Проблема общих стилей и компонент: несмотря на то, что каждый микросервис является отдельным приложением, он все равно - часть большого приложения, которая должна использовать единые стили и общие компоненты
• Сложность разработки по сравнению с монолитной архитектурой: особенно это будет заметно в первое время, когда необходимо будет организовать разработку отдельных команд, попутно решая вопрос реализации основного приложения и другие архитектурные проблемы
• Меньше разработчиков будут знать, как устроен продукт в целом, так как в процессе разделения приложения на микросервисы, разделяются и компетенции технических специалистов
Как видно, основным недостатком микросервисной архитектуры является трудозатратность реализации, особенно если это касается уже написанной системы с большой кодовой базой. Кроме того, на текущий момент нет устоявшихся практик реализации данной архитектуры для клиентской части, поэтому этот подход сейчас находит популярность только среди больших проектов, где действительно есть потребность в разделении кода и команды на независимые части.
Рассмотрим подробнее, как можно реализовать данную архитектуру.
Использование IFrame
Тег IFrame является одним из старейших в спецификации HTML (поддерживается с версии 4, выпущенной в 1997 г.). Он позволяет в рамках текущего HTML-документа встроить любую веб-страницу, указав её url. При этом для дочернего HTML-документа через установку атрибутов можно предоставить возможность отправлять формы, запускать сценарии, открывать всплывающие окна и т.д.
Реализация микросервисной архитектуры с применение IFrame предполагает, что все микросервисы развернуты как независимые веб-приложения, а основное приложение посредством тегов IFrame внутри себя указывает, какие веб-страницы нужно подгрузить. Для конечного пользователя приложение будет выглядеть как одностраничное.
Несмотря на то, что IFrame позволяет легко внедрить другую веб-страницу, у данного подхода есть существенная проблема: система на клиентской части будет представлена в виде N-ого набора отдельных приложений и, в случае необходимости общения между ними, IFrame предоставляет не самый удобный механизм для этого.
23
Другая проблема — как организовать исходный код всех приложений, если у них будут общие компоненты, стили и другие общие ресурсы. Отсюда же вытекает и проблема того, как компилировать и собирать все эти приложения в дальнейшем. Очевидно, что сборку придётся настраивать вручную и на практике это может оказаться не самым простым и быстрым занятием.
Резюмируя, IFrame отлично подходит для тех приложений, которые действительно независимые вплоть до стилей и прочих ресурсов.
Микросервисы как пакеты
Другой подход состоит в том, чтобы выделить модули в отдельные пакеты (packages) посредством таких пакетных менеджеров как npm или yarn. Он применим в случае, когда реализована модульная архитектура.
Пакетные сборки в виде npm или yarn уже давно получили популярность благодаря простоте внедрения в проект. Поэтому построение комплексного приложения с использованием своих пакетов не должно вызывать сложностей у разработчиков. Однако при создании приложения, где модули будут представлены в виде отдельных пакетов, общие компоненты, скорее всего, придется также реализовывать в виде пакетов. Отсюда возникает первая потенциальная проблема -управление зависимостями: чем больше модулей и общих компонент, которые они используют, тем сложнее будет вести параллельную разработку модулей, особенно когда работу ведут независимые команды разработчиков.
Другой проблемой может стать совместное использование общих ресурсов (стили, картинки, различные json файлы) между пакетами, которые представляют приложения. А так как основные ресурсы хранятся в основном приложении, то встает вопрос - как их внедрить во все остальные приложения. Одна из возможных реализаций - использование symlink; вторая - использование менеджеров задач (Gulp, Rollup и т.д.), при сборке приложений для внедрения в библиотеку; третья - вновь реализация в виде отдельных пакетов. Сложность данной проблемы будет возрастать пропорционально росту пакетов.
Итак, данная архитектура подходит в том случае, когда модули независимы, а использование общих ресурсов между пакетами не вызывает трудностей. В остальных ситуациях такой подход не рационален.
Индивидуальные решения (custom solutions)
Когда необходимо контролировать весь процесс сборки, уместна реализация индивидуального решения. Это самый сложный путь, но он позволяет реализовать наиболее оптимальное решение под существующие потребности.
Первое, с чем необходимо определиться, - как именно будут реализованы микросервисы: с использованием каких фреймворков, будет ли система гетерогенная? Проще, чтобы вся система была написана на одном фреймворке/библиотеке, так как такой код проще поддерживать и легче переиспользовать. Помимо этого, в случае однородной системы передавать данные между микросервисами проще, так как везде можно использовать единый подход. После выбора технологий разработки микросервисов, необходимо решить, как эти микросервисы будут встраиваться в основное приложение.
Здесь появляется вторая проблема: реализация механизма загрузки микросервисов в основном приложении. Если микросервисы написаны на разных фреймворках/библиотеках, то задача усложняется. Если же все микросервисы созданы на едином фреймворке, то можно найти готовые решения, позволяющие подгрузить другие приложения. Так, например, для Angular одно из популярных решений - библиотека Mooa [8]. Также в рамках данной архитектуры вполне уместно частичное использование IFrame или пакетного подхода.
Описанный подход рационален только в случае, когда необходимо реализовать наиболее оптимальное решение с точки зрения загрузки микросервисов, либо сценарий загрузки нетривиален. Безусловно, такой путь наиболее трудозатратный.
24
Module Federation в Webpack 5
Сборка большинства Frontend-приложений выполняется с помощью инструмента Webpack. Этот сборщик модулей позволяет скомпилировать приложение с учетом всех зависимостей и ресурсов в виде готовой index.html страницы, js-скрипт файлов приложения (по умолчанию, в сжатом виде) и всех прочих необходимых ресурсов (стили, картинки, шрифты, json-файлы и т.д.), которые можно сразу развернуть на требуемом окружении. При этом Webpack самостоятельно определяет граф связности файлов проектов и очередность их включения в итоговую сборку, определяет и включает в сборку vendor code (используемый фреймворк/библиотеку), определяет все зависимости от сторонних библиотек и помещает их в итоговую сборку. Также, если имеются динамически подгружаемые (lazy loading) модули, то он помещает их в отдельные js-файлы (именуя их chunk файлами), которые подгружаются при необходимости.
Несмотря на то, что Webpack умеет динамически подгружать модули, делает он это лишь в рамках текущей сборки (проекта). Такая реализация накладывает ограничения в виде монолитного кода, который невозможно разбить на отдельные приложения с отдельными репозиториями.
В 2017 году решением данной проблемы занялся Zack Johnson, который активно обсуждал возможную реализацию проблемы в своем блоге [9] на протяжении последующих трех лет. В результате, в октябре 2020 года вместе с выходом Webpack 5.0 стал доступен новый плагин Module Federation [10].
Module Federation позволяет динамически подгружать модули (chunks) из других webpack сборок - иными словами, динамически подгружать код из других проектов/репозиториев. При этом основное приложение не теряет тех преимуществ, которое имело при монолитном коде: оно работает с чужими модулями так, как будто они находятся в том же проекте, поэтому не возникает проблем с передачей данных, параметров и проч. Вместе с этим решается проблема совместного использования общих ресурсов: картинок, шрифтов, css стилей, json-файлов и т.д. Помимо этого, Module Federation самостоятельно определяет vendor код (исходных код используемого фреймворка) и загружает его только один раз. Среди прочих преимуществ инструмента можно отметить возможность пересобрать отдельный модуль, не пересобирая все приложение. Более того, есть возможность реализовать Server-side rendering (SSR); но на текущий момент "из коробки" SSR не работает, и webpack необходимо сконфигурировать самостоятельно.
При всех ее достоинствах, Module Federation - новая и пока недостаточно распространенная технология: недостаток информации ощущается не только в Рунете, но и на англоязычных Интернет-ресурсах. Отметим также следующие потенциальные проблемы, связанные с технологией:
• в любом случае потребуется разбираться с конфигурированием Webpack, а для больших проектов это может занять большое время;
• могут возникать неинформативные ошибки, которые будет тяжело отлаживать;
• типы не передаются между модулями, поэтому придется вручную создавать декларационные файлы (d.ts файлы в typescript) там, где это необходимо;
• проблема зависимостей дочерних модулей на одни и те же внешние пакеты: желательно избегать ситуации, когда модули используют разные версии одного и того же пакета;
• vendor code один на все модули: невозможно проверить, как будет работать отдельный модуль на более новой версии фреймворка.
Таким образом, на сегодняшний день Module Federation - самый простой способ реализовать полноценную микросервисную архитектуру для Frontend: код можно разбить на отдельные проекты, при этом в дальнейшем подключить код из других сборок не составит труда - в этом поможет конфигурирование Webpack.
Подводим итоги
Манфред Штейер (Manfred Steyer) - один из евангелистов микросервисной архитектуры - в своём блоге [11] определил десять критериев для ее оценки (см. табл. 1).
Таблица 1. Критерии для оценки возможных решений микросервисной архитектуры
Архитектурные цели Описание
Изолированность Влияют ли пользовательские сценарии друг на друга
Независимое развертывание Может ли микросервис быть пересобран и развернут независимо от остального приложения
Одностраничное приложение (SPA) Является ли приложение в целом все еще одностраничным
Гетерогенность системы Могут ли микросервисы использовать разные фреймворки/библиотеки
Tree shaking (Встряхивание дерева зависимостей) Возможность исключать при сборке кода неиспользуемый код
Единый код фреймворка/библиотеки (vendor code) Возможность загрузить код фреймворка/библиотеки только один раз
Возможность изображать несколько микросервисов одновременно Могут ли в пользовательском окне отображаться сценарии из двух разных микросервисов одновременно
Предупреждение конфликта версий Решается ли проблема конфликта версий
Параллельная разработка Может ли быть Frontend-код полноценно разделен между разными командами разработчиков
Единая итоговая сборка Итоговый код всего приложения собирается в единую сборку
На мой взгляд, данные критерии позволяют безоговорочно определить, какими преимуществами и недостатками обладает то или иное решение.
В таблице 2 можно увидеть окончательное сравнение с учетом данных критериев.
Таблица 2. Сравнительная таблица микросервисных архитектур для Frontend
Цели\Архитектура IFrame Пакетный подход Индивидуа льное решение Module Federation
Изолированность + + +/- +
Независимое развертывание + - + +
Одностраничное приложение (SPA) + + + +
Гетерогенность системы + - + -
Tree shaking (Встряхивание дерева зависимостей) + + - +
Единый код фреймворка/библиотеки (vendor code) - + - +
Возможность изображать несколько микросервисов одновременно + + + +
Предупреждение конфликта версий + - - +
Параллельная разработка + - + +
Единая итоговая сборка - + - +
Идеальных решений на сегодняшний день нет, и в любом случае придется мириться с какими-то их недостатками. Однако Module Federation позволяет закрыть основные потребности при разработке микросервисных приложений на Frontend, при этом с минимальными трудозатратами по сравнению с другими подходами. Без сомнений, именно эта технология станет доминирующей при разработке Frontend-приложений на ближайшие несколько лет.
Список литературы
1. US patent 8136109B1: [Электронный ресурс]. Режим доступа: https://patents.google.com/patent/US8136109Bl/en/ (дата обращения:26.10.2021).
2. Fowler Martin. Patterns of Enterprise Application Architecture, 2002.
3. Статья про паттерн Репозиторий на портале "Справочник Паттернов Проектирования": [Электронный ресурс]. Режим доступа: http://design-pattern.ru/patterns/repository.html/ (дата обращения:26.10.2021).
4. Статья "Тонкий клиент" на Wikipedia: [Электронный ресурс]. Режим доступа: https://en.wikipedia.org/wiki/Thin_client/ (дата обращения:26.10.2021).
5. Moore Gordon E. "Cramming more components onto integrated circuits", 1965.
6. Статья "Толстый клиент" на Wikipedia: [Электронный ресурс]. Режим доступа: https://en.wikipedia.org/wiki/Rich_client/ (дата обращения:26.10.2021).
7. Fowler Martin. Статья "Micro Frontends": [Электронный ресурс]. Режим доступа: https://martinfowler.com/articles/micro-frontends.html/ (дата обращения:26.10.2021).
8. Библиотека Mooa: [Электронный ресурс]. Режим доступа: https://github.com/phodal/mooa/ (дата обращения:26.10.2021).
9. Блог Zack Jackson: [Электронный ресурс]. Режим доступа: https://scriptedalchemy.medium.com/ (дата обращения:26.10.2021).
10. Официальная документация Module Federation на портале webpack. [Электронный ресурс]. Режим доступа: https://webpack.js.org/concepts/module-federation/ (дата обращения:26.10.2021).
11. Блог Manfred Steyer. [Электронный ресурс]. Режим доступа: https://www.angulararchitects.io/en/blog/ (дата обращения:26.10.2021).
12. Steyer Manfred. Enterprise Angular, 2021.
13. Herrington Jack, Jackson Zack. Practical Module Federation, 2021.