По работе мне довелось провести ряд собеседований на позицию Backend-разработчика. Хорошим для оценки архитектурных навыков мне кажется следующий вопрос:


Если вам необходимо спроектировать взаимодействие двух систем, в каких случаях вы выберете RPC, в каких REST, а в каких MQ?


Если ответ на этот вопрос у вас вызывает затруднения, загляните в мой небольшой ЛикБез на тему.




Для начала, нужно определиться концептуально, какие вообще бывают взаимодействия (в самом общем виде).


Во-первых, вызовы могут быть синхронные и асинхронные. Сам по себе вопрос об этом выборе интересен. И я думаю, что очень многие всегда будут отдавать предпочтение асинхронному async/await без конкретной причины — тоже хороший вопрос для интервью.


Во-вторых, модель взаимодействий может быть однонаправленная (one-way) и вызовы вида запрос-ответ. Если вы исповедуете CQS, соблюдаете требование идемпотентности, то скорее всего вызовы будут однонаправленными.


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


Выбор


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


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


Сценарий транзакции


Организует бизнес-логику в процедуры, которые управляют каждая своим запросом.
TS


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


Исходя из определения, данного Мартином Фаулером, вызывать необходимо определённый сценарий и в определённой последовательности. RPC подход появился именно отсюда. Т.е. подойдут такие протоколы как: Sockets, WebSockets, gRPC, SOAP и другие.


Обработчик таблицы


Одна сущность обрабатывает всю бизнес-логику для всех строк таблицы БД или представления.
TM


Для данной формы организации доменной логики характерна работа над отдельными таблицами, с помощью репозиториев, реализующих CRUD-операции. Сервис строится с использованием API-Controller — адаптера к репозиторию реализующий удалённый вызов CRUD-процедур с использование протокола HTTP. Таким образом, если ваше приложение базируется на БД с отдельными репозиториями, вам наиболее подходит REST протокол. В ряде случаев, особенно полезным становится использование протокола OData, расширяющего REST.


Модель предметной области


Объектная модель домена, объединяющая данные и поведение.
DDD


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


Агрегат


Шаблон доменной модели, как можно видеть, очень похож на сценарий транзакции, но (1) имеет очерченные границы (Bounded Context), и (2) связан с доменной сущностью (агрегатом). Структура данных при этом сокрыта за абстракцией и может быть реляционном виде, а ещё проще когда в нереляционном.


Если сервис делается по принципам предметно-ориентированного проектирования, то есть несколько сложностей. В работе со своей командой, я столкнулся с тем, что для соблюдения инвариантов сущности, получения больших возможностей масштабирования, эффективнее всего будет создавать версии агрегата. При этом, если вы корректно оперируете агрегатом через его методы, классический REST уже не подходит. В частности, для работы с версиями модели, необходимо соблюдать требование идемпотентности — одна бизнес-операция может изменить соответственно только последнюю версию агрегата. Корректно в данном случае использовать только глагол POST, с разными dto разных операций, или конкретным указанием через маршрутизацию контроллера. Согласитесь — это не REST.


Совершенно по-новому в этом отношении смотрится gRPC — замена Windows Comunication Foundation. С последним очень часто бывают существенные проблемы соразвития, особенно если интеграция происходит с командой, интеграция с которой оставляет желать лучшего (т.е. худшие варианты карты контекстов тут не подходят). В рамках же смыслового ядра считаю технологию оправданной. А сам RPC подход был бы наиболее верным.


Отдельные возможности открываются для брокеров сообщений как средство получения ответа от сервиса, ведь доменная модель идеально подходит для получения очень чистых событий предметной области, потребителями которых могут быть любые другие сервисы, а сама ШИНА ДОМЕННЫХ СОБЫТИЙ может стать превосходным средством масштабирования. Организуя архитектуру определяемую событиями, важно не забывать про возможность циклического вызова, про маркеры корреляции.




Вполне ясно что можно скрестить ужа с ежом, добавить много особых кейсов. Но в самых типовых случаях, правильно обратиться к классификации бизнес-логики Фаулера, а потом уже к технологиям и протоколам. И всё же, если считаете что есть кейс который нужно сюда внести, напишите об этом в комментарии. Думайте про архитектуру!


Просто подумайте




Что почитать