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

Андрей Копылов, наш технический директор, рассказывает, какой подход к проектированию архитектуры приложений использует команда веб-разработчиков AREALIDEA, и,  чем 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;
  • несколько Сервисов;
  • одна Модель.

jnvihwkfvxhwjb1j2jtxsij9eoe.png


Сервис

Сервис — это мини приложение. Оно содержит:

  • один Роутер;
  • несколько Контроллеров;
  • несколько Views;
  • несколько Сервисов;
  • несколько Моделей.

5vzkj2cy_9jwynbdk0xx9zo-9sw.png


Монолит

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

Монолит содержит в себе:


  • один СуперРоутер;
  • несколько обычных Роутеров;
  • много Контроллеров;
  • много Views, много Сервисов;
  • много Моделей.

5bnaq73izwyx7ozycklg-ft2jc8.png

Это начинает выглядеть немного страшно. Здесь явно видно дополнительное вертикальное разделение слоев. Это позволяет оставаться приложению пока еще управляемым и поддерживаемым. Распиливание монолита на части становится чисто механической задачей.

Для сохранения стройности архитектуры нужно:


  1. Добавить один верхнеуровневый роутер, который будет разруливать глобальные пути — СуперРоутер.
  2. Распределить файлы в структуре помодульно. То есть в соответствии с будущим распилом на отдельные сервисы.


Тестирование

В рамках рассматриваемой архитектуры тщательному тестированию подлежат только сервисы — только в них заложена бизнес логика. А мокать нужно только Модели.

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


Заключение

На мой взгляд, KISS Architecture подходит для 80% проектов и обеспечивает плавную эволюцию проекта.

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

© Habrahabr.ru