Статьи

Apache Hadoop: сокращение технического долга за счет рефакторинга

Технический долг ничего не стоит, если в коде не предпринимаются прагматические действия для его контроля и решения. Чтобы проиллюстрировать возможность автоматического исправления дефектов кода, которые увеличивают эту непреднамеренную задолженность, мы провели рефакторинг кода для двух подпроектов проекта Hadoop : Hadoop Common и Hadoop Mapreduce. Благодаря Scertify мы смогли исправить дефекты 25K за 2 минуты. Другими словами, 14% технической задолженности было списано без каких-либо человеческих усилий.

Начальный анализ

Согласно Википедии , Apache Hadoop является «программной средой с открытым исходным кодом, которая поддерживает распределенные приложения с интенсивным использованием данных». Эта структура содержит несколько проектов, Common и Mapreduce — два важных проекта с кодами соответственно 120K и 162K (за исключением пустых строк и комментариев). Версия, с которой мы работали, является последней версией разработки: 3.0.0-SNAPSHOT. Мы запустили Scertify Refactoring Assessment , наш плагин с открытым исходным кодом для Sonar, над проектами, чтобы получить представление об их технической задолженности.

Технический долг определяется как количество времени, необходимое для исправления всех обнаруженных дефектов. Как вы можете видеть на скриншотах ниже, у Common есть технический долг 70 дней, а Mapreduce — 66 дней. Scertify Refactoring Assessment также рассчитывает потенциал автоматической коррекции технического долга: списание долга. Они оба имеют хороший потенциал для автоматического рефакторинга, соответственно 38 и 36 дней. Итак, следующий шаг — использовать  Scertify   для выполнения этого автоматического рефакторинга.
Кстати, если вы хотите попробовать его с собственным исходным кодом, руководство по  установке и использованию Scertify доступно здесь .

 

Hadoop Common Original TechdebtHadoop Mapreduce Original Технический долг

Мы прокрутили различные ошибки и выбрали 8 правил для демонстрации.

Правила рефакторинга для демонстрации

Вот презентация правил рефакторинга, которые мы использовали в этой демонстрации. Как видите, некоторым правилам нужны параметры, чтобы быть эффективными. Это случай правил, касающихся ведения журнала. Инфраструктура ведения журналов, используемая в этих проектах, называется Apache Common logging, поэтому мы настроили правила для ее использования.

AvoidPrintStackTrace

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

Оригинальный код:

catch (Exception e) {
      e.printStackTrace();
      throw new IOException("Cannot initialize the class: " + clazz);
}

Рефакторированный код:

catch (final Exception e) {
      LOG.error(e.getMessage(), e);
      throw new IOException("Cannot initialize the class: " + clazz);
}

В этом случае LOG не был объявлен, поэтому он был добавлен в класс и был выполнен импорт:

private static final Log LOG = LogFactory.getLog(GenericWritable.class);

InefficientConstructorCall

Вызов конструктора типа оболочки, такого как Integer, для преобразования примитивного типа — плохая практика. Это менее эффективно, чем вызов статического метода valueOf.

PositionLiteralsFirstInComparisonsRefactor

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

AddEmptyStringToConvert

Использование конкатенации пустой строки для преобразования примитивного типа в строку является плохой практикой. Прежде всего, это делает код менее читабельным. Он также менее эффективен в большинстве случаев (единственный случай, когда конкатенация строк немного лучше, это когда примитив окончательный). Вот пример, взятый из класса MD5MD5CRC32FileChecksum.
Оригинальный код:

xml.attribute("bytesPerCRC", "" + that.bytesPerCRC);

Рефакторированный код:

xml.attribute("bytesPerCRC", String.valueOf(that.bytesPerCRC));

GuardDebugLogging

Когда конкатенация String выполняется внутри журнала отладки, необходимо проверить, включена ли отладка, перед выполнением вызова. В противном случае конкатенация String всегда будет выполняться. Рефакторинг добавляет охрану перед вызовом для отладки. В этом случае он настроен на использование метода isDebugEnabled (), поскольку мы используем журнал Apache. Ниже приведен пример измененного кода, взятого из класса ActiveStandByElector:

if(LOG.isDebugEnabled()){
        LOG.debug("StatNode result: " + rc + " for path: " + path + " connectionState: " + zkConnectionState + " for " + this);
}

IfElseStmtsMustUseBraces

Это правило находит операторы if, которые не используют фигурные скобки. Рефакторинг добавляет необходимые скобки.

UseCollectionIsEmpty

Это правило находит использование метода размера Collection, чтобы проверить, является ли коллекция пустой. Вместо того, чтобы использовать size (), лучше использовать isEmpty (), чтобы сделать код более легким для чтения. Рефакторинг заменяет сравнения между размером и 0 вызовом isEmpty ().

LocalVariableCouldBeFinal

Этот метод отмечает локальные переменные, которые могут быть объявлены как final и не являются. Использование ключевого слова final — полезная информация для будущих читателей кода. Рефакторинг добавляет «окончательный» ключ. Это не критичное правило, но поскольку в нем огромное количество нарушений, полезно быстро избавиться от них с помощью автоматического рефакторинга. 

Рефакторинг результатов

Поэтому мы запустили Scertify в обоих проектах, чтобы обнаружить и изменить эти правила. На каждый проект уходит около 1 минуты, чтобы выполнить весь процесс. Scertify генерирует HTML-отчет с информацией об обнаруженных и исправленных ошибках. Ниже приводится сводка всех ошибок, исправленных в двух проектах. Многие мелкие вещи были исправлены, но и более важные. В целом, исправление 25392 дефектов заняло 2 минуты . Не так плохо, не так ли? Эти дефекты включают как незначительные нарушения, так и более критические нарушения с точки зрения ремонтопригодности, производительности или надежности.

Нарушения рефакторированы

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

Рефакторированный общий технический долгРефакторированный Mapreduce технический долг

И последнее, но не менее важное: Hadoop содержит множество модульных тестов, и, конечно же, мы позаботились о том, чтобы они были успешными после рефакторинга. В заключение, благодаря функциям рефакторинга Scertify мы смогли эффективно исправить дефекты 25K за несколько минут. Мы рады сделать переработанный код доступным для сообщества, вы можете скачать его ниже. Мы продолжим проводить такой рефакторинг в приложениях с открытым исходным кодом, поэтому, если у вас есть идея для проекта с открытым исходным кодом, который может использовать такой рефакторинг, просто дайте нам знать!


Скачать исходные файлы