Книга Макконнелла "Совершенный код. Практическое руководство по разработке программного обеспечения"

В самом начале книги автор рассказывает о целях написания книги:

Моей главной целью при написании этой книги было сокращени разрыва между знаниями гуру и лучших специалистов отрасли, с одной стороны, и общепринятыми методиками разработки коммерческого ПО - с другой. Многие эффективные методики программирования годами скрываются в журналах и научных работах, прежде чем становятся доступными программистской общественности.

Хотя передовые методики разработки ПО в последние годы быстро развивались, общепринятые практически стояли на месте. Многие программы все еще полны ошибок, поставляются с опозданием и не укладываются в бюджет, а многие не отвечают требованиями пользователей. Ученые обнаружили эффективные методики, устраняющие большинство проблем, которые отравляют нашу жизнь c 1970-х годов. Однако из-за того, что эти методики редко покидают страницы узкоспециализированных технических изданий, в большинстве компаний по разработке ПО они еще не используются. Установлено, что для широкого распространения исследовательских разработок обычно требуется от 5 до 15 и более лет (Raghavan and Chand, 1989; Rogers, 1995; Parnas, 1999). Данная книга призвана ускорить этот процесс и сделать важные открытия доступными средним программистам.

Одна из статье, на которую ссылается автор - Diffusing Software-Engineering Methods

Взять на заметку:

  • Раздел про указатели (dog tag).
  • Запасной парашют памяти.
  • Первой работой, посвященной инспекциям, является статья “Design and Code Inspections to Reduce Errors in Program Development (Fagan, 1976)”.
  • The Structure of Scientific Revolutions Томаса Куна.

Больше всего понравилась глава о тестировании ПО.

Про характеристики качества ПО.

Качество ПО имеет внешние и внутренние характеристики. К внешним характеристикам относятся свойства, которые осознает пользователь программы: Корректность, Практичность, Эффективность, Надежность, Целостность, Адаптируемость, Правильность, Живучесть.

Концентрация на одной внешней характеристике качества ПО может влиять на другую характеристику положительно, отрицательно, а может и не влиять. Улучшение некоторых аспектов качества неизбежно приводит к ухудшению других. Необходимость согласования решения с рядом противоречащих целей делает разработку ПО поистине инженерной дисциплиной. Подобные отношения имеют место и между внутренними характеристиками. Самый интересный аспект этой диаграммы в том, что концентрация на одной конкретной характеристике не всегда предполагает компромисс с другой характеристикой. Одни характеристики связаны между собой обратным отношением, другие — прямым, а третьи вообще не зависят друг от друга. Так, корректность характеризует степень, в которой работа системы соответствует спецификации. - стр. 458

Относительная эффективность методик контроля качества ПО

Не все методики контроля качества имеют одинаковую эффективность. Эффективность многих методик в плане нахождения и устранения дефектов уже известна. В данном разделе мы обсудим этот и некоторые другие аспекты “эффективности” методик контроля качества.

Эффективность обнаружения дефектов.

Некоторые методики более эффективны в обнаружении дефектов, чем другие, к тому же разные методики приводят к обнаружению разных дефектов. Одним из способов оценки методик обнаружения дефектов является определение процента обнаруженных дефектов из общего числа дефектов, имеющейся в программе на конкретном этапе. Показатели эффективности нахождения дефектов при использовании некоторых популярных методик указаны в таблице.

Методика устранения дефектов Минимальная эффективность Типичная эффективность Максимальная эффективность
Неформальные обзоры проекта 25% 35% 40%
Формальные инспекции проекта 45% 55% 65%
Неформальные обзоры кода 20% 25% 35%
Формальные инспекции кода 45% 60% 70%
Моделирование или прототипирование 35% 65% 80%
Самостоятельная проверка кода 20% 40% 60%
Блочное тестирование 15% 30% 50%
Тестирование новых функций (компонентов) 20% 30% 35%
Интеграционное тестирование 25% 35% 40%
Регрессивное тестирование 15% 25% 30%
Тестирование системы 25% 40% 55%
Ограниченное бета-тестирование (менее чем в 10 организациях) 25% 35% 40%
Крупномасштабное бета-тестирование (более чем в 1000 организациях) 60% 75% 85%

