ADR-2410201
Maxim YunusovОбоснование выбора метода структуризации системы «Слайдомёт».
Контекст
Необходимо выбрать подход к структуризации системы «Слайдомёт» с учетом следующих нюансов:
- Крайне скудное описание системы. Анализ на этапе старта. Есть только виденье системы.
- Предполагается активная проработка требований. Не исключается изменение начальных представлений.
- Структуризацией занимается один архитектор, без особой надежды вовлечь в процесс прочих заинтересованных лиц.
Требования
- В результате структуризации мы должны получить структуру системы «Слайдомёт», оформленную в виде компонентной модели. Должны быть перечислены основные компоненты модели и способы их взаимодействия.
- Процесс структуризации должен быть итерационным, предполагающим поэтапное уточнение решения с учётом вновь полученных данных анализа.
- Процесс должен способствовать формированию структуры системы с высокой функциональной сцепленностью и низкой связанностью. Или, в терминах объектной модели: "чем выше коннасценция — тем ближе должны быть элементы".
Решение
Говоря языком математики, структуризация — это кластеризация.
Выбираем в качестве кластеризуемых объектов транзакции системы. Транзакция — это область одного доменного языка и однозначно высокая сцепленность.
Мы должны определить критерий близости (функциональной сцепленности) и выбрать подходящий метод, коих всего ничего:
- Алгоритм квадратичной ошибки.
- Восходящий алгоритм.
- Нисходящий алгоритм.
- Логический подход.
Выбранный вариант:
Логический подход с подстраиваемым деревом решений.
(Дальше можно не читать)
Варианты
Алгоритм квадратичной ошибки
(например, метод k-средних).
Скармливаем ему наши транзакции, и дело сделано. Но где взять транзакции? Для выявления транзакций можно использовать хорошо проработанные подходы типа «Событийного штурма».
Сам событийный штурм предлагает использовать интуитивный подход для выявления агрегатов и ограниченных контекстов. Однако прикрутить сюда «математику» не проблема.
Минусы:
- Для проведения событийного штурма необходима группа доменных экспертов (минимум четверо) и много времени. То есть мы должны предварительно провести полноценный анализ системы. В контексте нашей задачи это исключается.
Нисходящий алгоритм
Объекты сначала помещают в один кластер, а потом постепенно разделяют на кластеры всё меньше и меньше.
В архитектуре известен как подход «Monolith First».
Создается жертвенная архитектура, которую потом полностью переписывают.
Плюсы:
- Эволюционный алгоритм, поддерживающий развитие системы.
Минусы:
- Путь долгий и дорогой (предполагает обязательный архитектурный редизайн).
- По ходу работы придётся перестраивать процессы, так как разработка монолита и разработка сервисной архитектуры существенно различаются.
Восходящий алгоритм
Еще один эволюционный алгоритм. Каждый объект назначают кластером, а потом постепенно объединяют их до достижения нужной гранулярности.
Вопрос в том, что взять за основу.
Существует несколько распространенных (анти-)паттернов:
- Декомпозиция по сущности
Подход, известный как Entity-service.
У нас есть диаграмма концептов — создаём по компоненту на концепт. Компонент содержит только CRUD-операции для одной сущности и ничего более.
Плюсы:
- Эволюционный алгоритм, поддерживающий развитие системы.
Минусы:
- Выполнение каждой операции приводит к большому количеству вызовов.
- Распределенный монолит.
- Слишком долгая дорога вверх. - Декомпозиция по акторам
Известен как Domain-last approach.
У нас есть контекст-диаграмма — разбиваем систему по акторам.
Минусы:
- Предположение о том, что разные акторы говорят на разных доменных языках, ошибочно. Тут многое на многое. То есть еще хуже, чем предыдущий случай. В ходе эволюции нужно будет не только объединять компоненты, но и переразбивать их.
Логический подход
Формируем дерево решений, в узлах которого критерии распределения объектов (у нас — транзакций).
Прогоняем наши объекты (транзакции) от корня до листьев (компонент).
Тут главный вопросы — как построить дерево и что взять за критерий?
- Возможность переиспользования
Известен как Unjustified Re-Use.
Сцепляем элементы, которые можно повторно использовать в дальнейшем (привет, SOA!).
Минусы:
- Слишком нечеткий критерий.
- Можно додробиться до отдельных объектов и констант. - Подстраиваемое дерево решений
Формируем дерево решений эволюционно. Сообразно архитектурным задачам текущего этапа.
Первый этап — языковая дифференциация. Мы должны разделить транзакции по доменным языкам, на котором они «произносятся».
Как понять на каком языке «говорит» транзакция?
Здесь я предлагаю не париться с математикой и решать вопрос «по-архитектурному» — на слух.
Так же, как вы на слух определяете, на каком «человеческом» языке говорит собеседник.
Вы же при этом не используете строгие метрики и мат. модели?
Чаще всего мы просто узнаём знакомые слова или ориентируемся на национальную принадлежность собеседника.
Минус:
- Требуется архитектор, умеющий слышать стейкхолдеров и понимающий, на каком доменном языке они говорят.