Я регулярно общаюсь с потенциальными пользователями, озабоченными ошибками в программах на языке Си++. Их озабоченность выражается в том, что они пробуют инструмент PVS-Studio и начинают писать о том, что при испытаниях что-то подозрительно мало ошибок было найдено. И хотя, вроде чувствуется, что инструмент им интересен, их реакция полна скептицизма.
1. Статический анализ и ROI
Автор: Андрей Карпов
Дата: 06.06.2011
Я регулярно общаюсь с потенциальными пользователями, озабоченными ошибками в
программах на языке Си++. Их озабоченность выражается в том, что они пробуют инструмент PVS-
Studio и начинают писать о том, что при испытаниях что-то подозрительно мало ошибок было
найдено. И хотя, вроде чувствуется, что инструмент им интересен, их реакция полна скептицизма.
И начинается общение, где я пытаюсь убедить какой хороший и полезный продукт PVS-Studio, и
как он мог бы быть полезен компании. На что получаю критику своих обоснований и колкие
замечания по работе анализатора и выдаваемым ложным предупреждениям. В общем, идёт
нормальная маркетинговая работа.
В ходе общения, мной был написан развернутый ответ, который оппонент по дискуссии
предложил мне оформить в виде статьи. Что я и делаю. Надеемся услышать комментарии
касательно оценки пользы, которую могут принести инструменты статического анализа кода. Хотя
статья написана с ориентацией на PVS-Studio, приведенные в ней расчеты, как мне кажется, будут
интересны вне зависимости от того о каком инструменте статического анализа говорить.
----
Текст, приведенный ниже, отвечает на следующий фрагмент письма:
...
Еще найдены порядка 40 (сорока) реальных дефектов - в основном, это недопиленный
копипаст.
В связи с этим есть вопрос: что мы получим от интеграции совсем не дешевой программы в
процесс разработки ПО, в коде которого программа выявляет настолько мало дефектов? Да,
я понимаю, что мы быстрее обнаружим свежепосаженную ошибку, но ведь их так мало.
...
Итак, взглянем на инструменты статического анализа с точки зрения возврата инвестиций (ROI).
Возьмем среднего программиста, который основную часть рабочего времени тратит на
разработку программного обеспечения на языке Си++. Мне такого человека очень легко
представить, поскольку я сам активно программировал и программирую. Предположим, что он
использует ночной запуск статического анализатора кода. Также предположим, что в таком
режиме использования и при среднем темпе программирования, анализатор может обнаружить
два дефекта в коде, допускаемых человеком в неделю.
Говорю это не абстрактно, а опираясь на собственный опыт. Я сейчас только в пол силы работаю с
кодом, но почти каждую неделю замечаю ляп в своем собственном коде, благодаря ночному
2. анализу. Обычно это мелочь, которая все равно бы выявилась при написании теста или запуске
регрессионных тестов, но изредка попадается и более серьезное. Пример дефекта, найденного
PVS-Studio в собственном коде буквально на днях:
bool staticSpecification = IsStaticSpecification(sspec);
bool virtualSpecification = IsVirtualSpecification(sspec);
bool externSpecification = IsVirtualSpecification(sspec);
То, что я пишу статьи о вреде Copy-Paste, вовсе не мешает мне самому сделать подобную ошибку.
Я тоже человек, я тоже копирую фрагменты кода и тоже иногда ошибаюсь. Выловить ошибку,
подобную приведенной выше, очень непросто. На практике она привела бы к тому, что в
некоторых редких случаях анализатор выдал бы ложное предупреждение на некоторые
конструкции кода. Составить ручной тест мне вряд ли бы удалось для этой редкой ситуации
(собственно и не удалось, раз я заложил этот код в SVN). Ошибка коварна тем, что если на неё
пожалуется кто-то из пользователей, то я бы искал её не менее пары часов, да ещё бы просил
пользователя прислать *.i файл. Но мы отвлеклись.
Если программист пишет код регулярнее, чем это делаю я, то 2 полезных предупреждения от
анализатора в неделю - это естественное количество. Итого за год анализатор может выдать
2*4*11 = 88 полезных предупреждений. Временем исправления подобных дефектов и
подавлением ложных предупреждений можно практически пренебречь. Тем не менее, все-таки
учтем их.
Пусть на 2 полезных исправления и 2 ложных срабатывания человек в неделю тратит 20 минут.
Итого в год на работу с анализатором кода будет потрачено: 20*4*11 = 880 минут. Или 15 часов.
Кажется, много пустой траты времени? Это очень мало, по сравнению с тем, что мы посчитаем
дальше.
Теперь рассмотрим цену устранения тех же дефектов, если они не обнаруживаются во время
ночных проверок анализатором кода.
60% из этих ошибок будет обнаружено самим программистом чуть позже при написании юнит-
тестов, самостоятельном предварительном тестировании или в процессе отладки других участков
кода. Будем считать, что поиск самой ошибки и её исправление в этом случае занимает около 15
минут, поскольку человек работает с недавно написанным кодом и хорошо в нём ориентируется.
Примером может быть ситуация, когда в каком-то диалоге программист обнаруживает текст,
который там быть не должен и выясняет, что он случайно вчера использовал x.empty() вместо
x.clear():
url_.empty();
if (status_text)
url_ = status_text;
Только не говорите, что исправление подобных ошибок это 1-2 минуты времени. Конкретно
исправление это вообще несколько секунд. Но нужно ещё найти нужное место, скомпилировать
3. исправленный код, проверить корректность исправления, возможно, заложить правки в SVN. Так
что пусть будет 15 минут.
Сразу отмечу, что ошибки такого рода обычно правятся на автомате и как бы не считаются
ошибками, поскольку нигде не учитываются.
35% ошибок обнаружатся на этапе тестирования. У этих ошибок более долгий жизненный цикл.
Вначале тестировщик локализует и воспроизводит проблему. Составляет и помещает описание
ошибки в баг-трекер. Программист находит и исправляет ошибку, после чего уведомляет
тестировщика о необходимости вновь проверить данный участок и закрыть ошибку. Суммарное
время, которое затратят вместе тестировщик и программист составит порядка 2-х часов.
Примером такой ошибки может быть некорректная работа с OPENFILENAME. Программисту может
повезти и он не увидит "кракозябры" в диалоге, а увидит их только тестер и то не каждый раз
(Гейзенбаг):
OPENFILENAME info = {0};
...
info.lpstrFilter = L"*.txt";
Осталось 5% незамеченных ошибок. То есть эти ошибки не обнаруживаются программистом и QA-
инженерами, но могут быть выявлены статическим анализатором кода.
Если взять и проверить ваш текущий проект с помощью PVS-Studio или другого статического
анализатора, то вы увидите как раз эти самые ненайденные 5% ошибок. Эти 5% и есть те самые 40
ошибок, о которых говорил потенциальный пользователь в ходе проб PVS-Studio.
Остальное 95% ошибок вы поправили сами ранее в процессе написания тестов, юнит-
тестирования, ручного тестирования и других методов.
Итак, у нас есть 5% ошибок, которые мы не можем найти и выпускаем с ними продукт. Из них 4%
могут вообще никогда не проявить себя и про них нет смысла говорить. Оставшийся 1% ошибок
может неожиданно проявить себя на стороне заказчика и доставить массу неприятностей.
Например, клиент хочет написать плагин к вашей системе, и программа падает из за подобного
кода:
bool ChromeFrameNPAPI::Invoke(...)
{
ChromeFrameNPAPI* plugin_instance =
ChromeFrameInstanceFromNPObject(header);
if (!plugin_instance && (plugin_instance->automation_client_.get()))
return false;
4. Вы так не делаете и всегда тестируете внешние интерфейсы? Молодцы. А вот у Google в Chromium
вот здесь не получилось. Так что зарекаться не стоит.
И если вам дорог клиент, и вы цените его, то вас ждут мучительные часы поиска дефекта и
переписки с клиентом. После чего вы ещё дополнительно будете вынуждены сделать для него
фикс или досрочно выпустить очередную версию. На подобные ошибки можно легко потратить
40 часов рабочего времени различных людей, не говоря о нервах.
Что, кто сказал "это неправда"? Вы никогда не сидели с одним коварнейшим багом целую
неделю? Тогда вы и не программировали никогда толком. :)
Посчитаем, сколько времени можно было сэкономить в течение года:
88 * 0.60 * 15 = 792 минуты
88 * 0.35 * 120 = 3696 минут
88 * 0.01 * 40 * 60 = 2212 минут
Итого, человек в течение года тратит на исправление некоторого подмножества собственных
ошибок: (792 + 3696 + 2212) / 60 = 112 часов.
Команда из 5 человек в течение года потратит на некоторые собственные ошибки около 560 часов
времени или 70 дней. С учетом оплачиваемых выходных, отпусков и болезней это приравнивается
к 4 месяцам работы одного абстрактного человека.
Выгодно или не выгодно использовать статический анализатор, зависит от зарплаты ваших
сотрудников.
Поскольку имеется в виду абстрактный человек (участвуют не только программисты), то возьмем
зарплату в 50 000 р. Учитывая налоги на зарплату, аренду помещения, покупку и амортизацию
компьютеров, премии, интернет, сок и прочее, то это число можно смело умножить как минимум
в 2 раза.
Получаем, что цена правки ошибок (не всех, но большинства) без использования статического
анализа составляет 100 000 * 4 = 400 000 рублей.
Если быстро находить эти же ошибки с помощью статического анализа кода, то цена их
исправления составит: 5 * (15 / 8) * 100 000 / 20 = 47 000 рублей.
Прибавим сюда стоимость покупки лицензия PVS-Studio на команду из 5 человек.
Итого цена исправлений ошибок с использованием статического анализатора составит (3 500
евро) * 40.5 + 47 000 = 189 000 рублей.
5. Итого, чистый PROFIT в год от использования статического анализатора PVS-Studio в команде из 5
программистов составляет:
400 000 - 189 000 = 211 000 рублей.
Цена исправления некоторых ошибок уменьшилась более чем в 2 раза. Думайте сами, решайте
сами, иметь или не иметь...
Да, еще замечу, что при расчетах я придерживался скромных позиций. На самом деле, я думаю,
инвестиции окупятся гораздо лучше. Хотелось показать, что даже при скромных расчетах, есть
прибыль. И только, пожалуйста, не пытайтесь упрекнуть меня в каких-то цифрах. В статье показан
подход к качественной оценке пользы, а не количественной.