АрхитектураАрхитектура ПОАрхитектор программного обеспечения

В чём ключевое архитектурное отличие вертикального среза от горизонтальных слоёв при изменении одной бизнес...

В чём ключевое архитектурное отличие вертикального среза от горизонтальных слоёв при изменении одной бизнес-возможности?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Вертикальный срез группирует код по бизнес-возможности и проводит её через нужные технические уровни внутри одного модуля. Поэтому изменение одной возможности обычно затрагивает один ограниченный срез. Горизонтальные слои группируют код по технической роли, из-за чего изменение возможности часто требует координированных правок в нескольких слоях.

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

Исторический контекст

Горизонтальное слоение появилось как способ управлять сложностью через разделение технических обязанностей: представление, прикладная логика, доменная модель и инфраструктура. Такой подход облегчает унификацию общих механизмов, но не всегда совпадает с тем, как бизнес меняет систему.

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

Постановка проблемы

Представим систему, где добавление одной бизнес-возможности требует изменений в общем контроллерном слое, общем сервисном слое, нескольких репозиториях и наборе конфигураций. Даже если бизнес-правило относится только к одной функции, изменение проходит через множество технических границ.

Это увеличивает связанность изменений: сложнее оценить область воздействия, провести ревью и выпустить функциональность независимо. Однако простое копирование кода по вертикальным срезам тоже опасно: исправление общего правила может потребовать поиска нескольких копий.

Подробное решение

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

В вертикальном срезе граница проходит вокруг бизнес-возможности. Внутри него могут находиться обработка входного запроса, прикладной сценарий, доменные правила и доступ к данным, но наружу публикуется небольшой контракт модуля.

Механизм уменьшения связанности основан не на отсутствии зависимостей, а на их локализации. Внутренние изменения среза не требуют изменений в других срезах, пока не меняется его внешний контракт или общий бизнес-инвариант.

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

Главный компромисс — между локальностью изменений и повторным использованием. Чем больше код разделяют между срезами, тем выше риск общей точки связанности; чем больше дублируют, тем выше стоимость исправления одинакового поведения и поддержания единообразия.

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

Ситуация из практики

В платформе обучения существовали возможности записи на курс, проверки работ и выдачи сертификатов. Код был организован по слоям, поэтому изменение правил выдачи сертификата требовало правок в общем сервисном слое, доменных объектах, репозитории и нескольких тестовых наборах. Часть зависимостей была технически общей, хотя бизнес-сценарии почти не пересекались.

Рассматривались три варианта. Сохранение слоёв требовало меньше структурных изменений и сохраняло высокий уровень повторного использования, но не устраняло сквозные изменения. Выделение отдельных микросервисов усиливало автономность, однако добавляло сетевую и эксплуатационную сложность без доказанной необходимости. Переход к микросервисам был бы преждевременным.

Выбрали вертикальные срезы внутри модульного монолита: запись, проверка работ и сертификаты получили отдельные внутренние границы и собственные сценарии. Стабильные технические механизмы оставили общими, а бизнес-правила не стали помещать в общий слой.

В результате изменения правил сертификатов стали локальными для соответствующего модуля, а общая инфраструктура сохранила единообразие. Компромиссом стала некоторая дубликация прикладных адаптеров и необходимость отдельно контролировать общие бизнес-правила.

Что кандидаты часто упускают

  1. Уменьшает ли вертикальный срез любую связанность?

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

Поэтому после перехода нужно проверять не только структуру каталогов, но и направление зависимостей, публичные контракты, владение данными и фактический граф вызовов. Формальное разделение кода без ограничения доступа к внутренностям не создаёт настоящей модульности.

  1. Когда дублирование между вертикальными срезами следует признать допустимым?

Дублирование обычно допустимо, если поведение небольшое, изменяется независимо и его принудительное объединение создало бы сильную связанность. Например, два среза могут иметь похожие преобразования входных данных, но разные бизнес-смыслы и разные темпы изменений.

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

  1. Когда вертикальные срезы не решат проблему независимо от выбранной структуры?

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

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