Принципы организации сервисов. Типы взаимодействий

Содержание

Слайд 2

Меня хорошо слышно && видно?

Меня хорошо слышно && видно?

Слайд 3

Карта вебинара Кейс Response-reply и message-based протоколы Синхронное и асинхронное взаимодействие

Карта вебинара

Кейс
Response-reply и message-based протоколы
Синхронное и асинхронное взаимодействие
Оркестрация и хореография
Anemic и

rich model
Слайд 4

Пользовательский сценарий Есть авторизованный клиент И есть интернет-магазин "Гозон" И клиент

Пользовательский сценарий

Есть авторизованный клиент
И есть интернет-магазин "Гозон"
И клиент вводит в строке

поиска "Красный самокат"
Тогда появляется список товаров, подходящих под запрос клиента
И в карточке товара пользователь видит
1) название
2) цену
3) изображение
4) скидку
5) доступность в разных магазинах
Слайд 5

Пользовательский сценарий Когда клиент нажимает карточку на товар Тогда клиент переходит на страничку с описанием товара

Пользовательский сценарий

Когда клиент нажимает карточку на товар
Тогда клиент переходит на страничку

с описанием товара
Слайд 6

Пользовательский сценарий Когда клиент нажимает на кнопку "Добавить товар в корзину" Тогда товар добавляется в корзину

Пользовательский сценарий

Когда клиент нажимает на кнопку "Добавить товар в корзину"
Тогда

товар добавляется в корзину
Слайд 7

Пользовательский сценарий Когда клиент переходит в корзину Тогда он видит список всех добавленных в корзину товаров

Пользовательский сценарий

Когда клиент переходит в корзину
Тогда он видит список всех

добавленных в корзину товаров
Слайд 8

Пользовательский сценарий Когда клиент нажимает на кнопку "оформить заказ" Тогда появляется

Пользовательский сценарий

Когда клиент нажимает на кнопку "оформить заказ"
Тогда появляется форма оформления

заказа, которая предлагает заполнить место и время доставки, и перейти к оплате
Слайд 9

Пользовательский сценарий Когда клиент выбирает место доставки, способ оплаты, и переходит

Пользовательский сценарий

Когда клиент выбирает место доставки, способ оплаты, и переходит к

оплате
Тогда возникает форма оплаты
Слайд 10

Пользовательский сценарий Когда клиент оплачивает заказ Тогда появляется окно "заказ оплачен"

Пользовательский сценарий

Когда клиент оплачивает заказ
Тогда появляется окно "заказ оплачен"
И клиенту

приходит сообщение на почту с деталями доставки
И заказ резервируется на складе
И службе доставки поступает заявка на доставку заказа
Слайд 11

Event storming Отражаем на доске бизнес процесс в виде набора стикеров

Event storming

Отражаем на доске бизнес процесс в виде набора стикеров

Слайд 12

Event storming https://miro.com/app/board/o9J_kvo2lAo=/

Event storming

https://miro.com/app/board/o9J_kvo2lAo=/

Слайд 13

Bounded-context Как протестировать bounded ли context? Если поменять внутреннюю бизнес-логику, придется

Bounded-context

Как протестировать bounded ли context?
Если поменять внутреннюю бизнес-логику, придется ли менять

логику в других контекстах?
Что должно случиться, чтобы контекст перестал быть актуальным?
Какова «функция» контекста?
Слайд 14

Bounded-context

Bounded-context

Слайд 15

Нулевая итерация bounded-context = сервис прописываем функции предметной области внутри контекста превращаем команды/действия в API методы

Нулевая итерация

bounded-context = сервис
прописываем функции предметной области внутри контекста
превращаем команды/действия в

API методы
Слайд 16

Нулевая итерация Поиск товара поиск товара по выбранным параметрам поиск по

Нулевая итерация

Поиск товара
поиск товара по выбранным параметрам
поиск по каталогу
каталог параметров поиска
Карточка

товара
получить данные в карточке товара для клиента
Формирование корзины
положить в корзину
убрать из корзины
изменить количество товара
Оформление заказа
выбрать место доставки
выбрать способ оплаты
выбрать способ доставки
Оплата заказа
провести оплату удобным для клиента способом
Доставка заказа
зарезервировать товар на складе
зарезервировать курьера для доставки товара
Слайд 17

API first design Поиск товара GET /api/v1/search/product_search/?q=Красный самокат&limit=20 GET /api/v1/search/product_catalog/?category_id=23&subcategory_id=43&q=Красный самокат

