Данный цикл статей я планирую, как историю в нескольких частях о том, как настраивается автоматическая проверка качества кода в нашем проекте. Процесс этот, вроде бы простой, оказался полным неочевидных деталей, так что появилось желание разъяснить подстерегаютщие трудности и их решения широкой аудитории, чтобы все могли сделать свой код чуть лучше, обойдя побольше грабель.
В итоге хочется добиться того, чтобы инспекции, проверка стилей, и вычисление метрик гонялись на сборочном сервере, тогда всем будет понятно в каком состоянии находится проект. Причём, в идеале, все те проверки, которые срабатывают на сервере должны срабатывать и в IDE, чтобы замечания к своему коду можно было устранять до того, как о них узнает вся команда. По мере совершенствования подходов, итерации будут дописываться и публиковаться.
В этой итерации, я буду настраивать проверку инспекций. Мы всей командой используем IntelliJ IDEA и TeamCity компании JetBrains, поэтому можно использовать те средства, которые они предоставляют. Для начала в IntelliJ IDEA будет настроен профиль инспекций, соответствие кода которому будет проверяться при каждой сборке при помощи TeamCity. Метод это штатный и описан в официальной базе знаний по TeamCity, но не всё получалось очень гладко…
Для начала надо определиться, что же проверять, для этого запустим IntelliJ IDEA, откроем проект и найдём настройки (Settings). Теперь перейдём в раздел инспекции (Inspections), для чего удобно воспользоваться поиском. В результате перед вами предстанет такая картина — полный список инспекций, разделённый по группам (синим выделены инспекции, настройки которых отличаются от стандартных):
Тут большое поле для творчества: каждой инспекции можно сопоставить серьёзность, с которой она будет оцениваться. Простое включение всех инспекций не заставит писать код идеально без включения мозга. Инспекции только дадут почувствовать плохие запахи раньше. Так существуют абсолютно противоположные инспекции, например, «Constant on left side of comparison» и «Constant on right side of comparison». Выбор тут зависит от ваших предпочтений и от тех стандартов, которые вы собираетесь поддерживать. Инспекций действительно очень много, полный проход займёт несколько часов, так что не забудьте запастись хорошим чаем.
Из полезных примечательных инспекций:
- I/O resource opened but not safely closed — позволит проверить, что для всех открытых ресурсов вызывается close и притом в нужном месте (аналогично с JDBC, JNDI и nio);
- Missing Override annotation — я пофорсил жёстко, чтобы обрабатывалось как ошибка, потому что этими самыми ошибками и чревато (недаром в Scala для подобной декларации используется обязательное ключевое слово);
- Iteration over 'keySet()' may be replaced with 'entrySet()' iteration — как ни странно немногие задумываются, что второй способ быстрее и вообще существует;
- Chain of 'instanceof' checks — позволяет намекнуть злостным нарушителям LSP, что можно жить
по-другому ; - Overly long method, Class with too many methods — позволяют следить, что методы и классы вовремя разбиваются и помещаются на разумном числе экранов.
Можно импортировать сохранённый профиль другим участникам команды через опцию Import, чтобы проверки работали у всей команды одинаково. Правда при каждом изменении профиля, команде придётся делать импорт заново, поскольку изменения экспортированного файла не отслеживаются автоматически.
Итак, мы перешли к настройке TeamCity. TeamCity позволяет собирать проект большим количеством разных способов. Для разных способов используются т.н. Runners: Maven, Ant и ещё около десятка. В их числе есть специальный — Inspections Runner. Для того, чтобы его использовать, надо создать отдельную конфигурацию сборки (Configuration) или добавить шаг (Build step) к существующей. На рисунке ниже показана заполненная форма для этого шага:
У нас
Ещё один интересный момент: потребление памяти. Без увеличения стандартного максимально выделяемого размера памяти и размера Permanent Generation, проверка инспекций будет падать. В новых версиях TeamCity, например, в установленной у нас 6.5.6 в поле JVM command line parameters заранее вписано:
-Xmx512m -XX:MaxPermSize=150m
В том же поле можно заставить TeamCity проверять или не проверять определённые пакеты, например, не очень интересно смотреть, какие претензии есть к стабам, сгенерированным для работы с
-Didea.include.patterns=src/main/java/ru/tcsbank/portal/*
Следующий пункт — путь к нашему
%system.teamcity.build.checkoutDir%/tcsInspectionsProfile.xml
Теперь осталось указать только название профиля, которое мы задали при сохранении в IDEA и количество предупреждений и ошибок, которые мы считаем смертельными — при которых, проект перестаёт собираться.
Изначально, я брал количество чуть большее, чем общее число непройденных проверок, затем, по мере улучшения качества кода, это количество уменьшалось и продолжает уменьшаться.
Итак, запускаем нашу сборку и видим,
Что же, теперь мы всегда знаем улучшил ли коммит качество кода или ухудшил.
В завершение хочется сказать, что TeamCity скорее предназначается для сборки проектов IntelliJ IDEA, чем Maven, это несёт ряд ограничений: не проверяются стили кода, вдобавок к Maven загружается экземпляр IDEA на сервере (при сборке пробегает строка «Starting up IntelliJ IDEA 10.5.2…») и ещё… Inspection Runner странно себя ведёт на некоторых типах инспекций, например был случай, когда «Unused import» считал неиспользуемым класс, который использовался для создания анонимного наследника. Такие инспекции, к большому сожалению, пришлось отключить, чтобы не компрометировать правильность проверки.
Последующий выбор инспекций можно проводить вместе с командой по методу
В следующей итерации я планирую попробовать использовать «IntelliJ IDEA Project» runner, есть надежда, что это позволит сборке проходить побыстрее и исправит проблемы с точностью инспекций и позволит отказаться от постоянных reimport’ов профиля инспекций.