Русский
Русский
English
Статистика
Реклама

Как быть, когда все советуют растащить проект на микросервисы. А ты не готов

Монолит часто обсуждают в негативном ключе. Но сразу перейти на микросервисы получится не у всех и вот уже не первая команда и компания делятся опытом построения переходного звена: модульной архитектуры. Давайте в деталях посмотрим, как делаются такие проекты.



Недавно я смотрел два доклада на эту тему: от Юлии Николаевой из iSpring и Антона Губарева из Skyeng. Так как с Антоном мы работаем в одной компании, для своего подкаста я решил поговорить с Юлей.



Ниже текстовая расшифровка основных идей из разговора.

Мы взвесили причины, по которым хотели перейти в микросервисы, и настоящие проблемы, которые мешали нам жить в монолитной архитектуре


Юлия: Когда мы начинаем разрабатывать приложение, функционала мало и его нужно запустить как можно быстрее. Но если дело идет, на определенном этапе кодовая база начинает неконтролируемо разрастаться а новых архитектурных решений, которые сдержали бы этот хаос, не принимается.

Это произошло с нашим проектом: он стартовал в 2009-м, но долго не было людей и времени, чтобы бороться с неконтролируемым разрастанием кодовой базы. А к 2018-му стало понятно: пора уже как-то реструктуризировать монолит.

Когда встал вопрос, что делать с нашим монолитом, мы, естественно, тоже рассматривали микросервисы. Но У распределенной архитектуры свои накладные расходы. И мы не были к ней готовы. Например, у нас не было команды девопсов от слова совсем.

Не было как такового нормального CI/CD, не было ни докера, ни кубернетеса вообще ничего такого.


Плюс, у нас не стояла остро проблема масштабирования: нет таких нагрузок. Что реально мешало очень тесная связанность кода. Изменение в одной части зачастую приводило к ошибкам в куче других мест, плюс мы не могли нормально разрабатывать несколько фич. Вернее, разрабатывать параллельно мы могли, но вот смержиться на этом этапе могли возникать неожиданные логические конфликты.

Мы поняли: решив острые проблемы, сможем еще какое-то время жить в монолите. Но думали и о том, а как бы сделать так, чтобы потом легче было перейти в микросервисную архитектуру? Наша предметная область дистанционное обучение. И здесь можно выделить модули: геймификация, управление курсами, статистика, отчеты такие подобласти внутри основной предметной области. Мы стали представлять наше приложение как набор независимых модулей.

У нас все усугублялось тем, что кусок легаси написан Symfony 1.4 с использованием Propel 2, который не так просто использовать в парадигме DDD (Domain Driven Design). А нам очень хотелось DDD. Для этого хорошо подходит ORM Doctrine, которую к легаси так просто не прикрутишь.

Мы решили скрестить ужа с ежом и теперь живем с двумя фреймворками.


Сейчас я думаю, что можно было пойти другим путем: не прикручивать новый фреймфорк, не прикручивать доктрину, а просто попытаться сделать чистую архитектуру на том, что есть. В основном наша проблема была в том, что бизнес-логика была в Propel Peers, моделях, контроллерах где ее только не было. И можно было, как у ребят из другого выпуска, на старом фреймворке сначала выделить модули, попытаться реализовать архитектуру, а потом уже это все в новый фреймворк перетаскивать. Возможно, так было бы проще и быстрее.


Буквально каждый день, на каждом шагу мы встречали множество вопросов, которые не знали, как решить


Мы, тимлиды, сначала вдвоем, потом втроем разрабатывали функционал в этой новой архитектуре. Было много вопросов. Начиная с того, как организовать папки в проекте: правда, когда сделали и поняли, как и зачем, находили в интернете просто массу источников, в которых все это написано. Наверное, не так искали)

Параллельно часть команды разработчиков ушла в девопсы.


Они занялись переездом в кубернетес, докер и все такое.

Чтобы погрузить остальную команду в тему, мы подготовили специальный курс по DDD, который пару выходных все проходили. Нашим разработчикам надо было реализовать два контекста прямо закодить их. Мы, конечно же, все идеи рассказали, но получили фидбэк, что очень сложно и мозг прямо ломает.

Да, поначалу тяжело. Но зато когда разработчик распробует и примет новую архитектуру, а ему прилетает фича, которую нужно сделать в легаси, у него сразу возникнет мысль: Как бы мне сделать так, чтобы было похоже на новую архитектуру.

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

На все у нас ушло, наверное, три с половиной месяца.


Мы не просто переделали архитектуру, но и реализовали новый функционал с вынесением частей из легаси. Плюс, все эти три месяца нам команда девопсов настраивала инфраструктуру, чтобы мы смогли взлететь в Kubernetes. Сейчас в новом коде у нас 14-15 контекстов плюс большой легаси, где можно было бы выделить несколько контекстов. Пока в легаси остается большинство контроллеров непонятно было, куда положить их код, потому что контроллеры могут получать и манипулировать данными разных контекстов.

