Недавно вышла новая версия библиотеки RefactorFirst 0.4.0, которая позволяет определять и визуализировать технический долг. С этой информацией можно пойти к своему тимлиду или продукт-оунеру и выбить время на рефакторинг, имея под руками железные доказательства.
Она ищет в Java-коде Божественные Классы и классы с очень высоким уровнем связности, которые следовало бы отрефакторить. Для этого используются правила God Class Rule и Coupling Between Objects Rule из опенсорсного коданализатора PMD.
Коротко опишу, что это такое, и как этим пользоваться.
Как выглядит результат
Код генерирует подобные диаграммы:
Что он обрабатывает?
Библиотека анализирует код проектов Maven (и Gradle, с небольшим хаком, описанным ниже). Мультимодульные проекты тоже поддерживаются.
Инструмент работает на основе исследования "Prioritizing Design Debt Investment Opportunities" (Zazworka, Seaman, Shull). Презентации, основанные на этой работе, выложены по ссылке. Не то, чтобы эти презентации были супер информативными, но передают дух исследования.
Проект связан с кодом опенсорсного коданализатора PMD и изменяется вместе с ним.
Где взять
Библиотека лежит на GitHub в репозитории jimbethancourt/RefactorFirst и имеет собранный билд в Maven Central.
Несмотря на то, что это работа практически одного человека (другие контрибьюторы есть, но их вклад минимален), работа эта ведется на протяжении нескольких лет. Библиотека собрала около двух сотен коммитов, десятки форков и сотни звёзд.
Как пользоваться в командной строке
Нужно выполнить команду Maven в корне репозитория. Собирать исходники предварительно - не обязательно.
mvn org.hjug.refactorfirst.plugin:refactor-first-maven-plugin:0.4.0:report
Проект Maven
Нужно добавить кусок копипасты в раздел <build>
. При указании параметра showDetails
, генерируется таблица с подробными значениями метрик.
<build>
<plugins>
...
<plugin>
<groupId>org.hjug.refactorfirst.plugin</groupId>
<artifactId>refactor-first-maven-plugin</artifactId>
<version>0.4.0</version>
<!-- optional -->
<configuration>
<showDetails>true</showDetails>
</configuration>
</plugin>
...
</plugins>
</build>
Анекдот про секцию Reporting в Maven
При чтении доументации, я наступил в описание фичи, которая звучит как анкедот.
Раньше можно было весь тот же конфиг, что и выше, указать в секции Reporting в pom.xml. Но репорты генерятся с помощью Doxia Site Renderer, который транзитивно зависит от бажной Velocity 1.7. Автор испугался выпилил всю генерацию отчётов начисто.
Речь идёт о баге CVE-2020-13936 в Apache Velocity. Если коротко, есть у атакующего есть способ изменять шаблоны Velocity, то он может выполнять произвольный код с правами пользователя, от которого делается разбор шаблонов. Эта проблема сохраняется вплоть до Velocity 2.2.
Живое напоминание того, что библиотеки в Java не просто уязвимы и смертны, а внезапно уязвимы и внезапно смертны.
Проект Gradle
Сам по себе Gradle не поддерживается. Но есть быстрый способ обхода: нужно создать минимальный POM-файл, и всё заработает само.
Просто положить в корень проекта что-то вроде:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
Потом установить Maven (хотя, какой пользователь Gradle не имеет установленного Maven?) и выполнить стандартную строчку:
mvn org.hjug.refactorfirst.plugin:refactor-first-maven-plugin:0.4.0:report
Как посмотреть отчёт
Как только плагин закончит работать (а он может работать часами напролёт на больших кодовых базах), нужно открыть файл target/site/refactor-first-report.html
(путь дан относительно корня проекта). В этом файле будет диаграмма, похожая на картинку сверху, и таблица с перечислением Божественных Классов, в том порядке, в котором их стоит рефакторить. Класс, расположенный на диаграмме слева наверху - наиболее прост для рефакторинга, и одновременно окажет наибольшее влияние на продуктивность команды (по крайней мере, такова идея).
Если в проекте будут замечены сильно связанные классы, то для них сгенерируется отдельная табличка.
У меня есть отчёт. Что дальше?
Дальше нужно пойти к своему тимлиду, или хозяину проекта, или еще кому-то, кто принимает решение о рефакторинге технического долга. Вместе с ним нужно сесть и приоритизировать всё, что вы нашли. Если это какой-то человек, который далёк от написания кода в проект, стоит заранее подготовиться к разговору и придумать объяснения, почему тот или иной рефакторинг позитивно скажется на продуктивности команды.
Если у вас есть IntelliJ IDEA, то можно использовать плагин Java Method Reference Diagram от Стефана Зеллера, с помощью которого можно начать разбираться с порядком рефакторинга.
Будущее проекта
Проект пилится буквально в одного человека, поэтому он готов принять любую помощь. Сейчас он хочет работать над следующим списком вещей:
Определение и приоритизация циклов в графе классов
Создание плагина для Gradle
Добавление метрик, собранных в результате юнит-тестирования, чтобы понять, насколько безопасны рефакторинги
Добавить счётчик багов в вычисление оси Y (ось вклада)
Добавить больше метрик из работы Object Oriented Metrics In Practice (Lanza, Marinescu, 2004)
Минутка рекламы. Если вы рефакторите адское легаси в российском проекте, то вам может очень помочь Axiom JDK, на котором это легаси запускается. Команда Axiom JDK - это одна из немногих компаний в мире, поддерживающая все главные версии Java, включая legacy-версии Java 6 и Java 7. Шестерку и семерку нельзя скачать на сайте, но можно попросить у саппорта по почте.
Если хотите больше таких новостей, подписывайтесь на мой Telegram-канал JavaWatch, и заходи в мой бар Failover Bar (у него тоже есть чат и канал).
novoselov
Если в проекте есть parent pom и модули, то плагин не работает.
Запускается только на parent, а все модули пропускает, т.к. директория проекта должна совпадать с git директорией
faceplam
SimSonic
Аналогично, не смог победить. Особенно проблема, если корневая помка в подпапке. Issue открыт несколько лет.
Вроде это обошёл новой фейковой помкой в корне, но столкнулся с отсутствием поддержки --enable-preview фич. Завел Issue.