Основной темой данного стрима будет "компонентно ориентированная декомпозиция". Как и любая декомпозиция - это лишь часть процесса построения архитектуры приложения, в задачи которой входит уменьшение зацепления компонентов между собой, в некоторых случаях для этого требуется изменение компонентной структуры приложения.
Монолиты часто представляют собой сильной зацепленные компонентно ориентированные приложения, поэтому сам по себе компонент не является признаком хорошей декомпозиции.Для уменьшения зацепление используется подход "извлечение компонент" и "ветвление (дублирование) компонент".
В первом случае мы постепенно уменьшаем зацепление путем точечного выделения компонента из всего приложения, во втором делается копирование всего монолита и удаляется лишнее.
Уход от монолитной архитектуры требует грамотной декомпозиции на компоненты, мы рассмотрим следующий алгоритм:
Часто на митингах звучит фраза "а теперь давайте обсудим архитектуру проекта" и далее начинается обсуждение того как нужно правильно разделить программу на классы и каким образом выстроить файловую структуру проекта. На самом деле речь идет не об архитектуре, а о декомпозиции, почему так? Давайте разбираться.
Декомпозиция — операция мышления, состоящая в разделении целого на части. Также декомпозицией называется общий приём, применяемый при решении проблем, состоящий в разделении проблемы на множество частных проблем, а также задач, не превосходящих суммарно по сложности исходную проблему, с помощью объединения решений которых, можно сформировать решение исходной проблемы в целом. (ист. википедия)
Архитектура программного обеспечения — совокупность важнейших решений об организации программной системы. Архитектура включает:
На самом деле определение архитектуры приложения имеет много трактовок, но все так или иначе сходятся в том, что архитектура - это выделение главного и принятие решений о функционировании системы в целом. Процесс выработки архитектурного решения, как правило, состоит из следующих шагов:
Таким образом "декомпозиция" действительно используется как составной компонент построения архитектуры программной системы, но само понятие архитектуры гораздо шире, чем само понятие декомпозиции. Так же важно понимать, что архитектурная декомпозиция строится как правило на базе функциональной декомпозиции, а не модульной или классовой.
Таким образом, если речь идет о разделении программы на классы (не о выделении интерфейсов, не о распределении обязанностей, не о выработке требований и т.д.), а только о "географическом" размещении файлов и вынесении кода в эти файлы, то это с большим натягом можно отнести к процессу построения архитектуры приложения, но правильнее всего называть "модульная декомпозиция" или "классовая декомпозиция". Архитектуре же строится по принципу "от общего к частному" и начинается со сбора и формирования требований.
При работе с готовым монолитным приложением в первую очередь нужно понять размер технического долга (рассмотрим на отдельном стриме) и качество построенной архитектуры. Самое простое, что можно сделать для оценки качества архитектуры - построить "температурную карту приложения".
Температурная карта - это схематическое отображение компонентов приложения в виде прямоугольник окрашенных в градацию цвета от зеленого до красного. При этом:
Температура выставляется взвешенно относительно медианного значения по проекту.
Задача: визуализировать приложение с позиции качеств кода, выделить наиболее и наименее перегруженные места. Понять насколько сбалансирован код, в контексте модифицируемости (см. стрим "Основные характеристики качества")
Желательно выводить оценку компонент на основе средств статического анализа и определить оценку "температуры" как фитнес функцию. Тогда при перестроении приложения новая карта будет обновляться автоматически.
Решение: рефакторинг кода с целью нормализации "температурной карты"
После оптимизации кодовой базы у нас получается монолитная система с более удачным уровнем грануляции компонент, сбалансированных по сложности и размеру. Но остается примерной такой же уровень зацепления, который и был. Поэтому следующим этапом выполняется шаг по определение и уменьшению силы зацепления.
Задача: выявить компоненты с наибольшим уровнем зацепления. В стриме по Основным характеристикам качества мы говорили что оптимальный уровень зацепления - 2-3 компонента, все что более 7 - уже плохо.
Решение: оптимизировать зацепление. Наиболее эффективные способы управлять зацеплением:
После того, как выполнены предыдущие два шага, у нас получается хорошо спроектированное монолитное приложение, которое не имеет явных проблем с основными характеристиками качества. На следующем этапе необходимо провести четкие архитектурные границы (частично они уже есть, но теперь их нужно провести явно).
Задача: провести архитектурные границы, изолирующие функциональность приложения.
Решение:
Обычно в монолитных приложениях используется прямое обращение ко всем сущностями приложения (например, прямое обращение к методам класса). Исключением, как правило, является обращение к СУБД, которе делается либо через драйвер, либо дополнительно используется прослойка ORM.
Задача: выявить интерфейсы на уровне модулей и поднять их уровень абстракции.
Решение: повышение уровня абстракции интерфейса, как правило, достигается за счет перехода от интерактивных механизмов взаимодействия к реактивным. Наиболее популярен механизм "Pub/Sub", где есть источник, приемник и медиатор (шина). Для использование интерфейса унифицируется формат передачи данных и способы сериализации данных (бинарные или текстовые).
Следующим шагом модули формируются в доменную стркутру - где каждый домент это по сути "микромонолит", т.е. либо сервис, либо микросервис. Выполняющий свою собственную бизнес-логику (не путать с DDD).
Задача: подготовить компоненты к раздельной дистрибуции на серверные мощности
Решение:
Финальным шагом выполняется проектирование разделенного монолита под масштабирование нагрузки.
Задача: выполнить подготовку инфраструктуры для развертывания модульного приложения
Решение: