13 августа 2015

Quality Assurance Tools: Паранойя в квадрате или как проверить собственный код на вшивость.

Преамбула

В пылу работы, особенно если могут отвлекать, люди могут забывать очевидные вещи.
Не потому что они плохие или некомпетентные, не потому что мало времени,а просто потому что вот забыли и всего делов.
Особенно больно становится когда твой код на Java, а люди забыли про определение методов equals и hashCode у объектов представляющих собой сущности в домене. toString конечно еще, но с ним чуть больше нюансов - современные IDE предоставляют хорошую интроспекцию объектов в дебаге, поэтому найти то, что toString продолбан чаще всего получается уже в логах с прода, где он не дает никакой информации.

А вот с equals и hashCode все веселее и проще - они иногда приводят к дням веселой отладки в попытках понять что же происходит.

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


И я решил что нужно попробовать сделать хоть какой-то инструмент для борьбы с этой проблемой.


Почему не статический анализ кода? 

Инструмент для обнаружения проблемы можно построить и не с нуля, используя средства статического анализа кода типа findbugz, checkstyle, pmd.
Все они предоставляют возможность расширения набора правил анализа, и все они open-source.
И все они обладают избыточным набором правил анализа на все случаи жизни, который можно и приходится настраивать.
И ни один из указанных инструментов не может проверить нужные мне условия прямо из коробки.
И самое главное - редко когда и мало кто ставит этот статический анализ кода в таком месте своего жизненного цикла разработки так чтобы он прерывал сборку проекта.
Мне же хотелось иметь средство, которое по умолчанию будет останавливать сборку проекта.

Почему именно так ? 

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

Идея решения проста - в процессе написания кода нужно поставить одну аннотацию, остальное компилятор при помощи процессоров аннотаций сделает сам.
Естественно процессор аннотации нужно написать, естественно аннотацию нужно повесить на класс, и если этого не сделать, то никакой процессинг не сработает.
Но аннотацию нужно поставить одну, а методов про которые нужно не забыть  - три, так что уже выигрываем.
Аннотаций я пока реализовал две:
@Pojo - проверяет что у класса определены  equals, hashCode, toString
@Helper - проверяет что класс соотвествует идее хэлпера (все методы статические, конструктор приватный, все поля константы, никакого состояния иметь не должен).

В натуре

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

При попытке компиляции тестового проекта вы увидите вот такую вот своершенно неизящный вывод в консоли.

Для тех кто не поленится сходить и почитать код сразу предупреждение - там есть говнокод, особенно в местах  по анализу и сравнению типов возвращаемых методами.  Сделано отвратительно, самому не нравится, но пока живет.  Как исправлю - обязательно выложу.


Мысли по ходу.

Мыслей в связи с этим вот pet project у меня накопилось больше, чем сам проект.

  1. Казалось бы фундаментальнейшая и низкоуровнвая вещь, такая как процессор аннотаций, должна быть вылизана, задокументирована и спроектирована очень хорошо. Но вот с документацией вообще швах.
  2. Информации и примеров того как это делать правильно в интернете не очень много. Свою подборку ссылок приведу в конце.
  3. Я не нашел ни одного вменяемого метода для тестирования этих процессоров аннотаций, кроме как создать отдельный проект в котором эти самые аннотации будут развешаны на классах дающих нужные кейсы.(смотри апдейт ниже) В мыслях крутиться использования инфраструктуры для тестирования плагинов к maven, но этот ад мы прибережем для следующей серии нашей мыльной оперы.
  4. Если отбросить лично мои заморочки и скомбинировать подход с построением AST, то анализатор может получится весьма и весьма мощный.
  5. Сразу нужно думать про нормальный репортинг, посколько API процессора аннотаций ничего кроме как минималистичного вывода в консоль делать не дает. То есть проанализировать код, найти плохое место в нем вы конечно можете но вот отрапортовать об этом будет сложно. Нужно писать что-то сбоку.
  6. Чтобы вся эта радость нормально работала библиотеку с аннотациями и процессорами нужно подключать к мавену в scope = provided. Так и только так!!! Иначе зависимость на аннотации и анализатор полезет дальше транзитивно, а мы помним что это всего лишь инструмент, не более того.


Ссылки

  1. Пост на хабре вдохновивший меня сделать это.
  2. Туториал по похожему кейсу.
  3. Фундаментальная статей про процессинг аннотаций в Java. Все разжевано и разложено по полочкам.
  4. Еще один хороший туториал в трех частяхпостах (раз, два, три)


UPD 22.11.2016 В процессе археологических раскопок кургана Гитхаб наша экспедиция нашла древний артефакт для тестирования кода процессоров. Подключили, попробовали - работает!