API first design

Поиск товара
GET /api/v1/search/product_search/?q=Красный самокат&limit=20
GET /api/v1/search/product_catalog/?category_id=23&subcategory_id=43&q=Красный самокат
GET /api/v1/search/catalog_filters/?category_id=42
Карточка товара
GET /api/v1/products/{id}/
Формирование

корзины
POST /api/v1/cart/products/ {id, quantity: 1}
DELETE /api/v1/cart/products/{id}/
PUT /api/v1/cart/products/{id}/ {quantity: 2}
Оформление заказа
POST /api/v1/order/address/ { geo_id }
POST /api/v1/order/payment_type/ { payment_type_id }
POST /api/v1/order/delivery_type/ { delivery_type_id }
Оплата заказа
POST /api/v1/order/pay/ - редирект на сервис оплаты
Доставка заказа
POST /api/v1/warehouse/reserve_order/ { order_id }
POST /api/v1/notify_order_is_created/ { order_id }
POST /api/v1/delivery/reserve_order/ { order_id }
Слайд 18

Какие методы еще нужны исходя из сценария? Формирование корзины GET /api/v1/cart/products/

Какие методы еще нужны исходя из сценария?

Формирование корзины
GET /api/v1/cart/products/ - забыли

получить все продукты в корзине
Оформление заказа
GET /api/v1/address/ - прокси к геокодеру
GET /api/v1/orders/ - список заказов
Словари
GET /api/v1/delivery_types/ - список типа доставок
GET /api/v1/payment_types/ - список типа платежей
Слайд 19

Какие методы еще нужны исходя из сценария? Какие данные о продукте

Какие методы еще нужны исходя из сценария?

Какие данные о продукте возвращают

методы?
GET /api/v1/search/product_search/?q=Красный самокат&limit=20
GET /api/v1/products/{id}/
GET /api/v1/cart/products/
Если все расширенные данные во всех API, то, если мы захотим сделать добавить свойство "промокод" и должны будем его показывать в карточке на поиске, и в полной карточке, и еще в корзине, то надо будет менять все API. Т.е. они будут все связаны между собой.
Пусть все эти методы возвращают вместо всех данных о продукте только id.
Но тогда нужно будет уметь возвращать данные о нескольких продуктах в одном запросе, чтобы на фронте было эффективно все.
Пусть появится еще метод
GET /api/v1/products/?filter_ids={ids}
Слайд 20

Корзина – это тоже самое, что и заказ? Формирование корзины и

Корзина – это тоже самое, что и заказ?

Формирование корзины и оформление

заказа кажется, что про одно и то же.
Сущность одна. Kорзина - это просто незаконченный заказ, в котором не выбрали тип платежей и доставку. Имеет смысл схлопнуть два сервиса «Формирование корзины» и «Оформление заказа» в один.
Управление заказом
GET /api/v1/order/
GET /api/v1/order/products/ # нужен ли теперь этот метод?
POST /api/v1/order/products/ {id: , quantity: 1}
DELETE /api/v1/order/products/{id}/
PUT /api/v1/order/products/{id}/ {quantity: 2}
POST /api/v1/order/address/ { geo_id: }
POST /api/v1/order/payment_type/ { payment_type_id }
POST /api/v1/order/delivery_type/ { delivery_type_id }
GET /api/v1/orders/ # Раздел «мои заказы»
Слайд 21

Нужен ли отдельный сервис оплаты? Что будет, если из сервиса Заказов

Нужен ли отдельный сервис оплаты?

Что будет, если из сервиса Заказов сразу

ходить во внешний сервис?
Сервис Заказов будет «знать» про внутренности внешнего сервиса оплаты.
Если понадобится оплата вне сервиса заказов (например, если надо будет пополнять счет в личном кабинете), то мы не сможем переиспользовать код.
Слайд 22

Как связать сервис оплаты и сервис заказов? Что будет, если мы

Как связать сервис оплаты и сервис заказов?

Что будет, если мы сделаем

прослойку в виде Сервиса оплаты?
Создать счет и получить ссылку на оплату можно по API
POST /api/v1/invoices/ { payment_type_id amount {order_id, redirect_url}}
Без ссылки на оплату флоу работы клиента заблокирован.
Как можно уведомить сервис Заказов, что оплата прошла?
POST /srv/api/v1/orders/{order_id}/invoice_payed/
В этом случае «Сервис оплаты» явно знает про «Сервис заказов» и получаем похожую проблему.
Слайд 23

