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