Потока-сознания-пост: и снова о декомпозиции
August 9, 2022
Предистория
Давным-давно, я знал только один подход к декомпозиции систем на базе "здравого смысла" и кластерного анализа. Декомпозиция по слоям - не в счёт, это не подход к декомпозиции, а избегание этой самой декомпозиции. Этим подходом, на самом деле, я пользуюсь до сих пор в случаях, когда надо максимально быстро выкатить первый "ходячий скелет" проекта. Однако, его сложно применять для планирования и оценки работ, и он опирается на то, что первые 10-20 классов критической массы будут спроектированны более-менее прилично, что не под силу молодым разработчикам, например.
Поэтому я начал думать дальше в поисках методики, которую можно было бы объяснить и молодым разработчикам и которая помогала бы им проектировать хорошие системы. Следующим шагом на этом пути стала идея компонентов. И на тот момент это была именно что идея - без конкретной методики декомпозиции системы на компоненты. Я сделал в такой парадигме пару небольших проектов и получилось в целом достаточно хорошо.
Но, во-первых, я это сделал по большому счёт интуитивно (хотя для одного из проектов нарисовал некоторое подобие диаграммы Эффектов). Во-вторых, сами компоненты я реализовывал по Чистой архитектуре, в которой (после этих же проектов) разочаровался. В-третьих, я все компоненты свалил в одно место - и компоненты мониторинга, и компоненты предметной области, и компоненты инфраструктуры. Наконец, меня смущало нарушение Common Reuse Principle - если операция компонента А требует данных компонента Б, то компонент А тащит в зависимости весь компонент Б.
Поэтому на следующей итерации я попробовал разделить слои домена и приложения. И, честно говоря, либо я уже не помню, что меня на самом деле это сподвигло, либо это было помутнение сознания - дурацкая затея, вобщем, была. Но тем не менее, следующий проект я начал делать в этой парадигме.
Однако это была тупиковая ветвь эволюции Эргономичного подхода. Тот пост заканчивался словами "Вот у вас есть требования, вам надо спроектировать ядро - как это сделать? Ответ в следующем посте.". И "следующего поста" не было. Я не осилил придумать методику проектирования таких модулей и это стало одной из причин моего идейного кризиса начала года.
В итоге из этой части идейного кризиса я вышел отказавшись от CRP в пользу сокрытия информации и низкой сцепленности и вернувшись к парадигме ядра состоящего из равноценных компонентов. При том одумался я вовремя, и успел отрефакторить проект, который начал делать по слоям и он тоже завершён вполне благополучно и в ближайшие дни планируется его выход в прод.
Где-то в этот период я вплотную взялся за диаграмму Эффектов и именно она стала ответом на вопрос "Вот у вас есть требования, вам надо спроектировать ядро - как это сделать?". И на этот раз ответ у меня уже сформирован, осталось его только отредактировать и опубликовать (первую часть - уже в августе).
Очередной проект я начал с построения диаграммы Эффектов (в её текущей реинкарнации) и декомпозиции её на компоненты. Активную работу над проектом я закончил ещё в мае, но из-за бюрократических проволочек он ещё не в проде. Поэтому судить об успехе проекта с точки зрения заказчика ещё рано, но с технической точки зрения он был вполне успешен - у меня ни разу не было аналитического паралича и получившаяся декомпозиция и эстетически и по формальным метрикам хороша.
Казалось бы, вот он наш хэппи энд. Но не тут-то было. Или тут. Поехали к истории.
История
Я сейчас "лидю" медицинский легаси проект (Проект Э). Там среди прочего есть медицинский профиль пользователя и дневник наблюдений. Они разнесены по разным микросервисам и микросервис дневника зависит от профиля.
И теперь надо добавить в систему административную панель, где среди прочего надо показывать профили пользователя. И последнее события из дневника. В одной строке одной таблицы. Вопрос куда засунуть операцию получения страниц этой таблицы.
В дневник мы не можем её засунуть, т.к. у нас первичным источником являются профили, и не у всех есть события, и в этом случае мы потеряем часть профилей. Теоретически, можно закостылять это и залезть из дневника в базу профиля, но боюсь боги микросервисов поразят меня молнией сразу же после коммита.
А если положить операцию в профиль - появится цикл. Тут я уже сам скорее застрелюсь, чем допущу цикл.
На самом деле нет - так и будем сейчас делать, ибо сроки жмут…
Дилемма, вобщем. А я там в посте про декомпозицию подробненько покопался в подходе пакетирования по компонентам. По нему инфы мало, но такое ощущение, что он по сути совпадает с тем, что делаю я. Только вот Браун контроллеры выносит в отдельный слой. Как раз то, что я недавно счёл тупиковой ветвью эволюции. А тут у меня ситуация, которая плохо ложится на мой текущий способ декомпозиции. А вот если вытащить контроллер из компонентов, то уже он будет зависеть и от профиля и от дневника и "все щасливы". И я снова задумался: не попытаться ли мне ещё раз глянуть в сторону разделения на слои?
Нет. Изначальная команда Проекта Э декомпозировала его некорректно - по факту по сущностям. В итоге практически любая операция системы затрагивает от 3 до 6 микросервисов. Удачного дебага, сучки. Блин этош я…:( В общем это реально больно. Но я отвлёкся.
Так вот я (пока ещё) не занимался изучением вопроса как правильно декомпозировать эту систему. Но, полагаю, я бы пошёл одним из двух путей:
- Развернул бы зависимость, т.к. дневник является по сути частью агрегата профиля - при удалении профиля весь дневник должен быть удалён, создать дневник без профиля невозможно. Технически я бы выделил дневник в отдельный агрегат, но только исходя из принципа малых агрегатов.
- Сделал бы общий компонент/объект/модуль "Patients", с единым сервисом-интерфейсом инкапсулирующий ресурсы коллекции профилей и дневников
И, кажется, у нас снова победа декомпозиции на компоненты. Но ждём новых вызовов реальных проектов, возможно одному из них всё-таки получиться пошатнуть её позиции.
Ремарка: я сейчас говорю строго о декомпозиции API бакэндов информационных систем. В случае же "Web 1.0" приложения, когда контроллеры - это классические контроллеры из MVC, которые из нескольких компонентов собирают модель для представления - тогда стоит контроллеры выделить в отдельный слой, как у Брауна в пакетировании по компонентам.