Каждый более-менее успешный продукт приходит к состоянию, когда добавлять новые возможности в существующую кодовую базу становится тяжело настолько, что стоимость новой функциональности превосходит все возможные выгоды от ее использования. Конечно же, хороший и внимательный архитектор позаботится о приложении заранее и направит разработку в правильное русло. Самый популярный на данный момент подход подразумевает распиливание одного большого куска кода на много мелких проектиков, каждый из которых отвечает за свои определенные возможности. При проектировании такой системы нависает огромная ответственность. Нужно продумать и разработать такой тип взаимодействия между этими отдельно лежащими кусочками, чтобы будущие внесения изменений не требовали переписать все к чертям.
Понятное дело, в сети существует огромное количество экспертных статей, которые показывают нам важность такой архитектуры и рассказывают о том какую архитектуру можно назвать хорошей, а какую не очень. Существует огромное количество методов взаимодействия между отдельными програмками большого приложения со своими протоколами, версионированием протокола и документации, написания документации на программные интерфейсы, способа развертывания и синхронизации всего этого добра вместе. Безусловно, каждая такая статья или метод логичен и последователен и особенно, если описанный метод подтвержден на практике. Но беда не в том, что проектировщики не знают какую систему они хотят в итоге получить. Беда в том, как перейти к такой вот правильной архитектуре и когда же можно прекратить писать монолитное приложение и начать уже писать взрослые микросервисы, чтобы перед пацанами не было стыдно.
Сначала монолит
Во-первых, распространенный подход "сначала монолит" полностью оправдан и видится разумным компромиссом между стоимостью разработки и скоростью разработки. Небольшое монолитное приложение имеет несколько вполне очевидных преимуществ, одно из главных — скорость добавления новой функциональности. В нашем монолитном проекте проще отсмотреть связность кодовой базы и убедится, что новая, только что добавленная, функциональность работает. Несомненно, опытный читатель заметит, что микросервисы позволяют добиться слабой связности разных частей приложения, но не стоит забывать, что в большинстве случаев активно развивающиеся монолитные проекты имеют кодовую базу не самого высшего качества.
От микросервисов не уйти
Второе утверждение состоит в том, что бесконечно огромное приложение с бесконечной функциональностью монолитным быть не может. Рано или поздно появляются части приложения, которые запускаются на разных серверах или хотя бы просто разными процессами.
Главное начать
Третье заключение выводится из первых двух и в нем говорится, что любое монолитное приложение рано или поздно меняет архитектуру на микросервисную. Соответственно, существует момент времени в разработке приложения, когда необходимо менять стратегию разработки и начать вводить микросервисы.
Вышеупомянутые три утверждения ставят перед нами два вопроса: когда и как. Давайте по порядку.
Как понять, что наступил тот самый момент, что пора уже пилить микросервисы?
Давайте подойдем к этому вопросу сугубо практически, и ограничим искомую временную точку сверху и снизу. Однозначно, рано заниматься распилом монолита, если все члены команды все еще ориентируется в любой части приложения. Также признаком своевременности монолитной архитектуры является то, что новичок в команде может легко и непринужденно начать разрабатывать новый функционал сразу после ознакомления.
Выделять микросервисы уже становится поздновато, если возникает желание кешировать html-страницы целиком, потому что тормозят, а чтобы ускорить, нужно переписать половину приложения, заменить ORM или вообще переписать все на другом языке, где все хорошо и приложения не тормозят.
Переходить на архитектуру с микросервисами еще рано, если любой из видов фаулеровских рефакторингов может быть легко применен в монолитном приложении. А вот заменить монолитную архитектуру нужно было бы уже давно, если простого рефакторинга не предвидится, или вообще тяжело такого места найти, которое чисто по-фаулеровски можно было бы отрефакторить.
И самый главный критерий необходимости начать переходить на микросервисную архитектуру — когда стоимость добавления новой фичи начинает превосходить выгоду от этой самой фичи.
С чего начать миграцию архитектуры в пользу микросервисов?
Стратегий смены парадигмы несколько. Самая простая из них и стратегически неправильная — разработать микросервисную архитектуру с нуля, используя монолитное приложение, как пример для подражания. Наверное, распространенность такого подхода и есть главным аргументом приверженцев писать приложения сразу на микросервисах. Но это серьезно добавляет стоимости к изначальной разработке приложения.
Более адекватным подходом перехода от монолита к микросервисам является постепенное отпочковывание микросервисов и написание новой функциональности уже отдельно от основного приложения. Подход хороший и рабочий, но имеет один существенный недостаток — основное монолитное приложение в обозримом будущем не исчезнет. В итоге у нас будет монолит и куча вспомогательных сервисов, вместо набора независимых микросервисов.
В конечном счете, адекватным способом перейти к микросервисной архитектуре можно назвать способ, при котором основное монолитное приложение разбивается на несколько крупнокалиберных приложений с сильной междоусобной связностью. После чего подприложения рассматриваются и рефакторятся отдельно, попутно задевая соседей и заставляя их приспосабливаться и изменяться вместе. Постепенно такой подход приведет к уменьшению связности и появлению устоявшегося интерфейса каждого подприложения. При достижении такой вот устоявшейся временной точки, представляется возможным вносить изменения в подприложения, не затрагивая при этом соседние. И это подприложение рассматривается, как монолит попроще и уровнем ниже. И с ним проделываются аналогичные процедуры. Постепенно приложение бьется на более-менее равные части. Некоторые части в процессе становятся ненужными, некоторые дублируют уже существующие другие части или вообще сливаются в один общий сервис для устранения дублирования. В итоге рано, или скорее поздно, получается устоявшееся приложение на микросервисной архитектуре.
Вместо выводов.
Микросервисы — хорошо. Монолит — хорошо. Хороший код — хорошо. Рабочий код — хорошо. Статья не призывает срочно менять принцип разработки в приложениях, которые тормозят, криво написаны или написаны не так, как хотелось бы. Так же микросервисная архитектура не является панацеей от всех бед разработчиков. В статье описываются точки и способы перехода от монолитной к микросервисной архитектуре.
"Отказоустойчивость", "распределенность", "масштабируемость" это безусловно хорошо, но не это главное преимущество микросервисной архитектуры. Самое важное, что дает такой подход — удешевление стоимости внесения изменений.
Автор: aratak