Рубрики
Без рубрики

Анализ и проверка правил архитектуры программного обеспечения с помощью jQAssistant

Проверяемые правила архитектуры программного обеспечения с помощью neo4j

Автор оригинала: Stefan Fenn.

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

/**
 * Always returns true
 */
public boolean aMethod() {
  return false;
}

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

  • Модули Java или различные проекты Java для разделения слоев.
  • АспектJ и кодовое плетение для перехватчиков методов
  • Собственное расширение стиля проверки
  • Собственный процессор аннотаций
  • jQAssistant с Neo4j

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

Анализ с помощью jQAssistant

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

  • Байтовый код Java с зависимостями и метаинформацией
  • Файлы свойств, pom.xml
  • С помощью плагина можно собрать еще больше информации, такой как таблицы из файлов Excel.

Информация хранится в локальной базе данных графиков Neo4j.

Чтобы показать, что включено в базу данных, мы проанализируем проект Apache Commons Lang.

Подготовьте язык Apache Commons Lang для jQAssistant

Сначала загружается проект

git clone https://github.com/apache/commons-lang.git

После импорта проекта все, что остается, это добавить плагин Maven в файл POM.


 com.buschmais.jqassistant
 jqassistant-maven-plugin
 
   
     
       scan
       analyze
     
     
       MINOR
       MAJOR
     
   
 

После следующей сборки вся информация включается в базу данных графиков. Плагин Maven также можно использовать для запуска с jqassistant:server веб-сервера для Neo4j, который затем доступен по адресу http://localhost:7474/.

Обзор архитектуры с помощником

Например, в разделе классы теперь можно искать все классы “*Utils”.

Например, в разделе классы теперь можно искать все классы

Запрос СООТВЕТСТВУЕТ (n:Класс) ГДЕ n.name ЗАКАНЧИВАЕТСЯ ВОЗВРАЩЕНИЕМ "Utils" n – это специальный язык запросов к БД Cypher, который является аналогом SQL для графических баз данных. Запрос ищет узлы типа “Класс”, свойство “имя” которых заканчивается на “Utils”. Круглые скобки предназначены для обозначения узла.

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

Простые правила архитектуры

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

MATCH 
  p=(c:Class)-[r:DECLARES]->(m:Method) 
WHERE 
  m.cyclomaticComplexity > 50 
RETURN p

Здесь мы ищем соединения узлов, которые могут быть описаны в формате ASCII с помощью (…)-[…]->(…), т. е. С синтаксисом узел-ребро-узел .

Здесь мы ищем соединения узлов, которые могут быть описаны в формате ASCII с помощью (...)-[...]->(...), т. е. С синтаксисом || узел-ребро-узел || .

По-видимому, класс “NumberUtils” содержит два относительно сложных метода boolean isCreatable(java.lang. Строка) и java.lang. Номер createNumber(java.lang. Строка) . Также рассчитывается “эффективное количество строк”, и оба метода превышают 60 строк.

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

MATCH 
  p=(m1)-[:INVOKES]->(m2)-[:INVOKES]->(m3) 
WHERE 
  m1.name = 'toString' AND m3.name = 'toString' 
  AND m1.cyclomaticComplexity>1 AND m2.cyclomaticComplexity>1 
  AND m3.cyclomaticComplexity>1 
RETURN p LIMIT 200

Интересно, что это обнаружило рекурсивный вызов, который в противном случае вы бы сразу не увидели.

Интересно, что это обнаружило рекурсивный вызов, который в противном случае вы бы сразу не увидели.

java.lang. Класс строк toString(java.lang. Класс) здесь вызывается java.lang. Строка в строку(java.lang.reflect. Тип) , который может рекурсивно вызывать другие классы с помощью class toString снова. Вариант StringBuffer или StringBuilder может повысить производительность этих методов.

Циклические зависимости

Чтобы найти циклические структуры пакетов, запрос Cypher намного длиннее, но все еще относительно легко читается.

MATCH
  (a:Artifact),
  (a)-[:CONTAINS]->(p1:Package),
  (a)-[:CONTAINS]->(p2:Package),
  (p1)-[:DEPENDS_ON]->(p2),
  path=shortestPath((p2)-[:DEPENDS_ON*]->(p1))
WHERE 
  p1.fqn <> 'org.apache.commons.lang3' 
  AND p2.fqn <> 'org.apache.commons.lang3'
RETURN
  a.fileName, p1.fqn AS package, 
  extract(p in nodes(path) | p.fqn) AS Cycle
ORDER BY
  package
Чтобы найти циклические структуры пакетов, запрос Cypher намного длиннее, но все еще относительно легко читается.

Этот запрос теперь возвращает в результате не график, а таблицу.

Чтобы определить правила архитектуры, теперь их можно описать с помощью Cypher.

Идеи для дополнительных правил архитектуры

Например, в моих проектах использовались следующие правила:

  • Для каждого класса сущностей в данном пакете существует соответствующий класс и класс сопоставления .
  • Классы из пакета “контроллер” не могут напрямую использовать классы из пакета “сущность”.
  • Служебные классы могут не иметь открытого конструктора и переменных-членов.
  • Методы в перечислениях и классах DTO должны иметь низкий цикломатический индекс.
  • Мы различаем службы, которые “много вычисляют”, и службы, которые “ничего не вычисляют и просто делегируют дальше”. Вычислительные службы не должны использовать какие-либо другие службы. Делегирование услуг должно иметь низкий цикломатический индекс во всех методах.
  • Кодировщик делегирующих паролей должен использоваться в Spring Boot.
  • Количество параметров в методах не должно быть слишком большим.
  • Интерфейсы репозитория JPA не должны содержать методов по умолчанию.
  • Отражение должно использоваться только в пакете утилиты.
  • Методы контроллера должны начинаться с Http-команды.

Интеграция в JUnit

Чтобы получить ограничения на сборку из запросов Cypher, XML-файл хранится в проекте в разделе “jqassistant” для каждого ограничения.



    
        
        All JUnit test classes must have a name with suffix "Test".
        
    

    
        
    

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



    
         
        Labels the root package of the application with "Root".
        
    


Вывод

jQAssistant предлагает хороший способ гибко определять правила архитектуры. Доступно множество плагинов. Подключение новых артефактов проекта к базе данных графиков также возможно без особых усилий. Даже для простых запросов необходимо освоить только синтаксис и семантику Cypher.

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

Оригинал: “https://www.codementor.io/@fennstef/analysis-and-verification-of-software-architecture-rules-using-jqassistant-1h9q0b63gg”