24.37M
Категория: ПрограммированиеПрограммирование

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

1.

Принципы
организации сервисов.
Типы взаимодействий.
Архитектор ПО
Щетинников Стас

2.

Меня хорошо
слышно && видно?
Напишите в чат, если есть проблемы!
Ставьте + если все хорошо

3.

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

4.

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

5.

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

6.

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

7.

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

8.

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

9.

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

10.

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

11.

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

12.

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

13.

Bounded-context
Как протестировать bounded ли context?
• Если поменять внутреннюю бизнес-логику,
придется ли менять логику в других контекстах?
• Что должно случиться, чтобы контекст перестал
быть актуальным?
• Какова «функция» контекста?
13

14.

Bounded-context
14

15.

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

16.

Нулевая итерация
Поиск товара
поиск товара по выбранным параметрам
поиск по каталогу
каталог параметров поиска
Карточка товара
получить данные в карточке товара для клиента
Формирование корзины
положить в корзину
убрать из корзины
изменить количество товара
Оформление заказа
выбрать место доставки
выбрать способ оплаты
выбрать способ доставки
Оплата заказа
провести оплату удобным для клиента способом
Доставка заказа
зарезервировать товар на складе
зарезервировать курьера для доставки товара
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=Красный самокат
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 }
17

18.

Какие методы еще нужны исходя из сценария?
Формирование корзины
GET /api/v1/cart/products/ - забыли получить все продукты в корзине
Оформление заказа
GET /api/v1/address/ - прокси к геокодеру
GET /api/v1/orders/ - список заказов
Словари
GET /api/v1/delivery_types/ - список типа доставок
GET /api/v1/payment_types/ - список типа платежей
18

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}
19

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/ # Раздел «мои заказы»
20

21.

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

22.

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

23.

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

24.

Как связать сервис заказов и сервис
доставки?
Когда оплата завершилась, нам надо еще
1) послать уведомление на почту
2) зарезеривать товар на складе
3) сделать заявку на доставку в курьерскую службу
24

25.

Как связать сервис заказов и сервис
доставки?
Сервис Заказов явным образом (синхронно) ходит во все остальные
сервисы, когда получает сообщение из очереди, что заказ оплачен.
25

26.

Как связать сервис заказов и сервис
доставки?
Сервис Заказов публикует сообщение, что заказ оплачен, а остальные
сервисы его слушают.
26

27.

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

28.

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

29.

Request-reply протоколы взаимодействия
Request-reply - протоколы, в которых клиент посылает
запрос, сервис обрабатывает и отправляет ответ
Примеры:
HTTP: REST, SOAP, graphQL
gRPC
29

30.

Message-based протоколы взаимодействия
Message-based - протоколы, в которых клиент
отправляет сообщение через брокер сообщений, а
сервис сообщение читает из брокера сообщений
Примеры:
Amqp, stomp, 0mq, NATS и т.д.
30

31.

Request-response vs message based
Request-response:
• Проще дебаг и ловля ошибок
• Latency лучше
Message based
• Дебаг зачастую сложнее
• Latency за счет посредника выше
31

32.

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

33.

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

34.

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

35.

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

36.

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

37.

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

38.

Требования к API
Менять API со сломом обратной совместимости –
очень больно.
• API должен быть расширяем
• API достаточно стабилен
38

39.

Семантическое версионирование API
http://semver.org
MAJOR.MINOR.PATCH
• MAJOR – изменения без обратной совместимости
• MINOR – улучшения API с обратной
совместимостью
• PATCH – багфикс с обратной совместимостью
39

40.

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

41.

REST
• Модель зрелости Richardson
• Протокол Odata (https://www.odata.org/)
плюсы:
• Простой для дебага и реализации
• Максимально использует инфраструктуру HTTP
минусы
• Всего несколько «глаголов»
• Вложенные ресурсы и многословность
41

42.

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

43.

REST vs RPC
В целом сам по себе протокол взаимодействия
(RESTful или RPC) не влияет на расширяемость и
стабильность интерфейса.
43

44.

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": "на самом деле фича"
}
44

45.

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

46.

Datacentric API vs rich API
Если изменение какого-то поля в рамках CRUDметодов API — это не просто изменение данных, а
операция, завязанная на согласованное
изменение состояния сущности, то эту операцию
нужно выносить в отдельный метод и не давать
напрямую менять
46

47.

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 — если есть
статусная модель
47

48.

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 – перевести деньги
И т.д.
48

49.

Datacentric API vs rich API
Проблема касается не только REST-like, но и RPC
итерфейсы
editTicket() или editCampaign() ничем не лучше
49

50.

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

51.

Спасибо
за внимание!
English     Русский Правила