KISS Architecture. От микросервиса до монолита

Андрей Копылов, наш технический директор, рассказывает, какой подход к проектированию архитектуры приложений использует команда веб-разработчиков Ареал, и, чем KISS Architecture, его собственная разработка, так хороша.
Существует масса подходов к проектированию архитектуры приложения. MVC, DDD, Clean Architecture и множество других.
MVC хорошо подходит для маленьких приложений. При попытке масштабирования MVC превращается в самую распространенную архитектуру в мире IT — Большой ком грязи.
DDD отличная архитектура, но ее никто не понимает. Разве что сам создатель и пара архитекторов. Цель же архитектуры в том, чтобы она была понятна каждому разработчику.
Clean Architecture отличная архитектура, но ее полная реализация имеет смысл для огромных приложений. Для малых и средних мне она показалась слишком сложной.
Современные тенденции — переход к сервисам и микросервисам — на этом фоне Clean Architecture становится чересчур тяжеловесной.
Казалось бы тогда давайте возьмем MVC для микросервиса и на этом и остановимся. Но нет, такой велосипед нам не подходит.
Составляющие
Велосипед для проектов в нашем агентстве собран из запчастей от разных архитектурных подходов.
Вот компоненты, которые нужны для создания понятной и удобной структуры:
- Routers
- Controllers
- Views
- Services
- Models
Слои
Router
Router отвечает за маршрутизацию запросов. Размер роутера и их количество косвенно говорит о размере вашего приложения. Для большого монолитного приложения может быть более одного слоя роутеров.
Router присутствует в любой архитектуре, но часто в неявном виде. А поскольку явное лучше неявного, то стоит его вытащить наружу — сделать составной частью архитектуры.
Controller
Контроллер является прослойкой между роутером и сервисами. Бизнес логики в контроллере быть не должно.
Каждый контроллер управляет только одной сущностью. Если нужно больше сущностей, то нужно добавить еще один контроллер.
Количество и размер контроллеров косвенно говорит о размере вашего приложения. Вертикальный слой под контроллером можно выделить в отдельный микросервис.
Views
View находится в одном слое с контроллером, отвечает за конечное отображение данных. Контроллер после получения данных из сервиса передает данные во View и возвращает View для отображения.
В предельном случае View представляет собой JSON, XML и подобные форматы.
Services
Только Сервис может содержать бизнес логику. Сервис обычно обращается только к одной модели. Сервис может вызвать другой сервис.
Слой сервисов разделяем на Commands и Queries (команды и запросы). Это стандартный подход для CQRS.
Один сервис выполняет только одну функцию. Приватных функций может быть сколько угодно, а публичная только одна. Название сервиса начинается с глагола. Примеры: GetUsers, GetPostById, UpdateUser, PublishPost. Именно название сервиса намекает на правильное разделение функционала.
В Queries помещаем сервисы, которые не изменяют базу данных. Query содержит одну публичную функцию get. В Commands помещаем сервисы, которые изменяют БД. Command содержит одну публичную функцию execute.
Models
Модель содержит только простейшую логику, связанную с чтением и сохранением данных. Причем эти манипуляции могут быть и не связаны с БД.
Если модель работает с БД, то одна модель обслуживает только одну или несколько таблиц.
Рецепты
Микросервис
Микросервис в моем понимании должен управлять только одной сущностью. Поэтому архитектура для простейшего микросервиса будет выглядеть таким образом:
- один Роутер;
- один Контроллер;
- несколько Views;
- несколько Сервисов;
- одна Модель.

Сервис
Сервис — это мини приложение. Оно содержит:
- один Роутер;
- несколько Контроллеров;
- несколько Views;
- несколько Сервисов;
- несколько Моделей.

Монолит
Монолит — это большое приложение. Монолиты никто не любит по причине их монструозности. Монолит оправдан, если следовать подходу Monolith first. В таком состоянии ваше приложение может пребывать довольно долго.
Монолит содержит в себе:
- один СуперРоутер;
- несколько обычных Роутеров;
- много Контроллеров;
- много Views, много Сервисов;
- много Моделей.

Это начинает выглядеть немного страшно. Здесь явно видно дополнительное вертикальное разделение слоев. Это позволяет оставаться приложению пока еще управляемым и поддерживаемым. Распиливание монолита на части становится чисто механической задачей.
Для сохранения стройности архитектуры нужно:
- Добавить один верхнеуровневый роутер, который будет разруливать глобальные пути — СуперРоутер.
- Распределить файлы в структуре помодульно. То есть в соответствии с будущим распилом на отдельные сервисы.
Тестирование
В рамках рассматриваемой архитектуры тщательному тестированию подлежат только сервисы — только в них заложена бизнес логика. А мокать нужно только Модели.
Если у вас возникает желание протестировать, что-то кроме сервисов, то вероятно место для логики выбрано неправильно.
Заключение
На мой взгляд, KISS Architecture подходит для 80% проектов и обеспечивает плавную эволюцию проекта.
Этот архитектурный подход будет понятен всем разработчикам и для его применения на практике не нужно читать толстенные книги про DDD.