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

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

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

Слоистая архитектура

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

- "Transaction script"
- "Domain model"
- "Table Module"
- "Service Layer"

При реализации данных шаблонов следует придерживаться принципа разделения низкоуровнего доступа к хранилищам данных (БД) и непосредственно самими данными. Изоляция может быть реализована с помощью служебных сервисов, отвечающих за реализацию хранения данных и работы с интерфейсами СУБД.

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

С учетом развития SPA и переноса значительной функциональности с сервера на фронт, архитектура фронтенда и бэкенда становятся абсолютно идентичными, за тем исключением, что со стороны бэкенда API выполняет пассивную роль (отвечает на запросы), а на стороне фронтенда активную роль (делает запросы).

Модульное представление

Логика приложения:

- API
- Сервисный уровень
- Инфраструктурный уровень

Логика домена:

- Бизнес-логика

Идея: Способ организации бизнес-логики по процедурам, каждая из которых обслуживает один запрос, инициируемый слоем представления. Шаблоны корпоративных приложений. М. Фаулер

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

Жизненный цикл Transaction script

Частые ошибки:

- объединение сценария транзакции и источника данных;
- толстый контроллер;
- сложная логика, не подходящая к реализации в рамках простой транзакции;

Где может быть реализован "transaction script":

- сервис 
- модель

Варианты реализации:

- все сценарии в одном классе;
- паттерн "команда".

Недостатки:

- большое дублирование кода;
- нельзя покрыть сложную логику.

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

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

Существует два варианта реализации:

- простая - когда одна таблица БД отображается в один класс бизнес-логики
- сложная - когда существует сложная иерархия наследования и множество
 отношений между сущностями;

Допускается комбинация доменной модели и скриптов транзакции. Использование одного паттерна не исключает использование других паттернов.

Частые ошибки:

- неверная грануляция - слишком мелкие или слишком крупные классы;
- перемешивание бизнес-логики и технических аспектов;
- смешивание источников данных и доменных моделей;
- представление моделей предметной области в виде сервисов.

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

Варианты реализации:

- модели (часто)
- сервисы (крайне редко, так как обычно это неудачное решение)

Идея: Объект, охватывающий логику обработки всех записей хранимой или виртуальной таблицы базы данных. Шаблоны корпоративных приложений. М. Фаулер

Этот шаблон упрощает процесс проектирования за счет введения простого правила "одна таблица - один класс". Такое упрощение сделано из-за постоянных проблем с поиском правильного места для запросов к БД и отображении результатов этих запросов в доменной модели. Шаблон модуль таблицы изначально проектируется как способ установить связь между БД и сущностями приложения.

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

Модуль таблицы может манипулировать данными в том числе через статические методы.

Преимущества:

Недостатки:

Варианты реализации:

Жизненный цикл Table module

Идея: Схема определения границ приложения посредством слоя служб, который устанавливает множество доступных действий и координирует отклик приложения на каждое действие Шаблоны корпоративных приложений. М. Фаулер

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

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

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

Доменная модель не должна ничего знать о сервисах, но сервисы могут знать о доменной модели.

Жизненный цикл Service layer и Transaction script

Жизненный цикл Service layer и Domain logic