Главная страница
Навигация по странице:

  • Большинство ошибок имеет довольно ограниченную область ви

  • Многие ошибки не связаны с конструированием

  • Как правило, ошибки конструирования лежат на со

  • ЧАСТЬ V

  • Довольно часто причиной ошибок является неправильное понимание

  • Большинство ошибок легко исправить

  • Оценивайте опыт борьбы с ошибками в своей организации

  • Доля ошибок, обусловленных неграмотным конструированием

  • Ошибки самого тестирования

  • Планируйте тестирование программы так же, как и ее разработку

  • Встраивайте блочные тесты в среду тестирования

  • 22.5. Инструменты тестирования

  • Создание лесов для тестирования отдельных классов

  • Перекрестная ссылка

  • Инструменты сравнения файлов

  • Генераторы тестовых данных

  • Мониторы покрытия кода тестами

  • Совершенный код. Совершенный код. Мастер-класс. Стив Макконнелл. Руководство по стилю программирования и конструированию по


    Скачать 5.88 Mb.
    НазваниеРуководство по стилю программирования и конструированию по
    АнкорСовершенный код
    Дата31.03.2023
    Размер5.88 Mb.
    Формат файлаpdf
    Имя файлаСовершенный код. Мастер-класс. Стив Макконнелл.pdf
    ТипРуководство
    #1028502
    страница64 из 106
    1   ...   60   61   62   63   64   65   66   67   ...   106
    ГЛАВА 22 Тестирование, выполняемое разработчиками
    509
    Классификация ошибок
    Некоторые ученые попытались классифицировать ошибки по типу и определить распространенность ошибок каждо#
    го типа. У каждого программиста есть свой список наибо#
    лее неприятных ошибок: ошибки занижения или завыше#
    ния на 1, невыполнение повторной инициализации переменной цикла и т. д.
    В контрольных списках я указал и многие другие типы ошибок.
    Борис Бейзер объединил данные нескольких исследований и пришел к исключи#
    тельно подробной классификации ошибок по распространенности (Beizer, 1990).
    Вот резюме его результатов:
    25,18%
    Структурные ошибки
    22,44%
    Ошибки в данных
    16,19%
    Ошибки в реализации функциональности
    9,88%
    Ошибки конструирования
    8,98%
    Ошибки интеграции
    8,12%
    Ошибки в функциональных требованиях
    2,76%
    Ошибки в определении или выполнении тестов
    1,74%
    Системные ошибки, ошибки в архитектуре ПО
    4,71%
    Другие ошибки
    Бейзер сообщил свои результаты с точностью до двух разрядов после запятой, но исследования типов ошибок в целом не позволяют сделать окончательный вывод.
    Разные ученые сообщают о разных ошибках, а результаты исследований похожих типов ошибок иногда различаются на 50%, а не на сотые доли процента.
    Из#за таких больших различий выполненное Бейзером объединение результатов ряда исследований, вероятно, не способно дать нам точной информации. Но даже если имеющиеся данные неокончательны, на их основе мы можем сделать несколь#
    ко общих выводов.
    Большинство ошибок имеет довольно ограниченную область ви'
    димости Одно исследование показало, что в 85% случаев исправление ошибки требовало изменения только одного метода (Endres, 1975).
    Многие ошибки не связаны с конструированием Опрос 97 разработчиков позволил выяснить, что тремя наиболее частыми причинами ошибок были пло#
    хое знание прикладной области, изменения или конфликты требований, а также неэффективность общения и плохая координация действий разработчиков (Curtis,
    Krasner, and Iscoe, 1988).
    Как правило, ошибки конструирования лежат на со'
    вести программистов В двух давнишних исследовани#
    ях было установлено, что из всех ошибок 95% были допу#
    щены программистами, причиной 2% было системное ПО
    (компилятор и ОС), еще 2% — другое ПО, а оставшегося 1%
    — оборудование (Brown and Sampson, 1973; Ostrand and
    Weyuker, 1984). Системное ПО и инструменты разработки ис#
    пользуются сегодня гораздо шире, чем в 1970#х и 1980#х,
    Перекрестная ссылка Список всех контрольных списков при- веден после содержания книги.
    Если вы видите следы копыт,
    думайте о лошадях, а не о зеб- рах. Скорее всего ОС работает нормально. С базой данных тоже, наверное, все в порядке.
    Энди Хант и Дэйв Томас
    (Andy Hunt and Dave Thomas)

    510
    ЧАСТЬ V Усовершенствование кода поэтому я думаю, что сегодня программисты несут ответственность за еще боль#
    ший процент ошибок.
    На удивление распространенной причиной проблем являются
    опечатки В одном исследовании было обнаружено, что 36% всех оши#
    бок конструирования были опечатками (Weiss, 1975). Исследование по#
    чти 3 000 000 строк приложения для расчета динамики полета, проведенное в 1987 г.,
    показало, что опечатками были 18% всех ошибок (Card, 1987). В другом исследо#
    вании было установлено, что 4% всех ошибок были орфографическими ошибка#
    ми в сообщениях (Endres, 1975). В одной из моих программ коллега обнаружил ряд орфографических ошибок, просто проанализировав все строки исполняемо#
    го файла утилитой проверки орфографии. Внимание к деталям на самом деле важно. Если вы сомневаетесь в этом, учтите, что три самых дорогостоящих ошибки всех времен, приведших к убыткам объемом 1,6 миллиарда, 900 миллионов и 245
    миллионов долларов, были вызваны изменением
    одного символа в ранее коррек#
    тных программах (Weinberg, 1983).
    Довольно часто причиной ошибок является неправильное понимание
    проекта Компилятивное исследование Бейзера показало, что 16% ошибок было обусловлено неправильной интерпретацией проекта (Beizer, 1990). В другом ис#
    следовании было обнаружено, что неправильным пониманием проекта объясня#
    лось 19% ошибок (Weiss, 1975). Посвящайте анализу проекта столько времени,
    сколько нужно. Это не обеспечивает немедленную выгоду (кому#то даже может показаться, что вы не работаете!), но в итоге окупается с избытком.
    Большинство ошибок легко исправить Примерно в 85% случаев на исправ#
    ление ошибки требуется менее нескольких часов. Где#то в 15% случаев — от не#
    скольких часов до нескольких дней. И только около 1% ошибок требует больше#
    го времени (Weiss, 1975; Ostrand and Weyuker, 1984; Grady, 1992). Это подтвержда#
    ет и Барри Бом, заметивший, что на исправление около 20% ошибок уходит око#
    ло 80% ресурсов (Boehm, 1987b). Изо всех сил старайтесь избегать трудных оши#
    бок, выполняя предварительные обзоры требований и проектов. Исправляйте многочисленные мелкие ошибки так эффективно, как только можете.
    Оценивайте опыт борьбы с ошибками в своей организации Разнообразие результатов, приведенных в этом подразделе, говорит о том, что каждая органи#
    зация имеет собственный, уникальный опыт борьбы с ошибками. Это осложняет использование опыта других организаций в ваших условиях. Некоторые резуль#
    таты противоречат интуиции; возможно, вам следует дополнить свои интуитив#
    ные представления другими средствами. Начните оценивать процесс разработки в своей организации, чтобы знать причины проблем.
    Доля ошибок, обусловленных
    неграмотным конструированием
    Как и классификация ошибок, данные, соотносящие ошибки с разными этапами разработки, не окончательны. Но то, что с конструированием всегда связано боль#
    шое число ошибок, сомнений не вызывает. Иногда программисты утверждают, что ошибки конструирования дешевле исправлять, чем ошибки, допущенные при вы#

    ГЛАВА 22 Тестирование, выполняемое разработчиками
    511
    работке требований или проектировании. Возможно, исправить отдельную ошиб#
    ку конструирования и дешевле, но при учете всех ошибок ситуация меняется.
    Ниже приведены некоторые мои выводы.
    
    В небольших проектах дефекты конструирования составляют боль#
    шинство всех ошибок. В одном исследовании ошибок кодирования, до#
    пущенных в небольшом проекте (1000 строк кода), было обнаружено, что
    75% дефектов пришлось на этап кодирования, тогда как на этап выработки тре#
    бований — 10%, а на этап проектирования — 15% (Jones, 1986a). По#видимому,
    такое распределение ошибок характерно для многих небольших проектов.
    
    Дефекты конструирования составляют минимум 35% всех дефектов независи#
    мо от размера проекта. В крупных проектах доля дефектов конструирования не так велика, как в небольших, но и тогда она равна минимум 35% (Beizer, 1990;
    Jones, 2000). Некоторые ученые сообщают, что даже в очень крупных проек#
    тах дефектами конструирования являются около 75% всех ошибок (Grady, 1987).
    Обычно чем лучше разработчики знают прикладную область, тем лучше они проектируют общую архитектуру системы. В этом случае на детальное проек#
    тирование и кодирование приходится еще больший процент ошибок (Basili and
    Perricone, 1984).
    
    Хотя ошибки конструирования и дешевле исправлять, чем ошибки выработки требований и проектирования, это все равно дорого. Исследование двух очень крупных проектов, проведенное в Hewlett#Packard, показало, что стоимость исправления среднего дефекта конструирования составляла 25–50% от стоимо#
    сти исправления средней ошибки проектирования (Grady, 1987). При учете большего числа дефектов конструирования общая стоимость их исправления могла вдвое превышать стоимость исправления дефектов проектирования.
    Вот примерное отношение между объемом проекта и распределением ошибок
    (рис. 22#2):
    Рис. 22'2. По мере увеличения объема проекта доля ошибок, допускаемых
    во время конструирования, снижается. Тем не менее ошибки конструирования
    составляют 45–75% всех ошибок даже в самых крупных проектах

    512
    ЧАСТЬ V Усовершенствование кода
    Сколько ошибок можно ожидать?
    Ожидаемое число ошибок зависит от качества вашего процесса разработки. Вот некоторые соображения по этому поводу.
    
    Средний для отрасли показатель таков: примерно 1–25 ошибок на 1000
    строк кода в готовом ПО, разрабатывавшегося с использованием разных методик (Boehm, 1981; Gremillion, 1984; Yourdon, 1989a; Jones, 1998; Jones,
    2000; Weber, 2003). Проекты, в которых обнаруживается 0,1 от указанного числа ошибок, редки; о случаях, когда ошибок в 10 раз больше, предпочитают не сообщать (вероятно, такие проекты даже не доводят до конца!).
    
    Отделение прикладного ПО компании Microsoft сообщает о таких показате#
    лях, как 10–20 дефектов на 1000 строк кода во время внутреннего тестирова#
    ния и 0,5 дефекта на 1000 строк кода в готовой продукции (Moore, 1992). Для достижения этого уровня применяется комбинация методик чтения кода, опи#
    санных в разделе 21.4, и независимого тестирования.
    
    Харлан Миллз придумал «разработку методом чистой комнаты» — методику,
    позволяющую достигнуть всего лишь 3 дефектов на 1000 строк кода во время внутреннего тестирования и 0,1 дефекта на 1000 строк кода в готовой системе
    (Cobb and Mills, 1990). В нескольких проектах — например, в проекте разработ#
    ки ПО для космических кораблей — благодаря сочетанию методик формальной разработки, обзоров кода коллегами и статистического тестирования был до#
    стигнут такой уровень, как 0 дефектов на 500 000 строк кода (Fishman, 1996).
    
    Уоттс Хамфри (Watts Humphrey) сообщает, что группы, применяющие мето#
    дику Team Software Process (TSP), достигают уровня 0,06 дефекта на 1000 строк кода. Главный аспект TSP — обучение разработчиков изначальному предот#
    вращению дефектов (Weber, 2003).
    Результаты проектов TSP и проектов «чистой комнаты» подтверждают другую версию Главного Закона Контроля Качества ПО: дешевле сразу создать высококачественную программу, чем создать низкокачественную программу и исправлять ее. Производительность труда в случае одного полнос#
    тью проверенного проекта из 80 000 строк, разработанного методом «чистой комнаты», оказалась равной 740 строкам кода на человеко#месяц. В то же время средняя для отрасли скорость разработки полностью проверенного кода, учиты#
    вающая все затраты, не связанные с кодированием, близка к 250–300 строкам на человеко#месяц (Cusumano et al., 2003). Экономия затрат и повышение произво#
    дительности труда при использовании методик TSP или «чистой комнаты» объяс#
    няются тем, что эти методики почти исключают затраты времени на отладку. Что?
    Исключают затраты времени на отладку? Это действительно стоящая цель!
    Ошибки самого тестирования
    Вероятно, вам знакома следующая ситуация. В программе имеется ошибка.
    У вас сразу же возникают некоторые предположения о ее причинах, но весь код кажется правильным. Пытаясь изолировать ошибку, вы выпол#
    няете еще несколько тестов, но все они дают правильные результаты. Вы прово#
    дите несколько часов за чтением кода и пересчетом результатов вручную, но без#
    результатно. Еще через несколько часов что#то заставляет вас проверить тесто#

    ГЛАВА 22 Тестирование, выполняемое разработчиками
    513
    вые данные. Эврика! Ошибка в тестовых данных! Как глупо тратить часы на по#
    иск ошибки, если она кроется в тестовых данных, а не в коде!
    Это довольно распространенная ситуация. Зачастую сами тесты содер#
    жат не меньше, а то и больше ошибок, чем тестируемый код (Weiland, 1983;
    Jones, 1986a; Johnson, 1994). Объяснить это легко, особенно если разра#
    ботчики сами пишут тесты. Тесты обычно создают на ходу, не уделяя должного внимания проектированию и конструированию. Их часто считают одноразовы#
    ми и разрабатывают с соответствующей тщательностью.
    Ниже дано несколько советов по снижению числа ошибок в тестах.
    Проверяйте свою работу Разрабатывайте тесты так же тщательно, как и код,
    и внимательно проверяйте их. Анализируйте код каждого теста строка за стро#
    кой при помощи отладчика, как вы проверяли бы код готового приложения. Про#
    водите анализ и инспекцию тестовых данных.
    Планируйте тестирование программы так же, как и ее разработку
    Планирование тестирования следует начинать на этапе выработки требований или сразу после получения задания. Это поможет избавиться от тестов, основанных на неверных предположениях.
    Храните тесты Посвятите немного времени проверке качества тестов. Сохра#
    ните их для регрессивного тестирования и для работы над будущими версиями программы. Связанные с этим проблемы легко оправдать, если вы знаете, что собираетесь сохранить тесты, а не выбросить.
    Встраивайте блочные тесты в среду тестирования Пишите сначала код блочных тестов, но затем интегрируйте их в системную среду тестирования (та#
    кую как JUnit). Использование интегрированной среды тестирования предотвра#
    щает только что упомянутую тенденцию выбрасывать тесты.
    22.5. Инструменты тестирования
    В этом разделе рассматриваются типы инструментов тестирования, которые вы можете купить или создать. Конкретные инструменты названы здесь не будут,
    потому что ко времени издания книги они вполне могут устареть. Для получения свежих сведений обратитесь к своему любимому журналу по программированию.
    Создание лесов для тестирования отдельных классов
    Термин «леса» (scaffolding) пришел в программирование из строительства. Стро#
    ительные леса создаются для того, чтобы рабочие получили доступ к определен#
    ным частям здания. В программировании леса создаются исключительно для упрощения тестирования кода.
    Одним из типов лесов является объект, используемый дру#
    гим, тестируемым объектом. Такой объект называется «под#
    дельным объектом» (mock object) или «объектом#заглушкой»
    (stub object) (Mackinnon, Freemand, and Craig, 2000; Thomas and Hunt, 2002). С аналогичной целью можно создавать и низкоуровневые методы, называемые «заглушками». Поддель#
    ные объекты или методы#заглушки можно делать более или
    Дополнительные сведения Не- сколько хороших примеров ле- сов можно найти в эссе Джона
    Бентли «A Small Matter of Prog- ramming» в книге «Programming
    Pearls, 2d ed.» (Bentley, 2000).

    514
    ЧАСТЬ V Усовершенствование кода менее реалистичными в зависимости от требуемой степени достоверности. Такие леса могут:
    
    немедленно возвращать управление, не выполнив никаких действий;
    
    тестировать полученные данные;
    
    выводить диагностическое сообщение (например, значения входных парамет#
    ров) на экран или записывать в файл;
    
    запрашивать возвращаемые значения у программиста;
    
    возвращать стандартный ответ независимо от полученных данных;
    
    впустую тратить ресурсы процессора, выделенные реальному объекту или методу;
    
    играть роль более медленной, объемной, простой или менее точной версии реального объекта или метода.
    Другим типом лесов является поддельный метод, вызывающий реальный тести#
    руемый метод. Такой метод, называемый «драйвером» или иногда «тестовой сбруей»
    (test harness), может:
    
    вызывать объект, передавая ему некоторые данные;
    
    запрашивать информацию у программиста и передавать ее объекту;
    
    принимать параметры командной строки (если ОС это поддерживает) и пе#
    редавать их объекту;
    
    читать аргументы из файла и передавать их объекту;
    
    вызывать объект несколько раз, передавая ему при каждом вызове новый пред#
    определенный набор входных данных.
    Последний тип лесов, фиктивный файл (упрощенная вер#
    сия реального полноразмерного файла), включает такие же элементы. Небольшой фиктивный файл обладает двумя до#
    стоинствами. Его небольшой объем позволяет держать в уме все его содержимое и облегчает проверку правильности фай#
    ла. А так как файл создается специально для тестирования,
    вы можете спроектировать его так, чтобы любая ошибка в его использовании бро#
    салась в глаза.
    Очевидно, что создание лесов требует некоторой работы, но вы сможете повторно использовать их даже при обнаружении ошибки в классе. Кроме того, существуют многие инструмен#
    ты, упрощающие создание поддельных объектов и других видов лесов. При тести#
    ровании класса леса позволяют исключить его взаимодействие с другими классами.
    Леса особенно полезны, если в программе применяются утонченные алгоритмы. Так,
    если тестируемый код встроен в другой блок кода, тесты могут выполняться непри#
    емлемо медленно. Леса позволяют тестировать код непосредственно. Несколько минут,
    потраченных на создание лесов для тестирования кода, скрытого в самых глубинах программы, могут сэкономить много часов на отладке.
    Для создания лесов годится любая из многих доступных сред тестирования (JUnit,
    CppUnit, NUnit и т. д.). Если ваша среда разработки не поддерживается ни одной из существующих сред тестирования, вы можете написать несколько методов класса и включить в файл метод
    main() для их тестирования, пусть даже эти методы не
    Перекрестная ссылка Грань между инструментами тестиро- вания и инструментами отлад- ки размыта. Об инструментах отладки см. раздел 23.5.
    http://cc2e.com/2268

    ГЛАВА 22 Тестирование, выполняемое разработчиками
    515
    будут в итоговой программе работать сами по себе. Метод
    main() может читать параметры командной строки и передавать их в тестируемый метод, позволяя проверить его до интеграции с остальной частью программы. Выполняя инте#
    грацию, оставьте методы и предназначенные для их тестирования леса в файле,
    и заблокируйте леса при помощи директив препроцессора или комментариев. В
    итоге код лесов будет проигнорирован при компиляции, а если вы разместите его в конце файла, он и на глаза не будет попадаться. Оставленный в файле, он не причинит никакого вреда. Вам не придется тратить время на его удаление и ар#
    хивирование, а в случае чего он всегда будет под рукой.
    Инструменты сравнения файлов
    Регрессивное (или повторное) тестирование значительно облегчают автоматизированные инструменты сравнения действительных выходных данных с ожидаемыми. Данные,
    выводимые на печать, легко проверить, перенаправив их в файл и сравнив при помощи diff или другой утилиты срав#
    нения файлов с другим файлом, в который ранее были записаны ожидаемые дан#
    ные. Если файлы различаются, радуйтесь: вы обнаружили регрессивную ошибку.
    Генераторы тестовых данных
    Вы также можете написать код для систематичного тести#
    рования выбранных фрагментов программы. Несколько лет назад я разработал собственный алгоритм шифрования и написал на его основе программу шифрования файлов. Программа должна была так кодировать файл, чтобы его можно было декодировать, только введя правиль#
    ный пароль. При шифровании содержимое файла изменялось самым радикаль#
    ным образом. Было очень важно, чтобы программа декодировала файл правиль#
    но, потому что в противном случае он был бы испорчен.
    Я настроил генератор тестовых данных, который полностью тестировал шифро#
    вальную и дешифровальную части программы. Он генерировал файлы, состоящие из случайных символов и имеющие случайный объем в пределах от 0 до 500 кб. Он генерировал случайные пароли случайной длины в диапазоне от 1 до 255 симво#
    лов. Для каждого случая он генерировал две копии случайного файла, шифровал одну копию, заново инициализировался, дешифровал копию и затем сравнивал дешифрованную копию с первоначальной. Если какие#нибудь байты различались,
    генератор печатал всю информацию, нужную мне для воспроизведения ошибки.
    Я настроил генератор так, чтобы средний объем тестируемых файлов равнялся
    30 кб. Если бы я этого не сделал, файлы были бы равномерно распределены меж#
    ду 0 кб и 500 кб и имели средний объем 250 кб. Сокращение среднего объема позволило мне быстрее тестировать файлы, пароли, признаки конца файла, не#
    обычные объемы файлов и прочие возможные причины ошибок.
    Результаты не заставили себя ждать. Выполнив лишь около 100 тестов, я нашел две ошибки. Обе возникали в специфических ситуациях, которые могли ни разу не случиться на практике, однако это все же были ошибки, и я был рад их обна#
    ружить. После их исправления я тестировал программу несколько недель, зашиф#
    Перекрестная ссылка О регрес- сивном тестировании см. подраз- дел «Повторное (регрессивное)
    тестирование» раздела 22.6.
    http://cc2e.com/2275

    516
    ЧАСТЬ V Усовершенствование кода ровав и дешифровав около 100 000 файлов без каких бы то ни было ошибок.
    Учитывая то, что я протестировал файлы и пароли самого разного объема и со#
    держания, я мог быть уверен, что с программой все в порядке.
    Из этой истории можно извлечь ряд уроков, в том числе следующие.
    
    Правильно спроектированные генераторы случайных данных способны гене#
    рировать комбинации тестовых данных, о которых вы могли бы не подумать.
    
    Генераторы случайных данных могут протестировать программу тщательнее,
    чем вы сами.
    
    Со временем вы можете улучшить случайные тесты, обратив повышенное вни#
    мание на реалистичный диапазон входных значений. Это позволяет сконцен#
    трировать тестирование на тех областях, которые будут использоваться чаще всего, и максимально повысить их надежность.
    
    Модульное проектирование сполна окупается во время тестирования. Я смог отделить код шифрования и дешифрования и задействовать его независимо от кода пользовательского интерфейса, что упростило задачу написания тес#
    тового драйвера.
    
    Вы можете повторно использовать тестовый драйвер даже после изменения тестируемого им кода. Как только я исправил две ошибки, я смог сразу же на#
    чать повторное тестирование.
    Мониторы покрытия кода тестами
    Карл Вигерс сообщает, что тестирование, выполняемое без измерения покрытия кода тестами, обычно охватывает только 50–60% кода (Wiegers,
    2002). Монитор покрытия — это инструмент, который следит за тем, какой код тестировался, а какой нет. Монитор покрытия особенно полезен для систе#
    матичного тестирования, потому что он говорит вам, полностью ли код покры#
    вается конкретным набором тестов. Если вы выполнили полный набор тестов, а монитор покрытия сообщает, что какой#то код все еще не протестирован, значит,
    нужны дополнительные тесты.
    Регистраторы данных
    Некоторые инструменты могут следить за программой и собирать информацию о ее состоянии в случае краха по#
    добно «черному ящику», устанавливаемому в самолетах для определения причин крушения. Эффективная регистрация данных облегчает ди#
    агностику ошибок и сопровождение программы после ее выпуска.
    Вы можете создать собственный регистратор данных, записывающий сведения о важных событиях в файл. Записывайте в файл состояние системы до ошибки и подробные сведения об условиях возникновения ошибки. Можете использовать эту функциональность в предварительных версиях программ и блокировать в окончательных версиях. Если вы используете для хранения зарегистрированных данных самоочищающееся хранилище и тщательно продумали размещение и содержание сообщений об ошибках, можете оставлять функции регистрации дан#
    ных и в итоговых версиях программ.
    http://cc2e.com/2282

    1   ...   60   61   62   63   64   65   66   67   ...   106


    написать администратору сайта