В данной главе вы научились в какой-то мере определять критерии хорошего сервиса, а также узнали о способах поиска стыков в своем проблемном пространстве, что дает нам двойные преимущества — как слабой связанности, так и сильного зацепления. Жизненно важным инструментом, помогающим нам находить такие стыки, являются ограниченные контексты, а вписывание микросервисов в определяемые ими границы позволяет гарантировать, что получающаяся в результате система имеет все шансы сохранить свои достоинства неизменными. Кроме того, была дана подсказка о том, как можно выполнить дальнейшее дробление на микросервисы, а углубленное рассмотрение этого вопроса будет приведено чуть позже. Кроме того, состоялось представление MusicCorp, области, взятой в качестве примера, которая будет использоваться в книге и в дальнейшем.
Идеи, представленные Эриком Эвансом в книге Domain-Driven Design, весьма полезны при поиске разумных границ наших сервисов, и мы пока что рассмотрели их весьма поверхностно. Чтобы разобраться в практических аспектах данного подхода, я рекомендую обратиться к книге Вона Вернона (Vaughn Vernon) Implementing Domain-Driven Design (Addison-Wesley).
В данной главе мы прошлись в основном по верхнему уровню, а далее необходимо углубиться в технические подробности. При реализации интерфейсов между сервисами нас подстерегает множество подвохов, вызывающих разнообразные проблемы, и если мы стремимся уберечь свои системы от сплошной путаницы, в эту тему придется углубиться.
4. Интеграция
На мой взгляд, правильная интеграция является наиболее важным аспектом технологии, связанной с микросервисами. При должном выполнении ваши микросервисы сохранят свою автономию, в то же время можно будет вносить в них изменения и выпускать их новые версии независимо от всей остальной системы. При ненадлежащем исполнении вас ждут серьезные неприятности. К счастью, прочитав эту главу, вы научитесь обходить самые большие из возможных просчетов, от которых страдают другие попытки применения сервис-ориентированной архитектуры и которые могут все еще поджидать вас на пути перехода к применению микросервисов.
Для определения способа общения одного микросервиса с другим имеется широкое поле выбора. Но какой из вариантов будет правильным: SOAP, XML-RPC, REST, Protocol Buffers? Прежде чем углубиться в решение этой задачи, подумаем о том, что нам нужно получить от той технологии, на которую падет выбор.
Время от времени мы можем вносить изменения, требующие изменений и от наших потребителей. Как с этим справиться, мы рассмотрим чуть позже, но хотелось бы подобрать такую технологию, которая бы гарантировала, что подобная ситуация станет возникать как можно реже. Например, если микросервис добавляет новые поля к той части данных, которые он куда-нибудь отправляет, это не должно касаться уже имеющихся потребителей.
Если ваш стаж пребывания в IT-индустрии превышает 15 минут, то мне не нужно говорить вам о том, что мы работаем в быстро меняющемся пространстве. Что-то обязательно изменится. Все время появляются новые инструменты, среды программирования и языки, реализуются новые идеи, которые могут помочь нам работать быстрее и эффективнее. Сегодня вы можете пользоваться всем многообразием. NET-технологии. А что будет через год или через пять лет? Что, если вам захочется поэкспериментировать с набором альтернативной технологии, который может увеличить вашу продуктивность?
Я ярый сторонник свободы выбора и именно поэтому являюсь горячим приверженцем микросервисов. Это также является причиной того, что я считаю очень важным сохранение технологической независимости API, используемых для обмена данными между микросервисами. Это означает, что нужно избегать применения тех интеграционных технологий, которые диктуют, какие технологические наборы следует применять при реализации микросервисов.
Хотелось бы сделать сервис для потребителей как можно более простым в использовании. Красиво представленный микросервис не может рассчитывать на что-то существенное, если цена его применения заоблачно высока! Поэтому задумаемся над средствами, упрощающими использование потребителями нашего замечательного нового сервиса. В идеале хотелось бы дать клиентам полную свободу технологического выбора, но в то же время предоставление клиентской библиотеки может упростить внедрение сервиса. И все же зачастую такие библиотеки несовместимы с другими вещами, которые хотелось бы реализовать. Например, клиентские библиотеки можно использовать в качестве послаблений для потребителей, но это может происходить и за счет повышения связанности.
Нам не хотелось бы, чтобы наши потребители были привязаны к внутренней реализации сервисов. Это приводит к повышению связанности. Из этого также следует, что при возникновении необходимости внести какие-либо изменения в микросервис мы можем расстроить потребителей, потребовав от них ответных изменений. Это повышает цену изменения, то есть происходит именно то, чего мы стремимся избежать. Это означает также, что нам, скорее всего, не захочется вносить изменения из-за опасений заставить своих потребителей что-либо обновлять, что может повлечь за собой увеличение объема технических обязательств внутри сервиса. Следовательно, нужно избегать любых технологий, вынуждающих нас выставлять напоказ внутренние представления деталей сервисов.
После получения наставлений, которые могут помочь в выборе подходящей технологии, используемой для интеграции сервисов, рассмотрим некоторые из наиболее востребованных вариантов и попробуем определить, какой из них нам больше всего подходит. Чтобы проще было все обдумать, возьмем реальный пример из MusicCorp.
На первый взгляд создание клиентов можно рассматривать в виде простого набора CRUD-операций, но для большинства систем все далеко не так просто. Внесение в список нового клиента может потребовать инициирования дополнительных процессов, таких как создание финансовых платежей или отправка приветственных сообщений по электронной почте. А при изменении данных клиента или их удалении могут запускаться и другие бизнес-процессы.
Итак, помня об этом, мы должны рассмотреть ряд других способов работы с клиентами в системе MusicCorp.
До сих пор самой распространенной в промышленности формой интеграции, известной мне или любому из моих коллег, является интеграция с использованием базы данных (DB). Если в этой среде другим сервисам нужно получить информацию от какого-нибудь другого сервиса, они обращаются к базе данных. И если им нужно внести в нее изменения, они также обращаются к базе данных! Действительно, на первый взгляд все просто, и для начала это, пожалуй, наиболее быстрый вид интеграции, чем, вероятно, и объясняется его популярность.
На рис. 4.1 показан пользовательский интерфейс регистрации, с помощью которого создаются клиенты путем выполнения SQL-операций непосредственно над базой данных. Там также показано приложение центра обработки заказов, из которого осуществляется просмотр или редактирование клиентских данных путем запуска SQL-запросов в адрес базы данных. А с товарного склада также путем запросов в адрес базы данных производится обновление информации о клиентских заказах. Это довольно широко распространенная схема, но и тут без трудностей не обходится.
Рис. 4.1. Использование DB-интеграции для доступа к клиентской информации и внесения в нее изменений
Во-первых, разрешены просмотр подробностей внутренней реализации и привязка к ним извне. Структуры данных, хранящихся в базе, становятся законной добычей для любого, они во всей своей полноте используются всеми, кто имеет доступ к базе данных. Если мною будет принято решение изменить свою схему для более подходящего представления своих данных или упростить систему, я могу нарушить работу потребителей. Фактически база данных представляет собой слишком большой совместно используемый API, который к тому же весьма хрупок. Если мне потребуется внести изменения в логику, связанную, скажем, с управлением сервисом поддержки клиентов, и для этого нужно будет вносить изменения в базу данных, мне потребуется предельное внимание, чтобы не нарушить те части схемы, которые используются другими сервисами. Обычно в такой ситуации требуется большой объем регрессионного тестирования.
Во-вторых, мои потребители привязаны к конкретному технологическому выбору. Возможно, именно сейчас имеет смысл хранить сведения о клиентах в реляционной базе данных, и поэтому потребители для обращения с этими данными используют соответствующую (потенциально характерную для баз данных) управляющую программу. А что, если со временем станет понятно, что данные лучше хранить в нереляционной базе данных? Могу ли я принять такое решение? Следовательно, потребители тесно связаны с реализацией сервиса по обслуживанию клиентов. Как упоминалось ранее, мы действительно хотим обеспечить скрытие реализации деталей от потребителей, допуская приобретение нашим сервисом определенного уровня автономности в том, как со временем изменяется его внутреннее содержание. Придется распрощаться со слабой связанностью.
И наконец, на минутку задумаемся о поведении. Должна быть какая-то логика, связанная с тем, как вносятся изменения в данные о клиенте. Где же эта логика? Если потребители напрямую работают с базой данных, значит, связанной с этим логикой должны владеть именно они. Логика для выполнения подобных действий с данными клиентов может не распространяться среди нескольких потребителей. Если в редактировании информации о клиенте нуждаются сразу пользовательские интерфейсы товарного склада, системы регистрации и центра обработки заказов, устранять недочет или изменять поведение нужно в трех разн