Как связать сервис оплаты и сервис заказов? Что будет, если мы

Как связать сервис оплаты и сервис заказов?

Что будет, если мы сделаем

очередь событий «Произошла оплата»?
Сервис оплаты теперь не будет знать явно про Сервис заказов.
Но в этом случае увеличится latency, насколько будет комфортно пользователю, что сообщение об оплате может появится не сразу?
Кажется, что ок.
Слайд 24

Как связать сервис заказов и сервис доставки? Когда оплата завершилась, нам

Как связать сервис заказов и сервис доставки?

Когда оплата завершилась, нам надо

еще
1) послать уведомление на почту
2) зарезеривать товар на складе
3) сделать заявку на доставку в курьерскую службу
Слайд 25

Как связать сервис заказов и сервис доставки? Сервис Заказов явным образом

Как связать сервис заказов и сервис доставки?

Сервис Заказов явным образом (синхронно)

ходит во все остальные сервисы, когда получает сообщение из очереди, что заказ оплачен.
Слайд 26

Как связать сервис заказов и сервис доставки? Сервис Заказов публикует сообщение,

Как связать сервис заказов и сервис доставки?

Сервис Заказов публикует сообщение, что

заказ оплачен, а остальные сервисы его слушают.
Слайд 27

Промежуточный итог

Промежуточный итог

Слайд 28

Рекомендации 1. Начинайте с основного пользовательского сценария 2. Пробуйте использовать технику

Рекомендации

1. Начинайте с основного пользовательского сценария
2. Пробуйте использовать технику event storming
3.

Используйте декомпозицию по предметной области для первого приближения
4. Сначала проектируйте API
5. Каждый метод API связывайте с "функцией" в предметной области
6. Ищите связанные API методы и развязывайте их
7. Пробуйте разные границы у сервисов
8. Выбирайте подходящий тип межсервисных взаимодействий
9. Повторяйте
Слайд 29

Request-reply протоколы взаимодействия Request-reply - протоколы, в которых клиент посылает запрос,

Request-reply протоколы взаимодействия

Request-reply - протоколы, в которых клиент посылает запрос, сервис

обрабатывает и отправляет ответ
Примеры:
HTTP: REST, SOAP, graphQL
gRPC
Слайд 30

Message-based протоколы взаимодействия Message-based - протоколы, в которых клиент отправляет сообщение

Message-based протоколы взаимодействия

Message-based - протоколы, в которых клиент отправляет сообщение через

брокер сообщений, а сервис сообщение читает из брокера сообщений
Примеры:
Amqp, stomp, 0mq, NATS и т.д.
Слайд 31

Request-response vs message based Request-response: Проще дебаг и ловля ошибок Latency

Request-response vs message based

Request-response:
Проще дебаг и ловля ошибок
Latency лучше
Message based
Дебаг зачастую

сложнее
Latency за счет посредника выше
Слайд 32

Синхронное и асинхронное взаимодействие Синхронное взаимодействие – клиент ждет ответа от

Синхронное и асинхронное взаимодействие

Синхронное взаимодействие – клиент ждет ответа от сервиса
Асинхронное

взаимодействие – клиент не ждет ответа от сервиса и не блокирует свой поток выполнения
Синхронное и асинхронное взаимодействие ортогональны протоколам.
Синхронное взаимодействие возможно и с помощью message-based протоколов (amqp RPC)
Асинхронное взаимодействие возможно с помощью request-reply протоколов (long polling, websocket, webhooks)
Слайд 33

Синхронное и асинхронное взаимодействие

Синхронное и асинхронное взаимодействие

Слайд 34

Оркестрация и хореография

Оркестрация и хореография

Слайд 35

Оркестрация Оркестрация – один сервис координирует весь бизнес-процесс

Оркестрация

Оркестрация – один сервис координирует весь бизнес-процесс

Слайд 36

Хореография Хореография – сервисы координируются между собой за счет асинхронного взаимодействия и событийной модели

Хореография

Хореография – сервисы координируются между собой за счет асинхронного взаимодействия и

событийной модели
Слайд 37

Оркестрация vs хореография Оркестрация дает четкое понимание, что происходит и как

Оркестрация vs хореография

Оркестрация дает четкое понимание, что происходит и как выглядит

