Устав от нескончаемого code review или отладки, временами задумываешься, как бы упростить себе жизнь. И немного поискав, ну или случайно наткнувшись, можно увидеть волшебное словосочетание: "Статический анализ". Давайте посмотрим, что это такое и как он может взаимодействовать с вашим проектом.
Собственно говоря, если вы пишете на каком-либо современном языке, тогда, даже не догадываясь об этом, вы пропускали его через статический анализатор. Дело в том, что любой современный компилятор предоставляет пусть и крохотный, но набор предупреждений о потенциальных проблемах в коде. Например, компилируя C++ код в Visual Studio вы можете увидеть следующее:
В этом выводе мы видим, что переменная var так и не была использована нигде в функции. Так что на самом деле вы почти всегда пользовались простеньким статическим анализатором кода. Однако, в отличие от профессиональных анализаторов, таких как Coverity, Klocwork или PVS-Studio, предоставляемые компилятором предупреждения могут указывать только на небольшой спектр проблем.
Если вы не знаете наверняка, что такое статический анализ и как его внедрять, прочтите эту статью, чтобы более подробно ознакомиться с этой методологией.
В двух словах: ускорение и упрощение.
Статический анализ позволяет найти уйму различных проблем в коде: начиная от неправильного использования конструкций языка, заканчивая опечатками. Например, вместо
auto x = obj.x;
auto y = obj.y;
auto z = obj.z;
Вы написали следующий код:
auto x = obj.x;
auto y = obj.y;
auto z = obj.x;
Как видите, в последней строке появилась опечатка. Например, PVS-Studio выдаёт следующее предупреждение:
V537 Consider reviewing the correctness of 'y' item's usage.
Если хотите потыкать в эту ошибку руками, то попробуйте готовый пример на Compiler Explorer: *клик*.
И как вы понимаете, не всегда можно обратить внимания на подобные участки кода сразу и из-за этого можно засесть за отладку на добрый час, недоумевая, почему всё работает так странно.
Однако это явная ошибка. А если разработчик написал неоптимальный код из-за того, что позабыл какую-либо тонкость языка? Или же вовсе допустил в коде undefined behavior? К сожалению, подобные случаи совершенно обыденны и львиная часть времени тратится на то, чтобы отладить специфично работающий код, который содержит опечатки, типичные ошибки или undefined behavior.
Именно для этих ситуаций и появился статический анализ. Это помощник для разработчика, который укажет ему на различные проблемы в коде и объяснит в документации почему так писать не нужно, к чему это может привести и как это исправить. Вот пример как это может выглядеть: *клик*.
Больше интересных ошибок, которые может обнаружить анализатор, вы можете найти в статьях:
Теперь, прочитав этот материал и убедившись в пользе статического анализа, вы могли захотеть испытать его в деле. Но с чего начать? Как интегрировать новый инструмент в текущий проект? И как познакомить команду с ним? На эти вопросы вы найдёте ответы ниже.
Примечание. Статический анализ не заменяет и не отменяет такую полезную вещь, как обзоры кода. Он дополняет этот процесс, помогая заранее заметить и исправить опечатки, неточности, опасные конструкции. Намного продуктивнее сосредоточиться при обзорах кода на алгоритмах и понятности кода, а не над высматриванием не там поставленной скобки или читать скучные функции сравнения.
Всё начинается с пробной версии. Действительно, сложно решиться внедрять что-либо в процесс разработки, если никогда до этого не видел инструмента вживую. Поэтому первым делом стоит скачать пробную версию.
Что вы узнаете на этом этапе:
После того, как вы установили себе всё необходимое, то первым делом стоит запустить анализ всего проекта (Windows, Linux, macOS). В случае с PVS-Studio в Visual Studio вы увидите подобную картину (кликабельно):
Дело в том, что обычно на проекты с большой кодовой базой статические анализаторы выдают огромное количество предупреждений. Нет необходимости исправлять их все, так как ваш проект уже работает, а значит эти проблемы не являются критичными. Однако вы можете посмотреть на самые интересные предупреждения и исправить их при необходимости. Для этого нужно отфильтровать вывод и оставить только наиболее достоверные сообщения. В плагине PVS-Studio для Visual Studio это делается фильтрацией по уровням и категориям ошибок. Для наиболее точного вывода оставьте включёнными только High и General (тоже кликабельно):
Действительно, 178 предупреждений просмотреть значительно проще, чем несколько тысяч...
Во вкладках Medium и Low часто попадаются хорошие предупреждения, однако в эти категории занесены те диагностики, которые имеют меньшую точность (достоверность). Подробнее про уровни предупреждений и варианты работы под Windows можно посмотреть тут: *клик*.
Успешно просмотрев самые интересные ошибки (и успешно исправив их) стоит подавить оставшиеся предупреждения. Это нужно для того, чтобы новые предупреждения не терялись среди старых. К тому же статический анализатор – это помощник для программиста, а не список для багов. :)
После знакомства наступает время настройки плагинов и интеграции в CI. Это необходимо сделать до того, как программисты начнут использовать статический анализатор. Дело в том, что программист может забыть включить анализ или вовсе не захотеть. Для этого нужно сделать некоторую финальную проверку всего, чтобы непроверенный код не мог попасть в общую ветку разработки.
Что вы узнаете на данном этапе:
Так как идеальной документации не существует, иногда приходится писать в поддержку. Это нормально, и мы рады вам помочь. :)
А теперь приступим к сервисам непрерывной интеграции (CI). Любой анализатор можно внедрить в них без каких-либо серьезных проблем. Для этого нужно создать отдельный этап в pipeline, который обычно находится после сборки и юнит-тестов. Делается это при помощи различных консольных утилит. Например, PVS-Studio предоставляет следующие утилиты:
Для интеграции анализа в CI нужно сделать три вещи:
Например, для установки PVS-Studio на Linux (Debian-base) нужно выполнить следующие команды:
wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt \
| sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list \
https://files.pvs-studio.com/etc/viva64.list
sudo apt-get update -qq
sudo apt-get install -qq pvs-studio
В системах под управлением Windows отсутствует возможность установить анализатор из пакетного менеджера, однако есть возможность развернуть анализатор из командной строки:
PVS-Studio_setup.exe /verysilent /suppressmsgboxes
/norestart /nocloseapplications
Подробнее о развёртывании PVS-Studio в системах под управлением Windows можно почитать *тут*.
После установки нужно запустить непосредственно анализ. Однако делать это рекомендуется только после того, как прошла компиляция и тесты. Это связано с тем, что для статического анализа обычно требуется в два раза больше времени, чем для компиляции.
Так как способ запуска зависит от платформы и особенностей проекта, я покажу вариант для C++ (Linux) в качестве примера:
pvs-studio-analyzer analyze -j8 \
-o PVS-Studio.log
plog-converter -t errorfile PVS-Studio.log --cerr -w
Первая команда выполнит анализ, а вторая конвертирует отчёт в текстовый формат, выведет его на экран и вернёт отличный от 0 код возврата в случае наличия предупреждений. Подобный механизм удобно использовать для блокировки сборки при наличии сообщений об ошибках. Однако, вы всегда можете убрать флаг -w и не блокировать сборку, содержащую предупреждения.
Примечание. Текстовый формат — это неудобно. Он приводится просто для примера. Обратите внимание на более интересный формат отчёта - FullHtml. Он позволяет осуществлять навигацию по коду.
Подробнее про настройку анализа на CI можно прочитать в статье "PVS-Studio и Continuous Integration" (Windows) или "Как настроить PVS-Studio в Travis CI" (Linux).
Хорошо, вы настроили работу анализатора на сборочном сервере. Теперь, если кто-то залил непроверенный код, будет падать этап проверки, и вы сможете обнаружить проблему, однако это не совсем удобно, так как эффективнее проверять проект не после того, как произошло слияние веток, а до него, на этапе pull request'а.
В целом настройка анализа pull request'а не сильно отличается от обычного запуска анализа на CI. За исключением необходимости получить список изменённых файлов. Обычно их можно получить, запросив разницу между ветками при помощи git:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
Теперь нужно передать анализатору на вход этот список файлов. Например, в PVS-Studio это реализовано при помощи флага -S:
pvs-studio-analyzer analyze -j8 \
-o PVS-Studio.log \
-S .pvs-pr.list
Подробнее про анализ pull request'ов можно узнать *тут*. Даже если вашего CI нет в списке указанных в статье сервисов, вам будет полезен общий раздел, посвященный теории этого типа анализа.
Настроив анализ pull request'ов вы сможете блокировать содержащие предупреждения коммиты, тем самым создав границу, которую непроверенный код не сможет пересечь.
Это всё безусловно хорошо, однако хотелось бы иметь возможность посмотреть все предупреждения в одном месте. Не только от статического анализатора, но и от юнит-тестов или от динамического анализатора. Для это существуют различные сервисы и плагины. PVS-Studio, например, имеет плагин для интеграции в SonarQube.
Теперь пришло время установки и настройки анализатора для повседневного использования при разработке. К этому моменту вы уже познакомились с большей частью способов работы, поэтому это можно назвать самой лёгкой частью.
Как самый простой вариант – разработчики сами могут установить необходимый анализатор. Однако это займёт много времени и отвлечёт их от разработки, поэтому вы можете автоматизировать этот процесс, используя установщик и нужные флаги. Для PVS-Studio есть различные флаги для автоматизированной установки. Впрочем, всегда есть пакетные менеджеры, например, Chocolatey (Windows), Homebrew (macOS) или десятки вариантов для Linux.
Затем нужно будет установить необходимые плагины, например, для Visual Studio, IDEA, Rider etc.
На этом этапе пора сказать пару слов о способах ускорения работы анализатора при ежедневном использовании. Полный анализ всего проекта занимает очень много времени, однако часто ли мы меняем код разом во всём проекте? Едва ли существует настолько масштабный рефакторинг, что сразу затронет всю кодовую базу. Количество изменяемых файлов за раз редко превышает десяток, поэтому их и есть смысл анализировать. Для подобной ситуации существует режим инкрементального анализа. Только не пугайтесь, это не ещё один инструмент. Это специальный режим, который позволяет анализировать только изменённые файлы и их зависимости, причём это происходит автоматически после сборки, если вы работаете в IDE c установленным плагином.
В случае, если анализатор обнаружит в недавно измененном коде проблемы, то сообщит об этом самостоятельно. Например, PVS-Studio скажет вам об этом при помощи оповещения:
Само собой недостаточно сказать разработчикам использовать инструмент. Нужно как-то им рассказать, что это вообще и как это есть. Вот, например, статьи про быстрый старт для PVS-Studio, однако подобные туториалы вы сможете найти для любого предпочитаемого вами инструмента:
Подобные статьи дают всю необходимую для повседневного использования информацию и не отнимают много времени. :)
Ещё на этапе знакомства с инструментом мы подавили очень много предупреждений во время одного из первых запусков. Увы, но статические анализаторы не идеальны, поэтому время от времени выдают ложные срабатывания. Подавить их обычно легко, например в плагине PVS-Studio для Visual Studio достаточно нажать на одну кнопку:
Однако вы можете не только подавлять их. Например, вы можете сообщить в поддержку о наличии проблемы. Если ложное срабатывание возможно исправить, то в будущих обновлениях вы можете обратить внимание на то, что с каждым разом становится всё меньше и меньше специфичных для вашей кодовой базы ложных срабатываний.
Вот мы и прошли все этапы по интеграции статического анализа в процесс разработки. Несмотря на важность настройки подобных инструментов на CI, самым главным местом запуска является именно компьютер разработчика. Ведь статический анализатор – это не судья, который говорит где-то далеко от вас, что код никуда не годится. Напротив, это помощник, который подсказывает, если вы устали и напоминает, если вы о чём-либо забыли.
Правда без регулярного использования статический анализ вряд ли значительно упростит разработку. Ведь самая его главная польза для разработчика заключается не столько в поиске сложных и спорных участков кода, сколько в раннем их обнаружении. Согласитесь, что обнаружить проблему, когда правки ушли на тестирование, не только неприятно, но и очень долго. Статический анализ же при регулярном использовании просматривает каждое изменение прямо на вашем компьютере и сообщает о подозрительных местах во время работы над кодом.
А если вы или ваши коллеги всё ещё не уверены, стоит ли внедрять анализатор, то предлагаю сейчас перейти к чтению статьи "Причины внедрить в процесс разработки статический анализатор кода PVS-Studio". В ней разобраны типовые опасения разработчиков о том, что статический анализ будет отнимать их время и так далее.
0