Марк Ричардс

Паттерны архитектуры

программного обеспечения

Общие шаблоны архитектуры и способы их применения


Исходный текст, 2015 / Русский перевод, 2023


Оглавление

Глава 3
Микроядерная архитектура (Microkernel architecture)
Паттерн микроядерной архитектуры (второе название — паттерн архитектуры подключаемых модулей, плагинная архитектура) является естественным паттерном для реализации продуктовых приложений. Продуктовое приложение — это приложение, которое упаковано и доступно для скачивания в различных версиях, как типичный продукт стороннего производителя. Однако, многие компании также разрабатывают и выпускают свои внутренние бизнес-приложения как программные продукты, укомплектованные версиями, примечаниями к релизу и подключаемыми функциями. Такие приложения также естественным образом подходят для этого паттерна. Паттерн микроядерной архитектуры позволяет добавлять дополнительные функции приложения в качестве подключаемых модулей к основному приложению, обеспечивая расширяемость, а также разделение и изоляцию функций.
Описание паттерна
Паттерн микроядерной архитектуры состоит из двух типов архитектурных компонентов: основной системы (core system) и подключаемых модулей (plug-in modules). Логика приложения разделена между независимыми подключаемыми модулями и основной системой, что обеспечивает расширяемость, гибкость и изоляцию функций приложения и пользовательской логики обработки. На Рисунке 3-1 показана базовая схема паттерна микроядерной архитектуры.

Рисунок 3-1. Паттерн микроядерной архитектуры

Основная система паттерна микроядерной архитектуры традиционно содержит только минимальную функциональность, необходимую для работы системы. Многие операционные системы (далее — ОС) реализуют паттерн микроядерной архитектуры, отсюда и происхождение названия этого паттерна. С точки бизнес-приложений, основная система — это общая бизнес-логика без пользовательского кода для особых случаев, специальных правил или сложной обработки условий.
Подключаемые модули — это отдельные, независимые компоненты, которые содержат специализированную обработку, дополнительные функции и пользовательский код, предназначенный для улучшения или расширения основной системы для создания дополнительных бизнес-возможностей. Как правило, подключаемые модули должны быть независимы от других подключаемых модулей, но вы можете разработать модули, требующие присутствия других модулей. В любом случае, важно поддерживать коммуникацию между подключаемыми модулями на минимуме, чтобы избежать проблем с зависимостями.
Основная система должна знать, какие подключаемые модули доступны и как к ним добраться. Одним из распространённых способов реализации этого, является использование своего рода реестра подключаемых модулей. Этот реестр содержит информацию о каждом подключаемом модуле, включая такие вещи, как: имя модуля, контракт данных и сведения о протоколе удаленного доступа (в зависимости от того, как подключаемый модуль соединён с основной системой). Например, подключаемый модуль для налогового программного обеспечения, который в процессе налогового аудита сигнализирует об элементах с высоким риском, может иметь запись реестра, содержащую имя службы (AuditChecker), контракт данных (входные и выходные данные) и формат контракта (XML). Она также может содержать WSDL-описание (Web Services Definition Language), если плагин подключается через SOAP.
Подключаемые модули могут быть соединены с основной системой различными способами, а именно: через фреймворк OSGi (Open Service Gateway initiative), обмен сообщениями, веб-сервисы, или даже прямое связывание данных, например, через создание экземпляра класса (object instantiation). Тип используемого соединения зависит от размеров приложения, которое вы создаёте (небольшой продукт или крупное бизнес-приложение), и ваших конкретных потребностей (например, одиночное развёртывание или распределённое развёртывание). Сам по себе архитектурный паттерн не определяет никаких деталей реализации, кроме того, что подключаемые модули должны независимыми друг от друга.
Контракты между подключаемыми модулями и основной системой могут варьироваться от стандартных до пользовательских. Пользовательские контракты обычно встречаются в ситуациях, когда подключаемые компоненты разрабатываются третьей стороной и вы не можете контролировать контракт, используемый подключаемым модулем. В таких случаях обычно создаётся адаптер между контрактом подключаемого модуля и вашим стандартным контрактом, чтобы основная система не нуждалось в специализированном коде для каждого подключаемого модуля. При создании стандартных контрактов (обычно реализуемых через XML или Java Map) с самого начала необходимо создать стратегию управления версиями.
Пример применения шаблона
Возможно, лучшим примером микроядерной архитектуры является среда разработки приложений — IDE Eclipse. Загрузив базовый продукт Eclipse, вы получаете не более, чем современный редактор кода. Однако, как только вы начинаете добавлять плагины (подключаемые модули), он становится настраиваемым и полезным продуктом. Интернет-браузеры — это ещё один распространённый пример продукта, использующего микроядерную архитектуру. Средства просмотра и другие подключаемые модули добавляют дополнительные возможности, которых нет в базовом браузере (то есть в основной системе).
Можно привести бесконечное число примеров программных продуктов, но как насчёт крупных бизнес-приложений? Микроядерная архитектура применима и в этих ситуациях. Чтобы показать это, давайте рассмотрим ещё один пример страховой компании, но на этот раз связанный с обработкой страховых претензий.
Обработка претензий — очень сложный процесс. В каждом штате действуют свои правила и положения о том, что разрешено и что запрещено в страховом случае. Например, в некоторых штатах разрешена бесплатная замена лобового стекла, если оно было повреждено камнем, а в других штатах запрещена замена. Это создаёт почти бесконечный набор условий для стандартного рассмотрения претензий.
Неудивительно, что большинство приложений для урегулирования страховых претензий используют большие и сложные механизмы правил для обработки этой запутанности. Однако, эти механизмы правил могут вырасти в большой комок грязи (big ball of mud), в котором изменение одного правила влияет на другие правила. Или простое изменение правил требует армии аналитиков, разработчиков и тестировщиков. Использование паттерна микроядерной архитектуры может решить многие из этих проблем
Стопка папок, которую вы видите на Рисунке 3-2, представляет собой основную систему для обработки претензий. Она содержит основную бизнес-логику, необходимую страховой компании для обработки претензии, за исключением какой-либо специфической обработки. Каждый подключаемый модуль содержит специфические правила для своего штата (NH, TX и т.д — это аббревиатуры штатов США. — прим пер). В этом примере подключаемые модули могут быть реализованы с помощью частного исходного кода или с помощью отдельного экземпляра обработчика правил (rules engine). Независимо от реализации, ключевым моментом является то, что правила и обработка для конкретного штата отделены от основной системы обработки претензий и могут быть добавлены, удалены или изменены практически без последствий для остальной части основной системы или других подключаемых модулей.

