В чём ключевое архитектурное отличие вертикального среза от горизонтальных слоёв при изменении одной бизнес-возможности?
Вертикальный срез группирует код по бизнес-возможности и проводит её через нужные технические уровни внутри одного модуля. Поэтому изменение одной возможности обычно затрагивает один ограниченный срез. Горизонтальные слои группируют код по технической роли, из-за чего изменение возможности часто требует координированных правок в нескольких слоях.
Это не означает, что вертикальные срезы автоматически лучше: они могут дублировать инфраструктурный или прикладной код и требуют явных границ общих компонентов.
Горизонтальное слоение появилось как способ управлять сложностью через разделение технических обязанностей: представление, прикладная логика, доменная модель и инфраструктура. Такой подход облегчает унификацию общих механизмов, но не всегда совпадает с тем, как бизнес меняет систему.
Вертикальные срезы получили распространение как ответ на проблему сквозных изменений. Их цель — организовать систему вокруг бизнес-возможностей, чтобы команда могла развивать одну возможность с меньшим количеством координации между независимыми техническими областями.
Представим систему, где добавление одной бизнес-возможности требует изменений в общем контроллерном слое, общем сервисном слое, нескольких репозиториях и наборе конфигураций. Даже если бизнес-правило относится только к одной функции, изменение проходит через множество технических границ.
Это увеличивает связанность изменений: сложнее оценить область воздействия, провести ревью и выпустить функциональность независимо. Однако простое копирование кода по вертикальным срезам тоже опасно: исправление общего правила может потребовать поиска нескольких копий.
В горизонтальной архитектуре граница обычно проходит между техническими уровнями. Компонент верхнего уровня вызывает компоненты нижнего, а одна бизнес-возможность распределена по нескольким слоям. В результате изменение сценария может затронуть каждый слой и его контракты.
В вертикальном срезе граница проходит вокруг бизнес-возможности. Внутри него могут находиться обработка входного запроса, прикладной сценарий, доменные правила и доступ к данным, но наружу публикуется небольшой контракт модуля.
Механизм уменьшения связанности основан не на отсутствии зависимостей, а на их локализации. Внутренние изменения среза не требуют изменений в других срезах, пока не меняется его внешний контракт или общий бизнес-инвариант.
Общие технические механизмы всё равно допустимы: например, библиотека логирования, транспортный адаптер или единый механизм авторизации. Но общий компонент должен быть действительно стабильным и не превращаться в место, через которое срезы начинают зависеть от деталей друг друга.
Главный компромисс — между локальностью изменений и повторным использованием. Чем больше код разделяют между срезами, тем выше риск общей точки связанности; чем больше дублируют, тем выше стоимость исправления одинакового поведения и поддержания единообразия.
Вертикальный срез не равен отдельному микросервису. Несколько срезов могут находиться в одном процессе и использовать одну базу данных, сохраняя при этом модульные границы. Выделение сервиса имеет дополнительные последствия: сетевые сбои, распределённые операции, отдельное развертывание и эксплуатационную стоимость.
В платформе обучения существовали возможности записи на курс, проверки работ и выдачи сертификатов. Код был организован по слоям, поэтому изменение правил выдачи сертификата требовало правок в общем сервисном слое, доменных объектах, репозитории и нескольких тестовых наборах. Часть зависимостей была технически общей, хотя бизнес-сценарии почти не пересекались.
Рассматривались три варианта. Сохранение слоёв требовало меньше структурных изменений и сохраняло высокий уровень повторного использования, но не устраняло сквозные изменения. Выделение отдельных микросервисов усиливало автономность, однако добавляло сетевую и эксплуатационную сложность без доказанной необходимости. Переход к микросервисам был бы преждевременным.
Выбрали вертикальные срезы внутри модульного монолита: запись, проверка работ и сертификаты получили отдельные внутренние границы и собственные сценарии. Стабильные технические механизмы оставили общими, а бизнес-правила не стали помещать в общий слой.
В результате изменения правил сертификатов стали локальными для соответствующего модуля, а общая инфраструктура сохранила единообразие. Компромиссом стала некоторая дубликация прикладных адаптеров и необходимость отдельно контролировать общие бизнес-правила.
Нет. Он уменьшает прежде всего связанность изменений между бизнес-возможностями. Срезы всё ещё могут быть связаны общими данными, общими правилами, синхронными вызовами или нестабильной общей библиотекой.
Поэтому после перехода нужно проверять не только структуру каталогов, но и направление зависимостей, публичные контракты, владение данными и фактический граф вызовов. Формальное разделение кода без ограничения доступа к внутренностям не создаёт настоящей модульности.
Дублирование обычно допустимо, если поведение небольшое, изменяется независимо и его принудительное объединение создало бы сильную связанность. Например, два среза могут иметь похожие преобразования входных данных, но разные бизнес-смыслы и разные темпы изменений.
Общий компонент оправдан, когда правило имеет единый смысл, должно изменяться согласованно и обладает устойчивым контрактом. Важно не устранять всякое дублирование автоматически, а сравнивать стоимость повторного исправления со стоимостью общей точки изменения.
Они не решат проблему, если несколько возможностей обязаны совместно поддерживать один инвариант, используют общую модель владения или требуют неделимой операции. В таком случае разделение по каталогам не устраняет реальную связанность предметной области.
Сначала нужно определить владельца инварианта и допустимый контракт между модулями. Иногда правильным решением будет один более крупный модуль, иногда — явная координация через событие или процесс, но выбор должен следовать из требований к согласованности, а не только из желания получить независимые срезы.