Введение
Сегодня в любой более-менее серьезной компании, где настроен 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 реализует широкий набор метрик, основанных на научных исследованиях и публикациях в области программной инженерии. Вот некоторые из них:
LCOM (Lack of Cohesion in Methods) — связность методов внутри класса
TCC (Tight Class Cohesion) и LCC (Loose Class Cohesion) — степень связности классов
CAMC (Cohesion Among Methods of Class) — степень пересечения списков типов параметров отдельных методов со списком типов всех методов в классе
MMAC (Method-Method through Attributes Cohesion) — средняя связность всех пар методов в программе на основе анализа типов параметров и возвращаемых значений
В отличие от 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.html
(и index.xml
) со ссылками на все метрики.


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
содержится следующая информация:
Параметр |
Расшифровка |
|
количество методов в классе |
|
количество вызовов между методами |
|
количество связанных пар методов |
|
всего возможных пар методов |
Настройка 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)
fcoder
01.06.2025 07:21Вижу sonar только в энтерпрайзах, при этом ни удобным ни хорошим его назвать не могу. Толи у них маркетинг хороший толи сертификация какая-то необходимая по-закону
galua Автор
01.06.2025 07:21Сонар платный, а значит в нем есть поддержка, а энтерпрайзы такое любят.
Насчет сертификации не знаю, но как сонар считает метрики я не нашел (возможно плохо искал). Для сертификации, полагаю, процесс подсчета должен быть более прозрачным
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 проектах. Я сам часто самописными скриптами пользуюсь.
trukhachev
01.06.2025 07:21Sonar используем года с 19 примерно, вполне удобное решение, помогает не допускать глупые ошибки и опечатки, он просто часть процесса проверки кода. Мы не разрешаем отправлять код на ревью, если разработчик не "вычистил" после сонара. Просто чтобы не тратить время ревьюера на очевидные проблемы.
Важно понимать, что какие-то правила можно отключать, если они не подходят вашему проекту или команде, а так же писать свои (не то чтобы легко, но можно и мы так делаем).
Плюс удобно видеть и контролировать уровень покрытия кода тестами по всем проектам на разных языках в одном месте
moyantianwang
Admiration arises despite my incomprehension of what you said.