Similar presentations:
Принципы организации сервисов. Типы взаимодействий
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 storminghttps://miro.com/app/board/o9J_kvo2lAo=/
12
13.
Bounded-contextКак протестировать bounded ли context?
• Если поменять внутреннюю бизнес-логику,
придется ли менять логику в других контекстах?
• Что должно случиться, чтобы контекст перестал
быть актуальным?
• Какова «функция» контекста?
13
14.
Bounded-context14
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 basedRequest-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.
Семантическое версионирование APIhttp://semver.org
MAJOR.MINOR.PATCH
• MAJOR – изменения без обратной совместимости
• MINOR – улучшения API с обратной
совместимостью
• PATCH – багфикс с обратной совместимостью
39
40.
REST vs RPCREST
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.
Спасибоза внимание!