Боюсь, что этот текст выльется в достаточно большое количество букв. Но пишу сюда я тексты нечасто, так что может кто-нибудь его и осилит. Тем более, что использование микросервисов уже достаточно долго сопровождается вопросом: зачем мы это делаем. Несмотря на обилие вариантов ответов (см., например, отличный обзор Nate Schutta (+Matt Stine) Should that be a Microservice? Keep These Six Factors in Mind), вопрос этот задается снова и снова. У меня есть свой вариант ответа. Если говорить просто заключается он в переносе идей Чистой архитектуры Роберта С. Мартина (дядюшки Боба) из мира [монолитных] приложений в пространство распределенных архитектур. Цитата из его книжки Чистая архитектура. Искусство разработки программного обеспечения:
Архитектура программной системы – это форма, которая придается системе её создателями. Эта форма образуется делением системы на компоненты, их организацией и определением способов взаимодействия между ними. Цель формы – упростить разработку, развертывание и сопровождение программной системы, содержащейся в ней. Главная стратегия такого упрощения в том, чтоб как можно дольше иметь как можно больше вариантов.
Можно по-разному относиться к идеям этой книжки. Я даже не стану утверждать, что они всегда и всему подходят. Но небольшую часть из них, прежде чем вернуться к микросервисам, мне придется повторить.
Итак, поехали!
Идея номер раз: Парадигма программирования – это набор ограничений. Дядя Боб выделяет три парадигмы и сомневается, что когда-либо появится четвертая. Структурное программирование Дейкстры запрещает непосредственную передачу управления по метке, функциональное программирование – переопределение переменных, а вот объектно-ориентированное … – не очень понятно, что оно запрещает. И здесь история номер один. Простыми примерами на языке С Боб Мартин покушается на нашу уверенность в том, что ООП – это инкапсуляция, наследование и полиморфизм. Даже если вы не знаете С, то поймете примеры – как реализовывали инкапсуляцию и наследование до появления С++. Я это даже помню. Сам так делал. Явных примеров полиморфизма непосредственно в С нет, но их легко найти в структуре FILE из stdio.h. Но тогда зачем же появился язык C++, а потом и Java заменив такие простые механизмы инкапсуляции и наследования из C? Дядя Боб говорит, что для того, чтоб предоставить простой способ реализации структуры плагинов посредством инвертирования зависимостей.
Идея номер два: Работа архитектора ПО заключается в том, чтоб произвести функциональную декомпозицию (выделить модули) и определить те из них, что целесообразно сделать заменяемыми, т.е. плагинами. Для этих модулей необходимо придумать более-менее стабильные (а значит абстрактные) интерфейсы от которых будут зависеть и вызывающие и вызываемые модули. Собственно говоря – всё!
Безусловно я пропустил множество отличных историй из этой книжки. О том, как «неудача» Дейкстры в деле доказательства правильности программ подарила нам такую деятельность как тестирование ПО. Историю о линкерах и загрузчиках, повлиявшую на весь ход развития информационных технологий. Знаменитую картинку то ли с луковой, то ли с шестигранной архитектурой. Историю о том, почему выделение акторов и юзкейсов не только задача аналитика и как это влияет на архитектуру приложения. И даже недостающую главу, написанную Саймоном Брауном. Интересно, почитайте, а мы вернемся к микросервисам.
Реализация модуля в виде отдельного сервиса принципиально ничего не меняет. Мы преследуем ту же самую цель – сделать заменяемой реализацию части функций нашего приложения. Точно так же где-то внутри вызывающей микросервис системы должен быть интерфейс, задействованный в ходе исполнения сценария. А вот реализация этих функций уезжает в микросервис. Отличия от реализации подхода дядюшки Боба не столь велики. Во-первых, мы должны подумать о поведении системы при недоступности такого микросервиса. Код нужной нам функции исполняется вне нашего процесса. Он может не запуститься, не завершиться или же запросы или ответы в сети потеряются. Во-вторых, нам незачем использовать RPC. Взаимодействие может быть представлено в виде событий, команд и запросов и быть синхронным (преимущественно для запросов) или же асинхронным. В-третьих, локальные ссылки(указатели) при передаче параметров придется поменять на URL; но передача параметров aka по ссылке или же по значению, вообще говоря, остается. DDD – в помощь. Пожалуй, все. Ничего не забыл.
Но самое интересное в этой конструкции — это вопрос: а где живут интерфейсы. Напиши Боб Мартин свою книжку несколькими годами раньше, ответ был бы однозначным. Отвечая на мой вопрос, мегавендоры и консультанты дружно бы скандировали бы: ESB! ESB! ESB… Как вам такая идея? Виртуализация интерфейсов, все дела! Но в нашем времени ESB уже нет. Можно, конечно, попробовать засунуть их в API Gateway, но мы так делать не будем. В нашем времени точкой притяжения всего нужного и полезного фунционала являются sidecars – контейнеры, развертываемые с основным процессом на одном узле и помогающие ему решать те или иные задачи, например, задачу service discovery, решаемую при помощи service mesh и пр. Если мы заглянем в книжку Брендана Бёрнса Распределенные системы. Паттерны проектирования, ну или в другую похожу книжку, то обнаружим там паттерны Амбасадор и Адаптер. Ничего не напоминает? Контейнер Амбасадор, например, вызывается основной программой(локально), чтоб обратиться к некоторой внешней функции. Где эта функция расположена и как реализована мы не знаем. Амбасадор знает. Адаптер, наоборот – помогает внешней системе собрать с нас данные, например, для мониторинга. Сами мы эти API вызывать не умеем и данные никуда не передаем. А вот адаптер нам с этим поможет.
Это всё. Мы перенесли архитектурные практики монолитных систем на распределенные. Расширили спектр ответов на вопрос зачем из первой ссылки этого текста некоторым архитектурным соображением: чтоб как можно дольше иметь как можно больше вариантов. Уверен, что для ряда читателей эти рассуждения покажутся банальными. Возможно, что для кого-то – полезными. Ну а тех, у кого появятся возражения я прошу обязательно их озвучить в комментариях к этому сообщению
Не хватает брокеров сообщений?
Зачем?