И ура! Мы можем писать фичи в 3-4 потока командой из 12 бэкендеров.


Сергей: В PHP мы не можем дать программисту по рукам и запретить использовать какой-то внутренний класс другого модуля. Это же все держится на устных договоренностях внутри команды. Как это все организовать?


Юлия: Контролировать такую архитектуру сложно. Все разработчики должны быть погружены в эту идею, разделять ее. Мы по этим граблям прошлись поначалу, когда вовлекали команду. Многим казалось, что это оверинжиниринг дикий: Зачем так сложно, давайте так не будем.

Но спустя некоторое время, почувствовав разницу между написанием кода в новой архитектуре и в легаси, все прониклись. Некоторое время мы жили на договоренностях и пытались все отслеживать на ревью. Но сейчас между модулями есть API, по которому они взаимодействуют. И мы не имеем права в обход этого API что-то там из модуля подергать.

Мы нашли такую утилиту deptrac статический анализатор кода, который помогает контролировать зависимости.


Утилита встроена в наш CI/CD и запускается автоматически: фактически, большая часть договоренностей контролируется с ее помощью. Логические ошибки стараемся отлавливать еще на архитектурном ревью: это встреча, на которой разработчик, которому предстоит пилить фичу, представляет схемы, где все по слоям уже разделено. Там сразу понятно, что в каком контексте, какие взаимосвязи и т.д.

Сергей: А как такую архитектуру мэйнтэйнить?

Юлия: У нас есть статьи по тому, как располагать классы по слоям. Информацию про выделение контекстов очень сложно формализовать, потому что это вещь достаточно специфичная для каждой фичи. Тут каких-то правил не может быть, это просто архитектурный шаблон.

Сергей: БД у нас одна, проект у нас один. Что мне делать, если в моем модуле нужны данные из нескольких других контекстов?

Юлия: Это один из самых сложных вопросов наверное, как в модульной, так и в микросервисной архитектуре. Мы пытались в одном из случаев реализовать объединение данных из разных API: сделали запросы, объединение в памяти, сортировку, фильтрацию. Работало жутко медленно.

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

Сергей: И здесь мы подходим к проблеме с дублированием кода...

Юлия: Дублирование возникает, например, если у нас есть слой, который авторизует операции во всех контекстах и мы его дублируем в каждом контексте. То есть, у нас есть практически одинаковый код, который запрашивает: А есть ли права у пользователей. Но мы считаем, что это достаточно приемлемое дублирование.

Сергей: А что делать, когда одному модулю нужно выполнить действие в другом модуле? Например, при оплате изменить баланс, создать уведомление это все разные контексты. Как в монолите быть с этим?

Юлия: Ты перечислил кейсы, которые хорошо укладываются в событийную модель. У нас много через асинхронные ивенты сделано. Если контекст не должен знать ничего про то, что произойдет в других контекстах, будет событие, которое обработает все заинтересованные в нем лица. Если действие тесно связано с выполняемой операцией и про ее контекст нужно знать, напрямую вызывает метод API.

Все как в микросервисной архитектуре, грубо говоря.


Событийная модель везде одинакова. Один ивент могут слушать разные модули и обрабатывать по-разному. И даже в одном модуле может быть несколько разных хендлеров у одного события, если это надо.

Сергей: Но если приложение постоянно усложняется фичами и контекстами, модульный монолит все равно лишь промежуточный шаг к микросервисам?

Юлия: Да, конечно. Если подразумевается, что приложение будет непрерывно расти, если команды будут расти, это естественно. Например, у нас возникла проблема, что автотесты нереально долго выполняются перед релизом, а если что-то отвалится приходится повторно это все запускать.

Новые фичи, если они независимые, мы будем, наверное, в микросервисах сразу делать. Тем более у нас уже есть инфраструктура, есть шаблон, из которого можно создать новый микросервис. Но, допустим, если нужно использовать какие-то данные или классы из легаси, у которого нет своего API. У нас такой принцип, что легаси может дергать API, но новые контексты от легаси, фактически, ничего не могут получать и с ними не общаются, только через ивенты. Если мы вынесем что-то в микросервис, а этому микросервису нужен будет доступ к легаси коду, какому-то функционалу, то это будет достаточно сложно сделать.

P.S. Больше выпусков подкаста Между скобок с интересными людьми из мира PHP можно найти здесь.
Источник: habr.com
К списку статей
Опубликовано: 30.06.2020 12:04:28
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании skyeng

Php

Symfony

Совершенный код

Управление разработкой

Сервисная архитектура

Модульный монолит

Микросервисы

Утилиты

Категории

Последние комментарии

© 2006-2020, personeltest.ru