Источники: «Programming Productivity» (Jones, 1986a), «Software Defect Removal Efficiency» (Jones, 1996) и «What We Have Learned About Fighting Defects» (Shull et al., 2002)

Самое интересное в этих данных то, что типичная эффективность обнаружения дефектов при использовании любой методики не превышает 75% и что в среднем она равна примерно 40%. Более того, самые популярные методики — блочное тестирование и интеграционное тестирование — позволяют найти обычно только около 30–35% дефектов. Как правило, используется подход, основанный на интенсивном тестировании, что позволяет устранить лишь около 85% дефектов. Ведущие организации используют более широкий диапазон методик, достигая при этом 95%-ой или более высокой эффективности устранения дефектов (Jones, 2000). Итак, если разработчики хотят достигнуть более высокой эффективности обнаружения дефектов, они должны полагаться на комбинацию методик. Одно из подтверждений этого вывода было получено в классическом исследовании Гленфорда Майерса (Myers, 1978b). Участниками исследования были программисты, обладавшие минимум 7, а в среднем — 11 летним опытом. Исследуемая программа содержала 15 известных ошибок. Майерс попросил каждого программиста найти эти ошибки, используя одну из следующих методик:

  • тестирование выполнения программы по спецификации;
  • тестирование выполнения программы по спецификации с возможностью изучения исходного кода;
  • анализ/инспекция с использованием и спецификации, и исходного кода.

Различия эффективности обнаружения дефектов оказались очень большими: программисты нашли от 1 до 9 дефектов. Средний показатель был равен 5,1, или 1/3 от общего числа известных дефектов.

При использовании одной методики никакая из них не имела статистически значимого преимущества над любой другой. В то же время любая комбинация двух методик — в том числе использование одной методики двумя независимыми группами — приводила к увеличению общего числа найденных дефектов почти вдвое. В исследованиях, проведенных в Лаборатории проектирования ПО NASA, компании Boeing и других компаниях, было обнаружено, что разные программисты находят разные дефекты. Только примерно каждую пятую ошибку, обнаруженную в ходе инспекций, находят двое или более разработчиков (Kouchakdjian, Green, and Basili, 1989; Tripp, Struck, and Pflug, 1991; Schneider, Martin, and Tsai, 1992).

Майерс обращает внимание на то, что поиск одних видов ошибок оказывается более эффективным при непосредственном участии людей (например, при инспекции или анализе кода), а других видов — при компьютерном тестировании (Myers, 1979). Этот вывод подтвердился в более позднем исследовании, показавшем, что чтение кода способствует нахождению дефектов интерфейса, а функциональное тестирование — нахождению дефектов управляющих структур (Basili, Selby, and Hutchens, 1986). Гуру тестирования Борис Бейзер (Boris Beizer) сообщает, что неформальные подходы к тестированию обычно позволяют достигнуть покрытия кода тестами лишь на 50–60%, если только вы не используете анализатор покрытия (Johnson, 1994).

Таким образом, методики поиска дефектов лучше применять в комбинации. Джонс (Jones) также подтверждает этот вывод. Используя исключительно тестирование, высоких результатов добиться невозможно. Джонс сообщает, что комбинация блочного тестирования, функционального тестирования и тестирования системы часто приводит к обнаружению менее 60% дефектов, что обычно неприемлемо для конечного продукта.

Эти данные также помогают понять, почему программисты, начинающие применять дисциплинированную методику устранения дефектов, такую как экстремальное программирование, добиваются более высокой степени устранения дефектов. Как показывает таблица, набор методик устранения дефектов, применяемых в экстремальном программировании, позволяет устранить около 90% дефектов в обычной ситуации и 97% в лучшем случае, что гораздо выше среднего для отрасли показателя, равного 85%. Некоторые программисты связывают этот факт с синергичными отношениями между методиками экстремального программирования, но на самом деле это просто предсказуемый результат использования конкретного набора методик устранения дефектов. Эффективность других комбинаций методик может оказаться такой же или даже более высокой, поэтому выбор конкретных методик устранения дефектов, позволяющих достичь желаемого уровня качества, является одним из аспектов эффективного планирования проекта.

Угадывание ошибок