бизнес процесс
Оркестрация может излишне «связать» сервисы друг с другом
Хореография не всегда дает четкое понимание, что и когда происходит.
Хореография «развязывает» сервисы и им нет необходимости знать друг про друга
Слайд 38

Требования к API Менять API со сломом обратной совместимости – очень

Требования к API

Менять API со сломом обратной совместимости – очень больно.


API должен быть расширяем
API достаточно стабилен
Слайд 39

Семантическое версионирование API http://semver.org MAJOR.MINOR.PATCH MAJOR – изменения без обратной совместимости

Семантическое версионирование API

http://semver.org
MAJOR.MINOR.PATCH
MAJOR – изменения без обратной совместимости
MINOR – улучшения

API с обратной совместимостью
PATCH – багфикс с обратной совместимостью
Слайд 40

REST vs RPC REST API – это набор ресурсов, которые представляют

REST vs RPC

REST
API – это набор ресурсов, которые представляют сущности предметной

области и HTTP глаголов для манипулирования ими
RPC
API – это набор функций, которые выполняются удаленно.
Слайд 41

REST Модель зрелости Richardson Протокол Odata (https://www.odata.org/) плюсы: Простой для дебага

REST

Модель зрелости Richardson
Протокол Odata (https://www.odata.org/)
плюсы:
Простой для дебага и реализации
Максимально использует

инфраструктуру HTTP
минусы
Всего несколько «глаголов»
Вложенные ресурсы и многословность
Слайд 42

RPC SOAP, gRPC плюсы: Хорошо подходят для сложной бизнес-логики Богатый язык

RPC

SOAP, gRPC
плюсы:
Хорошо подходят для сложной бизнес-логики
Богатый язык описания контрактов
минусы
Поддержка языком программирования

Слайд 43

REST vs RPC В целом сам по себе протокол взаимодействия (RESTful

REST vs RPC

В целом сам по себе протокол взаимодействия (RESTful или

RPC) не влияет на расширяемость и стабильность интерфейса.
Слайд 44

Datacentric API vs rich API Есть сервис обработки тикетов и в

Datacentric API vs rich API

Есть сервис обработки тикетов и в нем

есть ресурс - /api/v1/tickets/{ticket_id}.json
GET /api/v1/tickets/42.json
{
“id”: 42,
“status”: “IN_PROGRESS”,
“description”: “Lorem ipsum”,
“type”: “feature”

}
Что будет если пропатчить?
PATCH /api/v1/tickets/42.json
{
"type": "bug",
"status": "closed",
"description": "на самом деле фича"
}
Слайд 45

Datacentric API vs rich API Есть сервис обработки тикетов и в

Datacentric API vs rich API

Есть сервис обработки тикетов и в нем

есть ресурс - /api/v1/tickets/{ticket_id}.json
Что будет, если изменить тикет?
PATCH /api/v1/tickets/42.json
{
"type": "bug",
"status": "closed",
"description": "на самом деле фича"
}
Что произойдет если статусная модель зависит от типа бага?
Слайд 46

Datacentric API vs rich API Если изменение какого-то поля в рамках

Datacentric API vs rich API

Если изменение какого-то поля в рамках CRUD-методов

API — это не просто изменение данных, а операция, завязанная на согласованное изменение состояния сущности, то эту операцию нужно выносить в отдельный метод и не давать напрямую менять
Слайд 47

Datacentric API vs rich API Вместо универсального ресурса /api/v1/tickets.json добавить еще

Datacentric API vs rich API

Вместо универсального
ресурса /api/v1/tickets.json добавить еще ресурсы-глаголы: POST /api/v1/tickets/{ticket_id}/migrate.json — смигрировать из

одного типа в другой
{POST /api/v1/tickets/{ticket_id}/status.json — если есть статусная модель
Слайд 48

Datacentric API vs rich API Вместо универсального ресурса /api/v1/tickets.json добавить еще

Datacentric API vs rich API

Вместо универсального
ресурса /api/v1/tickets.json добавить еще ресурсы сущности: POST /api/v1/tickets/migrations.json
POST /api/v1/subscriptions/trial.json

- создать триальную подписку
POST /api/v1/money_transfers.json – перевести деньги
И т.д.
Слайд 49

Datacentric API vs rich API Проблема касается не только REST-like, но

Datacentric API vs rich API

Проблема касается не только REST-like, но и

RPC итерфейсы
editTicket() или editCampaign() ничем не лучше
Слайд 50

Опрос https://otus.ru/polls/6404/

Опрос

https://otus.ru/polls/6404/