Введение

Сегодня в любой более-менее серьезной компании, где настроен CI/CD, используется SonarQube. Это уже стандарт де-факто. Он умеет определять code smells, дублирование, уровень покрытия тестами, распознавать недостижимый код и многое другое. Настроили, подключили к CI — и вроде бы все хорошо.

Но...

Иногда SonarQube оказывается недостаточно злым. Он легко пропускает:

  • классы с кучей скрытых зависимостей

  • запутанную бизнес-логику, размазанную по методам

  • высокий coupling при почти идеальных метриках на дашборде

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

Для таких случаев есть инструменты другого уровня. Не про стилистику и правила, а про архитектурную сложность. Один из таких инструментов — jpeek. Он не заменяет линтер, не ругается на System.out.println() и не просит добавить javadoc. Зато он умеет в цифрах показать насколько код близок к объектно-ориентированному аду.

Про jpeek

Как было упомянуто ранее, jpeek — это инструмент для анализа Java-кода, разработанный с акцентом на оценку архитектурной сложности и структурной связности классов. В отличие от линтеров и статических анализаторов, jpeek фокусируется на объектно-ориентированных метриках, таких как сцепленность (cohesion) и связность (coupling), предоставляя разработчикам более глубокое понимание качества архитектуры их кода.

Основной контрибьютор jpeek – Егор Бугаенко. Сам узнал о jpeek после его курса Software Quality Metrics (SQM Crash Course).

Метрики jpeek

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

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

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

Аналоги

Существуют и другие инструменты, предлагающие анализ архитектурных метрик:

  • CodeMR — плагин для IntelliJ IDEA, предоставляющий визуализацию метрик, таких как LCOM3, CAMC, LCAM и др.

  • SQMetrics — учебный проект для оценки качества Java-кода с учетом метрик NOC, LLOC, LCOM и др.

  • JProbe — очень древний анализатор (преимущественно для Java EE проектов)

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

Пример работы

Для демонстрации я взял небольшой Java-проект — jcabi-http, библиотеку с теми же контрибьюторами, что и jpeek. Проект простой, но с интересной структурой классов, что как раз подходит под анализ архитектуры.

Чтобы подключить jpeek, можно добавить maven-plugin в pom.xml:

<build>
  <plugins>
    <plugin>
      <groupId>org.jpeek</groupId>
      <artifactId>jpeek-maven-plugin</artifactId>
      <version>1.0.0</version>
      <executions>
        <execution>
          <goals>
            <goal>analyze</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Запускаем:

mvn clean compile jpeek:analyze

После выполнения плагина в папке target/jpeek появятся отчеты — один HTML-файл и один XML-файл на каждую метрику. Также сгенерируется index.htmlindex.xml) со ссылками на все метрики.

Главная страница HTML-отчета
Главная страница HTML-отчета
HTML-отчет по метрике CCM
HTML-отчет по метрике CCM

XML-отчет по метрике CCM выглядит следующим образом:

<package element="false" id="com.jcabi.http.response">
     <class color="red"
            element="true"
            id="JsonResponse$VerboseReader"
            value="0.25">
        <vars>
           <var id="methods">4</var>
           <var id="nc">6</var>
           <var id="ncc">4</var>
           <var id="nmp">6</var>
        </vars>
     </class>
     ...
</package>

Из отчета видно, что для внутреннего класса JsonResponse.VerboseReader значение CCM=0.25, что говорит о том, что методы класса тривиальны (без условий и ветвлений). В блоке vars содержится следующая информация:

Параметр

Расшифровка

methods

количество методов в классе

nc

количество вызовов между методами

ncc

количество связанных пар методов

nmp

всего возможных пар методов

Настройка CI

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

У меня когда-нибудь обязательно дойдут руки написать удобный валидатор для jpeek. Но пока можно обойтись простым питоновским скриптом вида:

import xml.etree.ElementTree as ET
import sys

# Пороговые значения метрик (определяются эмпирически для проекта)
thresholds = {
    'SCOM': 0.5,
    'LCOM2': 0.3,
    'CCM': 0.4  #  можно добавить еще метрик
}

report_path = 'target/jpeek/index.xml'

try:
    tree = ET.parse(report_path)
    root = tree.getroot()
except Exception as e:
    print(f"Can't read jpeek report: {e}")
    sys.exit(1)

for metric_name, max_defect in thresholds.items():
    metric = next((m for m in root.findall('metric') if m.get('name') == metric_name), None)
    if not metric:
        print(f"Can't find {metric_name} in report")
        continue

    try:
        defects = float(metric.get('defects', '0'))
    except ValueError:
        print(f"Invalid defects value for {metric_name}")
        continue

    print(f"{metric_name}: defects = {defects}; maximum value = {max_defect})")
    if defects > max_defect:
        print(f"{metric_name} validation failed")
        sys.exit(1)

print("jpeek validation passed successfull")

И дальше из CI можно вызвать:

python3 validate_jpeek.py

Заключение

SonarQube — отличная штука. Он действительно закрывает 90% проверок по качеству кода, распознавая возможные NPE, уязвимости и дублирование кода. Но если хочется получить более подробные и научно обоснованные отчеты, то без метрик вроде LCOM, CAMC или SCOM уже не обойтись.

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

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

Лично я после знакомства с jpeek стал смотреть на архитектуру классов иначе. Попробуйте — это действительно стоит внимания.

Комментарии (5)


  1. moyantianwang
    01.06.2025 07:21

    Admiration arises despite my incomprehension of what you said. 


  1. fcoder
    01.06.2025 07:21

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


    1. galua Автор
      01.06.2025 07:21

      Сонар платный, а значит в нем есть поддержка, а энтерпрайзы такое любят.

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


      1. danilovmy
        01.06.2025 07:21

        Сонар знаю изнутри. Метрика cognitive complexity - https://www.sonarsource.com/blog/cognitive-complexity-because-testability-understandability/, там в середине ссылка на пдф с объяснением метрики.

        Остальные метрики построены в основном на бесплатном Radon, можно идти по правилам проекта и читать, если есть описание метрики, плюс что то есть в их блоге.

        По поводу энтерпрайза - у них очень "авторитетный" сейлз Peter McKee с весомым опытом в докере. Я знаю его лично, он классно умеет пугать. В Америке с этим попроще - если приходит авторитет и говорит что все плохо, они верят. Удивительно как это отлично работает для энтерпрайза. Не инфа важна, а тот кто её говорит. :(

        P. S. Я позавчера делал доклад на PyCon IT про замеры сложности в Python проектах. Я сам часто самописными скриптами пользуюсь.


      1. trukhachev
        01.06.2025 07:21

        Sonar используем года с 19 примерно, вполне удобное решение, помогает не допускать глупые ошибки и опечатки, он просто часть процесса проверки кода. Мы не разрешаем отправлять код на ревью, если разработчик не "вычистил" после сонара. Просто чтобы не тратить время ревьюера на очевидные проблемы.

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

        Плюс удобно видеть и контролировать уровень покрытия кода тестами по всем проектам на разных языках в одном месте