Формальные методики тестирования хорошие программисты дополняют менее формальными эвристическими методиками. Одна из них - угадывание ошибок (error guessing). Термин “угадывание ошибок” - довольно примитивное название вполне разумной идем, подразумевающей создание тестов на основе обдуманных предположений о вероятных источниках ошибок.

Предположения можно выдвигать, опираясь на интуицию или накопленный опыт. Так, в главе 21 в числе прочих достоинств инспекций были указаны создание и обновление списка частых ошибок, используемого при проверке нового кода. Поддерживая списки ранее допущенных ошибок, вы повысите эффективность своих догадок. Ниже рассматриваются конкретные виды ошибок, угадать которые легче всего: Анализ граничных условий, Сложные граничные условия, Классы плохих данных, Классы хороших данных. - стр. 505

Классификация ошибок

Большинство ошибок легко исправить. Примерно в 85% случаев на исправление ошибки требуется менее некольких часов. Где-то в 15% случаев - от нескольких часов до нескольких дней. И только 1% ошибок требует большего времени. На исправление 20% ошибок уходит около 80% ресурсов.

Оценивайте опыт борьбы с ошибками в своей организации. Разнообразие результатов, приведенных в этом разделе, говорит о том, что каждая организация имеет собственный, уникальный опыт борьбы с ошибками. Это осложняет использование опыта дргуих организаций в ваших условиях. Некоторые результаты противоречат интуиции; возможно вам следует дополнить свои интуитивные представления дргуими средствами. Начните оценивать процесс разработки в своей организации, чтобы знать причины проблем. стр. 510

Борис Бейзер объединил данные нескольких исследований и пришел к исключительно подробной классификации ошибок по распространенности (Beizer, 1990). Вот резюме его результатов:

  • 25,18% Структурные ошибки
  • 22,44% Ошибки в данных
  • 16,19% Ошибки в реализации функциональности
  • 9,88% Ошибки конструирования
  • 8,98% Ошибки интеграции
  • 8,12% Ошибки в функциональных требованиях
  • 2,76% Ошибки в определении или выполнении тестов
  • 1,74% Системные ошибки, ошибки в архитектуре ПО
  • 4,71% Другие ошибки

Сколько ошибок ожидать?

Ожидаемое число ошибок зависит от качества вашего процесса разработки. Вот некоторые соображения по этому поводу:

  • Средний для отрасли показатель таков% примерно 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 строк кода в готовой системе (Cobb and Mills, 1990). В нескольких проектах - например, в проекте разработки ПО для космических кораблей - благодаря сочетанию методик формальной разработки, обзоров кода коллегами и статичстического тестирования был достигнут такой уровень, как 0 дефектов на 500 000 строк кода (Fishman, 1996).

  • Уоттс Хамфри сообщает, что группы, применяющие методику Team Software Process, достигают уровня 0,06 дефекта на 1000 строк кода. Главный аспект TSP - обучение разработчиков изначальному предотвращения дефектов.

Результаты проектов TSP и проектов “чистой комнаты” подтверждают другую версию Главного Закона Контроля Качества ПО: дешевле сразу создаты высококачественную программу, чем создать низкокачественную программу и исправлять ее.” - стр. 512

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

Макконнелл рекомендует технику создания тестов, которая используется во многих проектах с открытым исходным кодом:

Регрессивное (или повторное) тестирование значитально облегчают автоматизированные инструменты сравнения действительных выходных данных с ожидаемыми. Данные, выводимые на печать, легко проверить перенаправив их в файл и сравнив при помощи diff или другой утилиты сравнения файлов с другим файлом, в который ранее были записаны ожидаемые данные. Если файлы различаются, радуйтесь: вы обнаружили регрессивную ошибку.

Вот только он не упоминает, что такой способ зависит от установленной локали.

Инструменты возмущения состояния системы:

Другой класс инстументов тестирования предназначен для приведения системы в возмущенное состояние. Многие программисты могут рассказать истории о программах, которые работают 99 раз из 100, но при сотом запуске с теми же данными терпят крах. Почти всегд причиной является невыполнение инициализации какой-то переменной, и обычно эту ошибку очень трудно воспроизвести, потому что в 99 случаях из 100 неинициализированная переменная получает нулевое значение.

