Статьи

Люблю свою архитектуру

[Эта статья была написана Александром фон Zitzewitz]

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

Снимок экрана 2015-05-21 в 3.36.38 вечера

48 пакетов в циклической группе зависимостей (Apache Cassandra Project)

На снимке экрана ( Sonargraph-Explorer ) показано, как зависимости вышли из-под контроля в проекте Apache Cassandra, который все еще является относительно молодым проектом с открытым исходным кодом. В проекте 57 различных пакетов, и 48 из них настолько запутаны, что любая архитектура, которая могла существовать на ранних стадиях проекта, теперь полностью не распознается в коде. Это не означает, что Cassandra является плохим программным обеспечением, но это определенно означает, что его сложно поддерживать или понимать.

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

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

Как настроить архитектуру

Освоение архитектуры сложной программной системы похоже на управление империей. Поэтому разделяй и властвуй — отличная стратегия. Чтобы определить архитектуру, вам придется разделить вашу систему на более мелкие блоки, а затем описать, как эти различные элементы могут зависеть друг от друга. Я назову атомную единицу архитектуры «компонентом». В Java компонентом будет отдельный файл Java, в C ++ это будет комбинация исходного файла и связанного с ним заголовочного файла.

Первый уровень структурирования компонентов заключается в группировании связанных компонентов в «пакеты». Java уже предлагает эту концепцию, в C ++ или C # вы можете комбинировать использование пространств имен и физических каталогов для эмуляции пакетов. Начиная с уровня пакета, архитектура зависит от того, какую систему вы создаете. Для классического корпоративного приложения вам, вероятно, понадобятся слои для разделения технических аспектов и фрагменты, которые прорезают слои для разделения функциональности. Для других типов систем может быть достаточно определить только пару подсистем.

Снимок экрана 2015-06-02 в 14.00.42

Архитектурная модель со слоями и кусочками

Снимок экрана 2015-06-02 в 14.11.11

Архитектурная модель только с подсистемами

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

Возможные соглашения об именах могут быть:

com.company.project.slice.layer…
com.company.project.subsystem…

Для C ++ или C # вы можете достичь того же, используя комбинацию вложенных каталогов и пространств имен.

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

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

Хорошая новость заключается в том, что всегда можно разбить циклические зависимости, используя простые методы программных мастеров, такие как добавление интерфейсов или перестановка классов или методов. Рефкарта DZone № 130  подробно описывает пару техник.

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

Преимущества любви к вашей архитектуре

Если учесть, что от 70 до 80% общей стоимости срока службы типичной программной системы приходится на этап обслуживания, становится очевидным, что упрощение обслуживания сэкономит немало денег. Простота обслуживания напрямую связана с архитектурной целостностью системы и суммой технического долга, накопленного в ней. Минимизируя техническую задолженность с акцентом на архитектурную задолженность и внедряя архитектурный проект в течение всего срока службы системы, можно снизить общую стоимость на 25% и более.

Вот некоторые из преимуществ, которые вы получаете от поддержания вашей архитектуры в чистоте:

  • Изменения гораздо более локальны, и поэтому их легче внедрять и тестировать. Кроме того, вероятность ошибок регрессии значительно снижена, потому что общая связь является умеренной.
  • Легче повторно использовать части системы, потому что они не запутаны с не связанными частями кода.
  • Проще передать систему от команды разработчиков к команде обслуживания, особенно когда изменения могут автоматически проверяться на соответствие архитектуры. Также новым членам команды требуется меньше времени, чтобы стать продуктивным, потому что код легче понять.
  • Становится намного проще защитить систему от уязвимостей. Испорченные данные могут попасть в систему только через четко определенные архитектурные границы. Только те границы должны быть проверены на предмет правильности проверки данных. Эта выгода становится все более и более важной, но часто упускается из виду.
  • Менять архитектуру с классического веб-приложения на веб-сервисы и подобные изменения проще, потому что вся бизнес-логика четко отделена от пользовательского интерфейса и сервисных интерфейсов.
  • Добавление новых функций, исправление ошибок или внесение изменений будет проще и понятнее. Это означает, что типичные показатели разработки, такие как время, необходимое для исправления ошибки или развертывания изменения, значительно улучшатся.

Советы по внедрению автоматических проверок архитектуры

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

Для Java существуют бесплатные инструменты, которые автоматически обнаруживают циклы пакетов, например, JDepend  или  SonarQube . Если вы хотите больше комфорта и умения определять и применять архитектурные чертежи, вам понадобится коммерческий инструмент, такой как  Sonargraph  (бесстыдная вилка).