Pull to refresh

Анализаторы Roslyn: повадки и места обитания

Reading time 3 min
Views 4.5K
На днях объяснял одному товарищу что такое анализаторы Roslyn и как их писать. Ответ получился массивным, и я решил вынести его в отдельную публикацию.

Что такое анализаторы Roslyn? Если коротко — это отличный способ писать рефакторинги вроде Решарперовских. Постоянно встречаете одну и ту же ошибку в процессе ревью? Напишете анализатор с фиксером и забудьте про эту ошибку. Техническая сторона довольно проста, для первоначального знакомства отлично подойдут вот эта статья, вот это видео, вот эта серия постов, и вот этот туториал. Я же попытаюсь описать грабли моменты, которые лично у меня вызывали затруднение.

Первое — это Syntax Vizualizer. Любой анализатор содержит парсинг синтаксического дерева. Типичная задача — есть узел и надо отыскать его предка с типом «Объявление класса», или «найти все узлы объявления методов в которых используются строковые литералы». Синтаксическое дерево может быть с десятком уровней вложенности, и для его анализа хотелось бы заиметь визуализацию. Два популярных инструмента: Syntax Vizualizer и LINQPad. Первый идет по дефолту, выдает тонну технической информации по каждому узлу, и значительно тормозит на моем компьютере. Плюс, когда я набираю код анализатора Syntax Vizualizer начинает визуализировать непосредственно печатаемый код, что сбивает с толку. LINQPad дает чуть меньше информации, но зато красивее и нагляднее, так что рекомендую.

Следующий момент — тесты. Без них никуда. По факту, есть два варинта тестирования. Первый: написать анализатор, открыть второй экземпляр студии, создать там проект с написанным анализатором, подключиться из первой студии к процессу второй (Attach Process), начать дебаг. Правильный вариант тестирования: открыть тестовый класс, написать код, который должен подсвечиваться анализатором, задебажить тест.

Также порекомендую Test First подход. Сначала пишем неверный код, имплементируем анализатор. Когда анализатор готов — пишем тест для фикса, думаем как перейти от первоначального состояния к пофикшеному, пишем фикс. Конкретно в случае анализаторов такой пошаговый подход отлично заходит.

Слышали когда-нибудь о защитном программировании? В анализаторах пихайте его во все возможные места, ибо отвалившийся по NRE анализатор может уже не заработать до перезагрузки студии.

Учитывайте, большую часть анализаторов губит ненужность. Когда я впервые услышал про анализаторы — мне захотелось написать свой. Идеи возникали постоянно, но реализация выходила слишком сложной\затратной. Первый боевой анализатор был написан только через полгода после знакомства с Roslyn. Следующий — еще через три месяца. Могу предположить, что при работе с мелкими проектами (2 человека в команде) технология не особо полезна — задачи\технологии типовые, все разумное уже покрыто R# или VS.

После перехода на новый проект (6 человек в команде) 3 подходящих места для анализа нашлись буквально сразу. Два были отклонены командой как ненужные. Мораль: советуйтесь с коллегами, они с удовольствием объяснят почему вы идиот анализатор не нужен и вам не придется тратить время на бесполезную работу. Кстати, коллеги оказались самыми профессиональными моими заказчиками — объясняется все четко, на пальцах, с примерами.

Менеджеры иногда требуют цифры: сколько мы потратим, что получим. Тут оценка довольно проста: разработка занимает 2 дня на анализатор «под ключ» (с тестами \интеграцией \инфраструктурой). Разработчики PVS-Studio упоминали что могут потратить 2 недели на один анализатор не верьте им, но они свои анализаторы продают. Если вы пилите анализатор для внутреннего проекта (и уже доводилось писать анализаторы, хотя бы учебные) — 2 дней должно быть достаточно. Оценить профит сложнее. Тривиальный случай — регулярно всплывающая на Code Review ошибка: кто-то LINQ использует в ядре, кто-то дату сериализует без указания формата. Соответственно, профит считается как частота ошибки помноженную на цену фикса помноженную на год.

Встречаются случаи пооригинальнее. Например, есть сервис агрегирующий данные с десятка банков. У каждого банка свои правила сравнения\округления цен, для каждого банка написан свой класс Price, с кастом к decimal. Как только разработчик деплоит на прод сравнение типа

return localBankPrice == centralBankPrice; 

менеджер достает из сейфа две баночки вазелина. Так вот, Roslyn — не самое плохое лекарство при аллергии на вазелин.

В принципе, анализаторы могут быть полезны еще в нескольких ситуациях. Тривиальная — продукт на продажу. Мороки с написанием больше, но и (возможный) профит погуще. Если интересно узнать про промышленную разработку — зовем pavsenin \ Irina_DevExpress (DevExpress) и Andrey2008 (PVS-Studio).

Чуть менее тривиальный случай — анализаторы поставляемые с собственной библиотекой, этакая защита от некорректного использования.

Есть еще товарищи вроде eugenebb, творящие особую плагинную магию, но это совсем другая история.

Суммируя — анализаторы штука крайне интересная, особенно если не возлагать на них больших надежд. Если у вас есть десяток свободных вечеров для неспешного изучения чего-нибудь интересного — потыкайте Roslyn.
Tags:
Hubs:
+14
Comments 5
Comments Comments 5

Articles