Сначала — монолит, или правильный путь к микросервисной архитектуре

Во всех историях о проектах, основанных на микросервисной архитектуре, я заметил общий шаблон:

  1. Почти все успешные микросервисные проекты начинали с монолита, который стал слишком большим и в конце концов был разделён.
  2. Почти во всех случаях, когда проект с самого начала разрабатывался на микросервисах, возникали серьёзные проблемы.

Это наблюдение привело многих моих коллег к следующему утверждению: «не следует начинать новый проект с микросервисов, даже при полной уверенности, что будущее приложение будет достаточно большим, чтобы оправдать такой подход».

Monolith

Микросервисы — полезная архитектура, но даже сторонники говорят, что их использование значительно увеличивает стоимость и риски, другими словами, разработка микросервисов имеет смысл только в более сложных системах. Эти накладные расходы (в основном на обслуживание группы сервисов) будут тормозить команду. Из этого следует мощный аргумент в пользу стратегии «сначала — монолит», в которой вам сначала надо построить ваше приложение в виде монолита, даже если вы думаете, что в будущем, вероятно, можно будет получить выгоду от микросервисов.

Первая причина следовать принципу  «сначала — монолит» — классический принцип Yagni («Вам это не понадобится»). Когда вы начинаете разрабатывать новое приложение, насколько вы уверены, что оно будет  полезным для пользователей? Возможно, будет сложно масштабировать плохо спроектированную, но успешную программную систему, но это лучше, чем иметь хорошо спроектированную и непопулярную. Мы сейчас признаём, что лучший способ проверить, будет ли приложение пользоваться спросом — это создание его упрощённой версии. Вначале на первом месте стоит скорость разработки (а значит, и скорость получения обратной связи от потенциальных пользователей), и разработка микросервисов — это бремя, которое не следует на себя взваливать.

Следующая проблема состоит в том, что микросервисы работают хорошо, если вы достигли чётких, стабильных границ между отдельными сервисами — для этого нужно получить правильный набор ограниченных контекстов. Любой рефакторинг функциональности между сервисами сложнее аналогичного в монолите. Но даже опытные архитекторы, работая в знакомых областях, испытывают затруднения при определении правильных границ с самого начала. Построив монолитное приложение, вы сможете определить верные границы, прежде чем микросервисы встанут над ними плотным туманом. Это также даст вам время подготовить всё необходимое для создания сервисов с более чёткими границами.

Я слышал о различных путях реализации стратегии «сначала — монолит». Логичный путь — проектировать монолит со всей осторожностью, обращая внимание на модульность в программном обеспечении, границы API и способ хранения данных. Если сделать это хорошо, то переход к микросервисам будет относительно простым. Однако я был бы более уверен в данном подходе, если бы знал достаточное количество проектов, где он сработал.

Более общий подход — начать с монолита и постепенно отделять от него микросервисы. В этом случае значительная часть первоначального монолита может остаться в качестве центральной в микросервисной архитектуре, но основная часть новой разработки будет происходить в сервисах, оставляя монолит без больших изменений.

Также распространён подход с полной заменой монолита. Немногие рассматривают это как повод для гордости, но всё-таки существуют преимущества разработки монолита «на выброс». Не стоит бояться разработать монолит, от которого потом придётся отказаться, особенно если он поможет скорейшему выводу продукта на рынок.

Ещё один путь, с которым мне приходилось сталкиваться — начать с пары неотёсанных сервисов, крупнее тех, что ожидаются в конце. Используйте эти большие сервисы, чтобы научиться работать в многосервисной среде, наслаждаясь при этом тем обстоятельством, что такой их размер уменьшает объёмы межсервисного рефакторинга, который вам приходится выполнять. Затем, когда уже будут определены границы, разбейте сервисы на более мелкие.

Хотя многие мои знакомые склоняются к подходу «сначала — монолит», далеко не все разделяют такой метод. Контраргумент состоит в том, что начиная с микросервисов, вы привыкаете к ритму разработки в таком окружении. Требуется очень много (даже слишком много) дисциплинированности, чтобы построить монолитное приложение в модульном виде, достаточном для простого разбиения на микросервисы. Начиная с микросервисов, вы работаете в небольших командах, разделённых границами сервисов, это позволит вам ускорить разработку за счёт дополнительных кадровых ресурсов, как только это потребуется. Такой подход особенно хорошо работает в случае замены системы, когда у вас есть больше шансов получить достаточно стабильные границы на раннем этапе. Несмотря на редкие примеры, я думаю, что не следует начинать с микросервисов, если у вас нет достаточного опыта их разработки.

Микросервисы только начинают свое развитие, поэтому у меня недостаточно примеров, чтобы с твёрдой уверенностью озвучить критерии использования стратегии «сначала — монолит». Таким образом, любой совет по этой теме нужно рассматривать как предварительный, какими бы хорошими ни были приводимые в его пользу аргументы.

Предлагаю также почитать рассуждения Сэма Ньюмана о целесообразности применения микросервисов в одном из проектов.

Перевод статьи «MonolithFirst»