Pull to refresh

Как я научился не волноваться и полюбил микросервисы, часть 1: Эффекты плохого кода

Reading time5 min
Views17K

Преамбула


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

Все паттерны разработки, как правило, имеют свои плюсы и минусы. Таким образом, преимущества зачастую носят субъективный характер и разработчику следует выбирать подходящие модели в зависимости от условий и контекста.

Я постараюсь выделить объективные или почти-объективные плюсы — преимущества, которые дадут положительный эффект любому разработчику независимо от языка программирования, размера команды или диеты. Первая статья посвящена стоимости плохо написанного кода – мы сравним эффекты влияния такого кода на монолитные приложения и на микросервисы.

Кроме того, позже, когда наберется несколько статей, я планирую смонтировать видео для YouTube – анимации и скринкасты донесут мою точку зрения яснее.

Введение: Как конвенции и фреймворки улучшают запутанный код


Когда вы пишете программу из 100 строк, то, в принципе, не имеет значения насколько крутой вы выбрали дизайн или насколько четко вы будете следуете модным идеям. Небольшое приложение относительно легко понять, просто потому что оно небольшое. А начать его оптимизировать было бы анти-паттерном само по себе – такую оптимизацию часто называют преждевременной.

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

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

Начинает появляться опасность запутанного кода – файл X обращается файлу Y, Y зависит частично от файла Z, файл Z импортирует несколько функций из файлов А и Б. Приходит младший разработчик, изменяет один файл и ломается всё приложение, а вы должны исправить ошибку, прежде чем боссу позвонит первый разгневанный клиент.

Решать проблему к нам пришли фреймворки. Фреймворки зачастую насаждают свои конвенции (правила), систематические разбиение приложения на файлы и каталоги. Например, контроллеры должны иметь дело только с веб-запросами, классы моделей должны содержать бизнес-логику, шаблоны должны содержать только HTML, конфигурация должна храниться в отдельном месте и желательно зависеть от текущей среды.

Хотите добавить ресурс? Измените файл маршрутов!
Хотите добавить дополнительную логику, которая запускается после сохранения записи? Подпишитесь на событие!
Хотите добавить дополнительные условия для запросов в базу данных? Создайте класс поведения таблицы!
И так далее.

Это не просто помогает разрабатывать более крупные монолитные приложения, это единственный способ разработать крупное приложение и не сойти с ума! Если каждый член команды будет иметь право добавлять код куда угодно, то ваш процесс разработки выскочит из-под контроля довольно быстро.

Посмотрим на структуру пустого приложения на Ruby on Rails:

./app/assets
./app/assets/config
./app/assets/images
./app/assets/javascripts
./app/assets/javascripts/channels
./app/assets/stylesheets
./app/channels/application_cable
./app/controllers
./app/controllers/concerns
./app/helpers
./app/jobs
./app/mailers
./app/models
./app/models/concerns
./app/views/layouts
./bin
./config
./config/environments
./config/initializers
./config/locales
./db
./lib
./lib/assets
./lib/tasks
./log
./public
./test
./test/controllers
./test/fixtures
./test/fixtures/files
./test/helpers
./test/integration
./test/mailers
./test/models
./tmp
./vendor
./vendor/assets
./vendor/assets/javascripts
./vendor/assets/stylesheets

Реальность такова, что в вашей команде могут быть неопытные (или с похмельем) коллеги, которые будут нарушать вроде бы простые конвенции время от времени, и код будет становится всё сложнее и уродливее, несмотря на выбор «правильных» фреймворка и структуры.

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

Монолиты и микросервисы: Влияние на спагетти-код


Вот что делают микросервисы со спагетти:

image

Ой, не та картинка. Вот так примерно выглядит спагетти-код в случае монолитного приложения:

image

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

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


image

Микросервисы, с другой стороны, как правило, общаются через веб-запросы (обычно RESTful) или через сообщения. Таким образом, разработчик не может просто взять и вызвать функционал одного микросервиса из другого микросерфиса – как минимум, придется создать дополнительный маршрут, открыть этот метод в контроллере и так далее. Это дополнительная работа, барьер, который разработчики не будут преодолевать без абсолютной необходимости. Существует также вероятность того, что тот другой микросервис в настоящее время поддерживается другой командой вашей компании, а разработчики там вредные и они не хотят добавлять ненужный (с их точки зрения) маршрут лишь ради того, чтобы сделать вашу жизнь проще.

В результате, вы, скорее всего, будете иметь меньшее количество по-лучше организованных соединений. А факт меньшего количества зависимостей между микросервисами (различными функциональными модулями вашего приложения) означает, что если микросервис А плохо реализован, он не будет иметь такого дурного влияния на другие микросервисы.

В среде микросервисов плохой код изолирован.

Микросервисы: Успокой своего внутреннего перфекциониста


Так как отдельно взятый микросервис – это не более, чем класс или два, вырезанных из вашего монолитного приложения, то теперь у вас меньше, значительно меньше файлов в рамках одного открытого приложения в IDE. Таким образом, вероятно, уже не нужно так сильно заботиться о строгих правилах наименования файлов и папок и, возможно, вы даже можете ослабить правила SOLID.

Теперь вы можете позволить себе «халяву» – можно сделать несколько ошибок, несколько неоптимальных реализаций, а ваше приложение всё еще достаточно легко читать и править, потому что ваш LoC (Lines of code) упал с нескольких тысяч до жалких десятков или сотен!
Процесс разработки ускорится, потому что вы меньше обеспокоены строгими правилами и мириадой зависимостей!

Вывод


Микросервисы, как архитектурный паттерн, позволяют снизить стоимость (издержки от) неоптимального исходного кода, ускорить разработку и повысить качество сна.
Tags:
Hubs:
+8
Comments85

Articles