А в чём, собственно, проблема?
Для понимания проблемы сначала стоит вспомнить, чем хороши микросервисы и плохи монолитные приложения.
Основные проблемы монолитов:
- Чрезвычайно затруднена и замедлена совместная работа, приходится разрешать много конфликтов в коде;
- Приходится делать релиз целиком всего приложения, даже если изменилась одна запятая на второстепенном экране. Чревато ошибками и проблемами при релизе;
- Сильная связанность затрудняет понимание и разработку внутренность приложения - всё сильно переплетено и расцепить часто вообще невозможно;
- Если что-то одно падает, то падает сразу всё.
Микросервисы решают все эти проблемы:
- Микросервис - совершенно независимое, полностью отдельно работающее приложение. Другие микросервисы никак от него не зависят. Т.е. если один микросервис падает, то другие продолжают работать
- Полностью отдельные, независимые и непересекающиеся релизы в пром. Нет влияния микросервисов друг на друга.
- Объем кода несравнимо меньше кода монолита. В нём легче разбираться и конфликтов гораздо меньше
- Отдельные команды могут развивать микросервисы независимо. Релизы разные, в разное время и с разной частотой.
Часто систему неправильно разделяют (декомпозируют) на микросервисы, что полностью сводит на нет все их преимущества:
- Неправильная декомпозиция приводит к созданию "божественных" супер-классов в каждом из сервисов;
- Код дублируется, пересекается по функциями, не применяется принцип единственной ответственности;
- Не достигается слабая связанность и т.о. сервисы сильно зависят друг от друга и если падают, то падают все вместе
В результате получают тот же монолит, но только разделенный на "микросервисы".
Существуют два взаимодополняющих подхода к декомпозиции на микросервисы:
- По бизнес-умениям / областям
- По доменной модели
Микросервисы на базе бизнес-умений/областей
Это типичный подход, используемый при проектировании архитектуры предприятия, когда всё разбивают, фактически, по бизнес-областям.
Примеры бизнес-областей:
- Управление складом (приходно-расходные операции, хранение)
- Управление поставщиками (расчёты с подрядчиками/поставщиками)
- Управление внутрихозяйственной деятельностью (закупки, договора)
- Управление снабжением (формирование потребности в снабжении, ведение норм и стандартов снабжения, работа с поставщиками, контрактами)
Казалось бы всё нормально, но если посмотреть внимательно, то все сервисы включают в себя работу с одинаковыми типами объектов: договорами, контрактами, заказами, SKU и PLU, подрядчиками, сотрудниками и проч.
В каждой из областей они есть и в каждом сервисе их начинают реализовывать.
В результате такие микросервисы превращаются в "божественные классы", которые умеют делать все и повторяются из сервиса в сервис.
Это плохо и неправильно, потому что сводит на нет все преимущества микросервисов.
Микросервисы на базе доменной модели
Второй подход, не имеющий подобной проблемы - проектировать классы на основе доменной модели.
Упрощенно, например, делаем микросервис "Заказ", и только он выполняет операции с заказами, и больше никто. Все остальные сервисы вызывают микросервис Заказа и не реализуют у себя никаких операций по заказам.
Как это делается:
Разработчики и Бизнес договариваются о Едином Языке и выделяют Термины, которые и будут составлять основу доменной модели.
Термины выделяются из функциональных требований, например, написанных как User Story.
Далее очерчиваются границы поддомена. Это делается для того, чтобы точнее понять какие термины входят в границы поддомена.
Есть пограничные сущности, например, заявка, которая в разных поддоменах играет разные роли и обладает разным набором атрибутов. В этом случае заявку можно было бы включить во все поддомены.
В общем, разделение по поддоменам - это искусство, где нужен знающий человек.
Есть два дополнительных принципа, помогающих разделению на микросервисы:
Принцип единственной ответственности
Операции с поддоменом сосредоточиваются в одном единственном сервисе. Все остальные сервисы не реализуют у себя ничего, что может пересекаться по функциям с сервисом, отвечающим за поддомен.
Например, все операции по Заказу отдаются в микросервис Заказов и больше никуда.
Микросервису еще и выделяется собственная, полностью отделенная от остальных база данных.
Принцип максимальной близости
В микросервис выделяются т.н. Агрегаты - блоки настолько близкие друг-другу, что меняются все вместе.
Рассмотрим пример с машиной. Колесо машины не имеет смысла в отдельности от конкретной машины. Если какая-то запчасть машины сломается, то перестанет ехать вся машина целиком.
Это и есть Агрегат, когда изменения в любой из частей агрегата меняются весь Агрегат в целом.
Еще один пример Агрегата - Кредитная история. При добавлении нового платежа по кредиту или взятия нового кредита пересчитывается вся кредитная история целиком.
Всё, что входит в Агрегат можно смело выделить в отдельный микросервис.
Размер микросервисов
Влияет ли размер (по количеству Терминов в поддомене) на декомпозицию микросервисов?
Ограничений на размеры микросервиса на самом деле нет. Просто чем меньше делаются сервисы, тем больше с ними возни. Игра не стоит свеч - супер мелкая декомпозиция увеличивает связность и трудоемкость.
Поэтому сервисы не желательно делать слишком маленькими.
Алгоритм декомпозции
Что же получаем в итоге?
- Независимо работающие сервисы со слабой связанностью. Если падает один из них, остальные продолжают работать
- Удобство, быстрота и независимость разработки и развёртывания
Подведём итог и сформулируем правильный алгоритм декомпозиции на микросервисы:
- Начать с функциональных требований. Представить их в виде пользовательских историй
- Выделить системные операции
- Выделить общие Термины, домены и поддомены
- Составить таблицу Терминов и системных операций
- Разбить на микросервисы в соответствии с границами поддоменов
- Определить взаимодействие между микросервисами и при необходимости изменить границы поддоменов
- Распределить системные операции между микросервисами
И не забываем, что микросервисы имеют и свои недостатки, которые надо научиться решать, например, отсутствие целостности данных и транзакционности.
Буду рад Вашим вопросам в комментариях.