Инструменты тестирования из этого класса могут иметь самые разнообразные возможности.

Заполнение памяти. Эта функция помогает находить неинициализованные переменные. Некоторые инструменты перед запуском программы заполняют память произвольными значениями, чтобы неинициализированные переменные не получили случайно значение 0. Иногда память целесообразно заполнять конкретным значением. Например, в случае процессоров с архитектурой x86 значение 0xCC соответсвует машинному коду команды прерывания. Если вы заполните память значением 0xCC и программа попробует выполнить что-то, чего выполнять не следует, вы натолкнетесь в отладчике на точку прерывания и обнаружите ошибку.

Встряхивания памяти. В многозадачных средах некоторые инструменты могут переуопрядочивать выделенную программе память, что позволяет гарантировать отсутствие кода, требующего, чтобы данные находились по абсолютным, а не относительным адресам.

Селективный сбой памяти. Драйвер памяти позволяет имитировать недостаток или неудачный запрос памяти, может отказывать в запросе памяти после произвольного числа неудовлетворенных запросов. Это особенно полезно при тестировании сложных программ, выделяющих память динамически.

Проверка доступа к памяти (проверка границ). Инструменты проверки границ следят за операциями над указателями, гарантируя их корректность. Такие инструменты полезны при поиске неинициализированных или “висячих” указателей.” - стр. 518

Протоколы тестирования

Обеспечить повторяемость процесса тестирования недостаточно - вы должны оценивать и проект, чтобы можно было точно сказать, улучшается он в результаты изменений или ухудшается. Вот категории данных, которые можно собирать с целью оценки проекта:

  • административное описание дефекта (дата обнаружения, сотрудник, сообщивший о дефекте, номер сборки программы, дата исправления);
  • полное описание проблемы;
  • действия, предпринятые для воспроизведения проблемы;
  • родственные дефекты;
  • тяжесть проблемы (например, критическая проблема, “неприятная” или косметическая);
  • источник дефекта: выработка требований, проектирование, кодирование или тестирование;
  • вид дефекта кодирования: ошибка занижения или завышения на 1, ошибка присваивания, недопустимый индекс массива, неправильный вызов метода и т.д.;
  • число строк, затронутых дефектом;
  • время, ушедшее на нахождение дефекта;
  • время, ушедшее на исправление дефекта;

Собирая эти данные, вы сможете подсчитывать некоторые показатели, позволяющие сделать вывод об изменении качества проекта:

  • число дефектов в каждом классе; все числа целесообразно отсортировать в порядке от удшего метода к лучшему и, возможно, нормализовать по размеру метода;
  • среднее время тестирования в расчете на один обнаруженный дефект;
  • среднее число обрануженных дефектов в расчете на один тест;
  • среднее время программирования в расчете на один исправленный дефект;
  • процент кода, покрытого тестами;
  • число дефектов, относящихся к каждой категории тяжести. - стр. 520

Различия в эффективности отладки

Эти данные не только сообщают нам кое-что об отладке, но и подтверждают Главный Закон Контроля Качества ПО: повышение качества программы снижает затраты на ее разработку. Лучшие программисты обнаружили больше дефектов за меньшее время и исправили их более корректно. Нет нужды выбирать между качеством, стоимостью и быстротой - они идут рука об руку. - стр. 526

Соответствующие стандарты

  • IEEE Std 730-2002 - стандарт IEEE планирования контроля качества ПО.
  • IEEE Std 1061-1998 - стандарт IEEE методологии метрик качества ПО.
  • IEEE Std 1028-1997 - стандарт обзоров ПО.
  • IEEE Std 1008-1987 (R1993) - стандарт блочного тестирования ПО.
  • IEEE Std 829-1998 - стандарт документирования тестов ПО.
    • стр. 469

Макконнелл в главе о тестировании, выполняемом разработчиками советует к прочтению такие книги:

  • Kaner, Cem, James Bach, and Bret Pettchord. Lessons Learned in Software Testing.
  • Whittaker, James A How to Break Software: A Practical Guide to Testing. Boston, MA
  • Whittaker, James A “What is Software Testing? And Why Is It So Hard?” IEEE Software
  • Myers Glenford J. The Art of Software Testing. New York
Теги: booksquotes