Запахи кода возникают на всех уровнях детализации. Мы можем классифицировать запахи в зависимости от их масштаба и воздействия. В частности, запахи, возникающие в локальной области видимости, обычно внутри метода, могут называться запахами реализации (например, пустой блок catch или магическое число). Запахи, включающие свойства класса и область воздействия, включают набор классов, тогда они называются запахами дизайна (например, класс бога и многогранная абстракция). Запахи, возникающие на самом высоком уровне детализации, когда мы наблюдаем за свойствами компонентов (пакетов/пространств имен) и их влиянием на всю систему, называются архитектурными запахами (такими как божественный компонент и плотный компонент). структуру).

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

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

Запахи архитектуры

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

  • Неоднозначный интерфейс. Этот запах возникает, когда компонент предлагает только одну общую точку входа в компонент.
  • Циклическая зависимость. Этот запах возникает, когда два или более компонентов архитектуры прямо или косвенно зависят друг от друга.
  • Плотная структура. Этот запах возникает, когда компоненты имеют чрезмерные и плотные зависимости без какой-либо определенной структуры.
  • Концентрация функций. Этот запах возникает, когда компонент реализует более одной архитектурной задачи/функции.
  • Божественный компонент. Этот запах возникает, когда компонент слишком велик либо с точки зрения LOC, либо с точки зрения количества классов.
  • Рассеянная функциональность. Этот запах возникает, когда несколько компонентов отвечают за реализацию одной и той же задачи высокого уровня.
  • Нестабильная зависимость. Этот запах возникает, когда компонент зависит от других компонентов, которые менее стабильны, чем он сам.

Давайте возьмем проект с открытым исходным кодом, чтобы проанализировать и увидеть несколько примеров архитектурных запахов. Мы проанализировали последнюю версию Дженкинса с помощью DesigniteJava Enterprise. Анализируемая версия Jenkins содержит 203 тысячи LOC.

Мы обнаружили много примеров запаха архитектуры божественного компонента. Большой компонент трудно понять и, следовательно, сложнее поддерживать. Многие такие случаи снижают ремонтопригодность проекта. Один из экземпляров, указанных в пакете hudson.model; этот пакет содержит 646 классов и всего 56 710 LOC.

Инструмент также сообщает о запахе циклической зависимости. Этот экземпляр содержит длинную цепочку зависимостей, образующих длинный клубок. Задействованные компоненты: hudson.init, hudson.util, hudson, jenkins.util.io, hudson.model, jenkins.model, hudson.security, hudson.model.queue, jenkins.security, hudson.tasks, hudson.model.listeners, hudson.security.captcha, hudson.diagnosis, jenkins.util, jenkins.model.lazy, hudson.widgets, hudson.scm, hudson.util.io, jenkins, hudson.slaves, jenkins.slaves, hudson.node_monitors, hudson.console, jenkins.security.apitoken. Важно понимать, что единичные циклы (два компонента зависят друг от друга) сравнительно легче обнаружить человеческому глазу. Однако циклы длиной 3 и более незаметно скрыты в вашем коде, и вам нужна поддержка инструментов, помогающих выявить такие экземпляры.

Архитектурный запах концентрации функций возникает, когда компонент реализует более одной архитектурной задачи/функции. Другими словами, компонент не связан. Подобно LCOM (отсутствие связности методов), применяемому к классам, DesigniteJava вычисляет LCC (отсутствие связности компонентов) для измерения связности компонентов. Пакет jenkins.util.io страдает от этого запаха, где расчетный LCC равен 0,7. Независимые наборы связанных классов внутри этого компонента: [PathRemoverTest, FileLockerRule, PathRemover, PathChecker], [FileBoolean], [LinesStream], [CompositeIOException], [RetryStrategy], [PausingGCRetryStrategy], [OnMaster].

Рассеянная функциональность указывает на то, что два или более пространств имен реализуют одну и ту же архитектурную задачу (что-то вроде противоположного запаху концентрации функций). DesigniteJava проверяет доступ к внешним пространствам имен, которые встречаются вместе с методом. Если такие обращения происходят в компоненте много раз, это приводит к запаху архитектуры рассеянной функциональности в компонентах, к которым осуществляется доступ. Один из 18 примеров в проанализированном коде показывает, что hudson.model и jenkins.model часто используются вместе и реализуют схожую функциональность.

Последний пример архитектурного запаха относится к плотной структуре. Этот запах возникает, когда все компоненты образуют очень плотный граф зависимостей. Таким образом, за анализ может произойти не более одного экземпляра. DesigniteJava формирует граф зависимостей среди всех пакетов и вычисляет среднюю степень графа. Для проанализированной версии кода Jenkins инструмент сообщил о средней степени = 9,02, что означает, что каждый компонент в среднем связан более чем с 9 другими компонентами, что довольно много. Это указывает на то, что связь между компонентами высока, и необходимо приложить усилия для ее уменьшения.

Анализ эволюции качества архитектуры

Мы разрабатываем служебную программу на Python для анализа нескольких версий проекта Java и обнаружения архитектурных запахов с помощью DesigniteJava. Эта служебная программа использует аналитические отчеты, сгенерированные DesigniteJava, а затем создает данные эволюции (LOC и количество архитектурных запахов в каждой версии) и графики (плотность архитектурных запахов, распределение архитектурных запахов по версиям и структуру зависимостей компонентов) для представления эволюции. Эта служебная программа имеет открытый исходный код, и вы можете использовать ее для наблюдения за эволюцией качества архитектуры ваших Java-проектов.



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

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

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

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

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

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

Вперед, продолжать. Если у вас есть проект Java, вы можете использовать эту утилиту с открытым исходным кодом вместе с DesigniteJava Enterprise, чтобы понять качественные характеристики архитектуры вашего программного обеспечения.