Ранняя изоляция компонент vs прагматизм: когда жёсткие границы компонент убивают гибкость и скорость разработки

от автора

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

Изменение границ компонент это сложно. В ООП это сложнее чем в ФП из-за более крупной гранулярности, класс сложнее чем отдельная функция. Изменение границ микросервисов сложнее чем в монолите.

Проблема ранней изоляции:

Необходимость частого рефакторинга на раннем этапе

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

Гибридный подход:Функциональный домен, императивная оболочка.

Домен — функциональное ядро: Бизнес-логика в чистых функциях, независимых от инфраструктуры.

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

Риски:Скрытая привязка к библиотеке: Домен косвенно зависит от её типов. — Сложность замены: Если библиотека всё же потребует замены, придётся модифицировать методы расширения.

Итог: Ранняя изоляция через толстые адаптеры часто избыточна.

Методика

Как же тогда должна выглядеть методика обследования и проектирования на основе DDD, но оставляя гибкими границы доменов по bounded context до нужного момента?

Методика пригодна как для проектирования архитектуры доменных компонент, так и более мелкого уровня детализации (структуры данных и функции).

Определения (мои)

  1. Состояние — наблюдаемое явление, фиксированный набор значений параметров системы или её части в определённый момент времени, определяющий её поведение и доступные действия.

  2. Типы → Категории возможных состояний системы и их допустимых комбинаций.

  3. События → Факты о произошедших изменениях (прошлые состояния).

  4. Процессы → Механизмы перехода между состояниями (будущие изменения состояний).

Последовательность проектирования компонент (домена DDD либо более мелких сущностей):

1. Анализ домена:

— Event Storming → выявление ключевых событий и процессов.

— Определение Bounded Context → границы модулей. Домен должен быть такой чтобы помещался а голове одного доменного эксперта. Если говорить про модули кода, то принцип единственной ответственности не позволит вырасти когнитивной сложности компонента, так как не смешивает разные предметные области в одном коде.

2. Моделирование типами:

— Каждое доменное понятие → алгебраический тип данных, определяет набор возможных состояний и их комбинаций.

— Бизнес-правила → валидаторы как функции.

3. Чистые функции для логики:

  • Мелкая гранулярность в ФП позволит легко переносить функционал через границу компонент

  • Сервисы → композиция pure-функций

  • Обработка ошибок → Either/Result типы.

4. Изоляция эффектов и состояний:

IO-операции → отдельный слой (Http, БД).

Использование СУБД выноса состояний наружу или монад для отсутствия скрытых побочных эффектов / состояний. Если это сложно или не эффективно, то для реализации состояний можно использовать состояние объекта в ООП. Также ООП имеет преимущество если ООП библиотеки уже реализуют почти всю логику вашей предметной области и ваши добавления незначительны.

5. Оптимизация скорости (при необходимости)

Когда же тонкая и гибкая прослойка должна стать жёсткой и надёжно изолирующей?

Выбор между тонкой и толстой прослойкой между компонентами зависит от контекста:

1. Тонкая прослойка (быстро/минимализм) или даже вызовы библиотек напрямую, жертвуя гибкостью и принципом единственной ответственности.

— Подходит, если термины библиотеки на 80% совпадают с вашим доменным языком.

— Подходит когда граница компонент ещё не сложилась, она может и должна легко меняться.

— Риск: Привязка к библиотеке, но экономия времени на разработку.

2. Толстая прослойка (надёжность/изоляция):

— Нужны доменные модели, полностью абстрагированные от библиотек.

— Границы компонент не меняются.

— Нужно надёжно изолировать компоненты, чтобы изменения в одних не требовали цепочку изменений других. Особенно, если другими компонентами уже владеет другая группа разработки.

Компромисс:

Даже минимальные адаптеры (интерфейсы + базовые преобразования) лучше, чем прямое использование библиотеки в ядре. Это сохраняет путь к будущим изменениям без переписывания системы.

Правило выбора:

Чем критичнее компонент для бизнеса и чем более стабильны границы между компонентами, тем «толще» должна быть прослойка между компонентами.

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

Рефакторинг ООП это просто?

18.18% Конечно, написал фабрику фабрик и вперёд!2
72.73% Я лучше сначала сделаю как проще8
0% ООП? Паттерны проектирования? А что это?0
9.09% Рефакторинг? Зачем? И так сойдёт!1

Проголосовали 11 пользователей. Воздержался 1 пользователь.

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

Прототипы без статической типизации проще?

12.5% Сначала пишу без типов, а потом если нужно добавлю их1
12.5% Ерунда, всегда пишу без статических типов1
75% Сразу типы: продумать типы значит спроектировать6

Проголосовали 8 пользователей. Воздержавшихся нет.

ссылка на оригинал статьи https://habr.com/ru/articles/882826/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *