Многослойная архитектура
Наиболее распространенным архитектурным паттерном является паттерн многоуровневой архитектуры, известный также как паттерн n-уровневой архитектуры. Этот паттерн является фактическим стандартом для большинства приложений Java EE и поэтому широко известен большинству архитекторов, дизайнеров и разработчиков. Многоуровневая архитектура в значительной степени соответствует традиционным коммуникационным и организационным структурам ИТ в большинстве компаний, что делает ее естественным выбором для разработки большинства бизнес-приложений.
Описание паттерна
Компоненты в рамках модели многоуровневой архитектуры организованы в горизонтальные слои, каждый из которых выполняет определенную роль в приложении (например, логика представления или бизнес-логика). Хотя модель многоуровневой архитектуры не определяет количество и типы слоев, которые должны в ней присутствовать, большинство многоуровневых архитектур состоит из четырех стандартных слоев: презентационного, бизнес, персистентного и базы данных (рис. 1-1). В некоторых случаях бизнес-слой и слой персистентности объединяются в один бизнес-слой, особенно если логика персистентности (например, SQL или HSQL) встроена в компоненты бизнес-слоя. Таким образом, небольшие приложения могут иметь только три уровня, в то время как крупные и более сложные бизнес-приложения могут содержать пять и более уровней.
Каждый слой модели многоуровневой архитектуры имеет определенную роль и ответственность в приложении. Например, презентационный слой отвечает за работу с пользовательским интерфейсом и логикой взаимодействия с браузером, а бизнес-слой - за выполнение определенных бизнес-правил, связанных с запросом. Каждый слой в архитектуре формирует абстракцию вокруг работы, которую необходимо выполнить для удовлетворения конкретного бизнес-запроса. Например, презентационному слою не нужно знать и беспокоиться о том, как получить данные о клиенте; ему нужно только вывести эту информацию на экран в определенном формате. Аналогичным образом, бизнес-уровень не должен беспокоиться о том, как отформатировать данные о клиенте для отображения на экране, и даже о том, откуда они берутся; ему нужно только получить данные с уровня постоянства, выполнить бизнес-логику с этими данными (например, вычислить значения или агрегировать данные) и передать эту информацию на уровень представления.
Одной из мощных особенностей модели многоуровневой архитектуры является разделение задач между компонентами. Компоненты, находящиеся на определенном уровне, работают только с логикой, относящейся к этому уровню. Например, компоненты презентационного слоя работают только с логикой представления, а компоненты бизнес-слоя - только с бизнес-логикой. Такая классификация компонентов позволяет легко встроить в архитектуру эффективные модели ролей и ответственности, а также упростить разработку, тестирование, управление и сопровождение приложений, использующих данный архитектурный паттерн, благодаря четко определенным интерфейсам компонентов и ограниченности их области применения.
Ключевые понятия
На рис. 1-2 можно заметить, что каждый из слоев архитектуры отмечен как закрытый. Это очень важное понятие в модели многоуровневой архитектуры. Закрытый слой означает, что при перемещении запроса с уровня на уровень он должен пройти через слой, расположенный непосредственно под ним, чтобы попасть на следующий за ним уровень. Например, запрос, поступающий с презентационного уровня, должен сначала пройти через бизнес-уровень, затем через уровень постоянства и только после этого попасть на уровень базы данных.
Так почему бы не предоставить презентационному слою прямой доступ либо к слою постоянства, либо к слою базы данных? Ведь прямой доступ к базе данных с презентационного уровня гораздо быстрее, чем прохождение через кучу ненужных слоев для получения или сохранения информации из базы данных. Ответ на этот вопрос кроется в ключевой концепции, известной как уровни изоляции.
Концепция изолированных слоев означает, что изменения, внесенные в один слой архитектуры, как правило, не влияют на компоненты других слоев: изменения изолированы от компонентов этого слоя и, возможно, еще одного связанного с ним слоя (например, слоя персистентности, содержащего SQL). Если предоставить презентационному слою прямой доступ к персистентному слою, то изменения, внесенные в SQL в персистентном слое, повлияют как на бизнес-слой, так и на презентационный слой, что приведет к созданию очень тесно связанного приложения с большим количеством взаимозависимостей между компонентами. Такую архитектуру становится очень сложно и дорого изменять.
Концепция изолированных слоев также означает, что каждый слой независим от других слоев и, таким образом, практически не знает о внутренней работе других слоев архитектуры. Чтобы понять силу и важность этой концепции, рассмотрим масштабную работу по рефакторингу, направленную на преобразование фреймворка представления с JSP (Java Server Pages) на JSF (Java Server Faces). Если предположить, что контракты (например, модель), используемые между уровнем представления и бизнес-уровнем, остаются неизменными, то бизнес-уровень не пострадает от рефакторинга и останется полностью независимым от типа фреймворка пользовательского интерфейса, используемого уровнем представления.
Хотя закрытые слои обеспечивают изоляцию и, следовательно, помогают изолировать изменения в архитектуре, в некоторых случаях имеет смысл сделать некоторые слои открытыми. Например, необходимо добавить в архитектуру слой общих сервисов, содержащий общие сервисные компоненты, к которым обращаются компоненты бизнес-слоя (например, классы данных и строковых утилит или классы аудита и протоколирования). Создание слоя сервисов в этом случае обычно является хорошей идеей, поскольку архитектурно ограничивает доступ к общим сервисам только бизнес-слоем (а не уровнем представления). Без отдельного слоя архитектурно ничто не ограничивает доступ презентационного уровня к этим общим сервисам, что затрудняет управление этим ограничением доступа.
В данном примере новый слой сервисов, скорее всего, будет располагаться ниже бизнес-слоя, чтобы указать, что компоненты этого слоя сервисов недоступны с уровня представления. Однако в этом случае возникает проблема, поскольку бизнес-уровень теперь должен проходить через уровень сервисов, чтобы добраться до уровня персистентности, что совершенно бессмысленно. Это извечная проблема многоуровневой архитектуры, которая решается путем создания открытых слоев в архитектуре.
Как показано на рис. 1-3, уровень сервисов в данном случае помечен как открытый, что означает, что запросы могут обходить этот открытый уровень и переходить непосредственно к уровню, расположенному ниже него. В следующем примере, поскольку уровень сервисов открыт, бизнес-уровню теперь разрешено обходить его и переходить непосредственно к уровню персистентности, что вполне логично.
Использование концепции открытых и закрытых слоев помогает определить взаимосвязь между слоями архитектуры и потоками запросов, а также предоставляет проектировщикам и разработчикам необходимую информацию для понимания ограничений доступа к различным слоям в архитектуре. Неспособность задокументировать или должным образом сообщить, какие слои в архитектуре являются открытыми и закрытыми (и почему), обычно приводит к созданию жестко связанных и хрупких архитектур, которые очень сложно тестировать, поддерживать и развертывать.
Перевод книги "Software Architecture Patterns".