Tarkvara kvaliteed ja standardid Качество и стандарты программного обеспечения Отладка программ Что такое отладка? Отладка – это процесс обнаружения причин возникновения ошибки и ее последующего исправления (в отличие от тестирования, являющегося процессом обнаружения самого факта существования ошибки) Отладка включает в себя элементы тестирования и разработки На некоторых проектах отладка может занимать до 50% всего времени разработки Для многих программистов отладка – это самая трудная часть программирования При соответствующем подходе количество ошибок, требующих отладки, должно сократиться, и отладка должна стать самой легкой частью; при таком подходе все ошибки сводятся к небольшим недосмотрам или опечаткам Роль отладки в качестве ПО Как и тестирование, отладка не является способом улучшения качества ПО. Отладка – это всего лишь способ исправления дефектов в программе Качество программ должно обеспечиваться аккуратным анализом требований или прототипированием, грамотным проектированием и использованием лучших практик кодирования Отладка – это последняя надежда программиста Вариации в качестве отладки Исследования работы опытных программистов показали, что отличие лучших и худших результатов при отладке Среднее составляет ~20:1. Кроме время отладки того, некоторые (мин) программисты находят Среднее колбольше ошибок и во не исправляют их более найденных ошибок аккуратно Среднее колПример: исследование во ошибок, работы опытных допу-щенных программистов (как при исправлении минимум 4 года опыта других работы) при отладке ошибок программы с 12 ошибками: 3 самых быстрых программиста 3 самых медленных программи ста 5.0 14.1 0.7 1.7 3.0 7.7 Выводы о различиях в качестве отладки Три лучших программиста смогли найти ошибки примерно за треть времени по сравнению с худшими Кроме того, они допустили всего 2/5 ошибок по сравнению с худшими Самый лучший программист нашел все ошибки и не допустил ни одной ошибки при исправлении Худший не нашел 4 из 12 ошибок и сделал 11 ошибок при исправлении тех 8, что он нашел Схожие результаты получались и в других исследованиях (Gilb, 1977; Curtis, 1981) Эти результаты подтверждают общий принцип качества: «улучшение качества снижает стоимость разработки». Не нужно выбирать между качеством, стоимостью и временем – они все могут оптимизированы одновременно Ошибки как возможности Что означает наличие ошибки в программе? Видимо, то, что мы не полностью понимаем программу. Это неприятная мысль, но если мы программируем методом проб и ошибок, то ошибки неизбежны По большому счету надо улучшать свои навыки программирования, а не навыки отладки Но даже лучшие программисты допускают ошибки «На ошибках учатся». Что может узнать программист при изучении своих ошибок в программах? Понять программу, над которой работает Осознать свои типичные виды ошибок Оценить удачность своего подхода к решению проблем Оценить удачность своего подхода к исправлению ошибок «Вредные советы» по отладке «Проще всего найти ошибку методом угадывания» «Не надо тратить времени на понимание проблемы» Разбросайте случайным образом множество отладочных печатей. Смотрите только на результат работы. Исправляйте программу где попало – вдруг повезет и она заработает? Не сохраняйте исходную версию программы. Ошибка-то, скорее всего, тривиальная! «Исправляйте ошибку самым очевидным способом» Не нужно тратить времени на сложные исправления, затрагивающие всю программу. Отладка и суеверия Не доводилось ли вам говорить следующие фразы? Компьютер глючит Это ошибка в компиляторе Кривые входные данные Редактор неправильно сохраняет программы и потому компилируется неправильная версия Кто его знает, когда происходит эта ошибка. Может быть, это зависит от фазы луны? Чаще всего, ошибки в программах – ваши собственные; нечего сваливать свои ошибки на других Даже если это не ваша ошибка, полезно предполагать обратное. Ошибки и так трудно находить, а если вы еще и не будете их искать... Нахождение ошибок Отладка состоит из нахождения ошибок и их исправления. Первая часть обычно занимает до 90% времени и усилий. Наиболее эффективный метод отладки – "научный". Обобщенный научный подход может быть сформулирован так: Сбор данных через повторяемые эксперименты Создание гипотезы, отражающей максимум доступных данных Разработка эксперимента для проверки гипотезы Подтверждение или опровержение гипотезы При необходимости - итерация предыдущих шагов Этот подход находит следующее отражение в отладке: Стабилизация ошибки (1-ый шаг общего метода) Обнаружение точного места ошибки (2-4 шаги общего метода) Исправление ошибки Тестирование исправления Поиск похожих ошибок Сквозной пример Мы будем рассматривать методику отладки на следующем примере. Предположим, что у нас есть программа, работающая с базой данных сотрудников. Эта программа должна печатать список сотрудников и их налоговые отчисления в алфавитном порядке. Ниже приведен результат работы: Formatting, Fred Freeform Goto, Gary Modula, Mildred Many-Loop, Mavis Statement, Sue Switch Whileloop, Wendy $5,877 $1,666 $10,788 $8,889 $4,000 $7,860 Проблема заключается в том, что Many-Loop, Mavis и Modula,Mildred напечатаны в неправильном порядке Стабилизация ошибки Если проблема возникает нестабильно, то ее практически невозможно диагностировать. Нестабильные ошибки обычно связаны с проблемами инициализации или висячими указателями При стабилизации ошибки требуется также свести тест к минимально возможному (иногда это задача группы тестирования, но чаще всего это задача программиста) Сведение теста к минимальному – это тоже задача, требующая научного подхода (хоть и в миниатюре) Пример стабилизации В нашем примере мы обнаруживаем, что после второго запуска программы все в порядке: Formatting, Fred Freeform $5,877 Goto, Gary $1,666 Many-Loop, Mavis $8,889 Modula, Mildred $10,788 Statement, Sue Switch $4,000 Whileloop, Wendy $7,860 Однако при вводе новой записи, Fruit-Loop, Frita, проблема сортировки возникает снова В обоих случаях мы вводили одну запись, а не группу записей Отсюда гипотеза: проблема заключена в процедуре ввода новой записи (сортировка группы записей работает правильно) Повторный запуск подтверждает нашу гипотезу Обнаружение точного места возникновения ошибки После сведения теста к минимальному изменение любого аспекта этого теста изменяет и внешнее проявление ошибки. Естественно, мы будем использовать это для диагностики ошибки Например, в нашем примере, мы можем подозревать наличие ошибки смещения на единицу (ошибка, которая возникает при вводе одной, но не двух записей). Тогда мы можем попробовать граничные случаи (+1, 0, -1) Однако при просмотре программы мы не можем найти ни одной такой очевидной ошибки Поэтому мы должны вернуться к этапу варьирования теста. Мы добавляем сотрудника Hardcase, Henry ... и он появляется на правильном месте! Таким образом, наша первая гипотеза провалилась – это или более сложная проблема, или что-то совершенно иное Новые гипотезы При изучении нашего теста, мы замечаем, что Fruit-Loop, Frita и Many-Loop, Mary – это единственные фамилии, содержащие дефисы. Оба имени появлялись на неправильном месте при вводе. Может быть, в первом случае проблема была не в Modula, Mildred, а в Many-Loop, Frita? Новая гипотеза: проблема связана с именами, содержащими дефис, а не с вводом одного имени Однако это не согласовывается с правильностью повторной сортировки Новые гипотезы Мы смотрим в код и обнаруживаем, что программа использует две различных процедуры сортировки: при вводе сотрудника и при сохранении данных. Более того, первая процедура и не должна полностью сортировать записи – она подготавливает данные для ускорения процедуры сохранения программы. При этом всяческие особенности (типа дефисов) не поддерживаются Итак, проблема заключается в том, что данные печатаются до сохранения в файле, в не полностью отсортированном виде Новая гипотеза: имена с символами пунктуации неправильно сортируются вплоть до сохранения в файле Методы поиска ошибок После стабилизации ошибки и минимизации теста необходимо перейти к нахождению причины ошибки В зависимости от качества кода, это может быть тривиальным или сложным (если при поиске причины ошибки у вас возникают трудности, то, скорее всего, вся программа написана плоховато) Рекомендации по поиску ошибок: Используйте все доступные данные при выдвижении гипотез Минимизируйте тесты, показывающие ошибки Воспроизведите ошибку различными способами Соберите больше данных для генерации новых гипотез Используйте результаты негативных тестов Проведите мозговой штурм в поисках новых гипотез (не хватайтесь за первую гипотезу; ищите другие причины; думайте!) Методы поиска ошибок (2) Рекомендации по поиску ошибок: Сужайте подозрительные фрагменты кода (попробуйте убрать фрагмент кода и проверьте наличие ошибки; метод "разделяй и властвуй"; ставьте точки останова в отладчике) Относитесь внимательнее к тем процедурам, в которых уже встречались ошибки Проверяйте недавние исправления Расширяйте подозрительные фрагменты кода Проводите интеграцию постепенно Поставьте временное ограничение на "quick&dirty debugging" Ищите типичные ошибки (см. inspection checklists) "Исповедальная отладка" (расскажите проблему кому-то еще) Отдохните от проблемы Синтаксические ошибки В принципе, синтаксические ошибки постепенно вымирают. Как помочь им в этом процессе: Не доверяйте номеру строки с ошибкой, на которую указывает компилятор (см. как минимум на ±1 строку) Не доверяйте сообщениям компилятора Еще меньше доверяйте всем сообщениями компилятора после самого первого ("наведенные ошибки") "Разделяй и властвуй" (особенно хорошо работает для синтаксических ошибок) Ищите лишние комментарии, апострофы и кавычки. Исправление ошибок Относительно простая задача, но именно это делает ее столь опасной (50% исправлений неправильны!) Рекомендации по исправлению ошибок: Разберитесь в проблеме прежде, чем ее исправлять Разберитесь в программе, а не в проблеме (исследование в 1986 г. показало, что с исправлением лучше справляются те программисты, которые понимают контекст программы; под контекстом понимается несколько сот строк, а не 1-2) Убедитесь в правильности диагноза до исправления Не торопитесь! Не срезайте углы. Методы исправления ошибок Рекомендации по исправлению ошибок: Сохраняйте исходную версию кода Исправляйте проблему, а не симптомы: Исправления, ориентированные на симптомы, почти никогда не будут работать "Заплатки" на коде невозможно сопровождать Компьютеры предназначены для систематических вычислений – оставим "творческий подход" для людей Вносите исправления только тогда, когда вы уверены Вносите изменения по одной штуке за раз Проверяйте свои исправления Ищите похожие ошибки Психологические соображения при отладке Отладка – это психологически сложный процесс: Приходится искать ошибку в собственном коде Приходится думать последовательно и логично Приходится переключаться между разработкой и тестированием Приходится бороться со знакомоством с кодом "Психологические установки" Психологические установки Студенты, обучавшиеся структурному программированию, ожидают, что все конструкции похожи на три базовые операции (но код с goto ведет себя по-иному) Студенты, изучающие цикл while, зачастую подразумевают, что условие проверяется постоянно (а не в конце или начале цикла) Ошибки в присваиваниях примерно в три раза сложнее для обнаружения, чем "ошибки взаимодействия" Анекдот: программист случайно использовал переменные SYSTSTS и SYSSTSTS как одну и ту же переменную. Ошибку нашли только после сотен запусков и издания книги с кодом Типичная ошибка – "подразумеваемые скобки": Психологическое расстояние Психологическое расстояние определяет легкость различия различных слов людьми: Первая переменная Вторая переменная Психологич. Расстояние STOPPT ST0PPT Почти ноль SHIFTRF SHIFTRT Мало заметно CLAIMS1 CLAIMS2 Небольшое GCOUNT CCOUNT Небольшое PRODUCT SUM Большое Средства отладки Существует целый вагон средств, которые могут помочь при отладке: Компараторы исходных текстов Предупреждения компилятора Поставьте максимальный уровень предупреждений в компиляторе и исправляйте код соответствующим образом Считайте предупреждения ошибками Создавайте проектные соглашения по установкам компилятора Дополнительные средства проверки синтаксиса (lint - верификатор C-программ) Профайлеры Использование отладчика Современные отладчики умеют очень много: Точки останова на конкретных строчках кода Остановка на n-ой итерации цикла Остановка при изменении переменных Остановка при присваивании конкретного значения Прохождение кода строчка за строчкой Откат по программе Исследование всех данных в программе, включая типы, определенные пользователем Присваивание новых значений переменным Продолжение исполнения программы Многоязыковая отладка (язык1, язык2, ассемблер...) Запоминание установок Установка точки останова на изменение переменной Критика отладчиков "An interactive debugger is an outstanding example of what is NOT needed – it encourages trial-and-error hacking rather than systematic design, and also hides marginal people barely qualified for precision programming" Harlan Mills Отладчик действительно не заменяет мозгов, но и обратное не полностью верно Отладчик – это мощный инструмент. При правильном использовании, он дает большие преимущества; при неправильном – можно повредиться