Рисунок 3-2. Пример микроядерной архитектуры

Рекомендации
Одним из преимуществ паттерна микроядерной архитектуры является то, что он может быть встроен или использован как часть другого архитектурного паттерна. Например, если этот паттерн решает конкретную проблему, связанную с определённой изменчивой областью приложения, вы можете обнаружить, что с помощью этого паттерна невозможно реализовать всю (entire) архитектуру. В этом случае вы можете встроить архитектурный паттерн микросервисов в другой используемый вами паттерн (например, слоистую архитектуру). Аналогичным образом, компоненты обработчика событий, описанные в предыдущей главе, посвящённой событийно-ориентированной архитектуре, могут быть реализованы с использованием паттерна архитектуры микросервисов.
Архитектурный паттерн микросервисов обеспечивает отличную поддержку эволюционного проектирования и инкрементального метода разработки. Вы можете сначала создать надёжную основную систему, а по мере развития приложения, инкрементально добавлять фичи и функциональные возможности без необходимости вносить значительные изменения в основную систему.
Для продуктовых приложений, паттерн микроядерной архитектуры всегда должен быть выбран в качестве начальной архитектуры, особенно для тех продуктов, где вы с течением времени будете выпускать дополнительные функции и хотите контролировать, какие пользователи получат те или иные функции. Если со временем вы обнаружите, что этот паттерн не удовлетворяет всем вашим требованиям, вы всегда можете сделать рефакторинг вашего приложения, перейдя на другой архитектурный паттерн, более подходящий для ваших конкретных требований.
Анализ паттерна
Далее приведены оценки и общий анализ характеристик паттерна микроядерной архитектуры. Оценка для каждой из характеристик основана на естественном проявлении данной характеристики, как способности, качества (архитектуры), проявляющейся при реализации паттерна, а также на том, чем в целом известен этот паттерн. Для сопоставительного сравнения и получения представления о том, как этот паттерн соотносится с остальными паттернами нашего обзора, обратитесь к Приложению А в конце книги.
Общая адаптивность (Overall agility)
Оценка: Высокая
Анализ: Общая адаптивность — это способность быстро реагировать на постоянно меняющуюся среду. Изменения могут быть в значительной степени изолированы и быстро реализованы с помощью слабо-связанных подключаемых модулей. В целом, основная система в большинстве микроядерных архитектур быстро становится стабильной, и как таковая является устойчивой и требует незначительных изменений с течением времени.
Простота развёртывания (Ease of deployment)
Оценка: Высокая
Анализ: В зависимости от способа развёртывания паттерна, подключаемые модули могут быть динамически добавлены к основной системе во время развёртывания (например, hot-deploy — быстрая доставка изменений), что позволяет минимизировать время простоя в этом процессе.
Тестируемость
Оценка: Высокая
Анализ: Подключаемые модули могут тестироваться изолированно и могут быть легко имитированы основной системой для демонстрации или создания прототипа определённой функции с минимальными изменениями в основной системе или без изменений.
Производительность
Оценка: Высокая
Анализ: Хотя паттерн микроядерной архитектуры не предназначен для высокопроизводительных приложений, в целом, большинство приложений, построенных с использованием этого шаблона, работают хорошо. Это происходит, потому что вы можете настраивать и оптимизировать приложения, чтобы включить только те функции, которые вам нужны. JBoss Application Server является хорошим примером такого случая. Благодаря архитектуре подключаемых модулей вы можете сократить сервер приложений только до тех функций, которые вам нужны, удалив дорогостоящие неиспользуемые функции, такие как дистанционный доступ, обмен сообщениями и кэширование, которые потребляют память, процессор и потоки, что замедляет работу сервера приложений.
Масштабируемость
Оценка: Низкая
Анализ: Поскольку большинство реализаций микроядерной архитектуры относятся к продуктовым приложениям и обычно имеют меньший размер, они поставляются как единственный модуль развертывания, следовательно, не обладают высокой масштабируемостью. В зависимости от того, как реализованы подключаемые модули, иногда можно обеспечить масштабируемость на уровне подключаемых функций. Но в целом этот паттерн не славится созданием высоко масштабируемых приложений.
Простота разработки
Оценка: Низкая
Анализ: Микроядерная архитектура требует продуманного дизайна и надзора за контрактами, что делает её довольно сложной для реализации. Управление версиями контрактов, внутренние реестры подключаемых модулей, гранулярность модулей и широкий выбор доступных вариантов подключения модулей — всё это вносит свой вклад в сложность реализации этого паттерна.
Глава 4
Паттерн архитектуры микросервисов