Главная страница

Руководство по стилю программирования и конструированию по


Скачать 7.6 Mb.
НазваниеРуководство по стилю программирования и конструированию по
Дата18.05.2023
Размер7.6 Mb.
Формат файлаpdf
Имя файлаCode_Complete.pdf
ТипРуководство
#1139697
страница67 из 104
1   ...   63   64   65   66   67   68   69   70   ...   104
ГЛАВА 23 Отладка
541
Пример ухудшения кода в результате
его «исправления» (Java)
for ( claimNumber = 0; claimNumber < numClaims[ client ]; claimNumber++ ) {
sum[ client ] = sum[ client ] + claimAmount[ claimNumber ];
}
«Исправление».
if ( client == 45 ) {
sum[ 45 ] = sum[ 45 ] + 3.45;
}
Теперь допустим, что при нулевом числе исков (number of claims) со стороны клиента
37 вы не получаете 0. Плохое решение этой проблемы могло бы быть таким:
Продолжение примера ухудшения кода в результате
его «исправления» (Java)
for ( claimNumber = 0; claimNumber < numClaims[ client ]; claimNumber++ ) {
sum[ client ] = sum[ client ] + claimAmount[ claimNumber ];
}
if ( client == 45 ) {
sum[ 45 ] = sum[ 45 ] + 3.45;
}
Второе «исправление».
else if ( ( client == 37 ) && ( numClaims[ client ] == 0 ) ) {
sum[ 37 ] = 0.0;
}
Если уж и это не заставляет вас содрогнуться от ужаса, вы зря читаете мою книгу:
ничто в ней вас не тронет. Перечислить все недостатки этого подхода в книге,
объемом лишь около 1000 страниц, невозможно, поэтому ниже я указал только три главных.

В большинстве случаев эти исправления работать не будут. Проблемы в этом примере очень похожи на дефекты инициализации. Дефекты инициализации по определению непредсказуемы, поэтому тот факт, что сумма для клиента 45
отличается сегодня от верного значения на 3,45 доллара, ничего не говорит о том, что будет завтра. Завтра она может отличаться на 10 000,02 доллара, а может быть верной. Таковы ошибки инициализации.

Такой код трудно сопровождать. Если для исправления ошибок создаются ча- стные случаи, они становятся самой заметной особенностью кода. Значение
3,45 доллара не всегда будет таким, и позднее возникнет другая ошибка. В код придется включить новый частный случай, а частный случай для 3,45 доллара удален не будет. К коду будут прилипать все новые частные случаи. В конце концов эти «прилипалы» станут слишком тяжелыми для кода, и он пойдет на дно, где ему самое место.
>
>

542
ЧАСТЬ V Усовершенствование кода

Неразумно использовать компьютер для выполнения чего-то, что лучше сде- лать вручную. Компьютеры хороши для выполнения предсказуемых система- тичных вычислений, а творческая фальсификация данных лучше дается лю- дям. Вместо подделки данных в коде лучше было бы исправить их в распечат- ке результатов работы программы.
Изменяйте код только при наличии веских оснований С устранением только симптомов проблемы тесно связана методика случайного изменения кода до тех пор, пока он не покажется верным. Типичный ход мыслей при этом таков: «Похо- же, этот цикл содержит дефект. Наверное, это ошибка занижения или завышения на 1, так что я просто отниму 1 и посмотрю, что получится. Ерунда какая-то. Ну-ка,
а если прибавить 1? Вроде все работает. Думаю, проблема решена».
Какой бы популярной ни была эта методика, она неэффективна. Внесение слу- чайных изменений в код похоже на накачивание шин автомобиля при неисправ- ности двигателя. Так вы ничего не узнаете — только впустую потратите время.
Изменяя программу случайным образом, вы по сути говорите: «Не знаю, в чем тут дело. Будем надеяться, что это изменение сработает». Не делайте так. Это вуду-про- граммирование. Чем сильнее вы измените код, не понимая его, тем более сомни- тельной станет его корректность.
Не вносите в программу изменение, если не уверены в его правильности. Невер- ные изменения должны вызывать у вас удивление Они должны вызывать сомне- ния, пересмотр взглядов и самокритику. Они должны быть редкими.
Вносите в код по одному изменению за раз Одиночные изменения и так до- вольно коварны. При внесении сразу двух изменений дело только осложняется:
они могут привести к тонким ошибкам, похожим на первоначальные. В итоге вы попадаете в затруднительное положение: как узнать, имеете ли вы дело со старой ошибкой, только с новой ошибкой, похожей на старую, или сразу с новой и ста- рой? Не осложняйте себе жизнь и вносите изменения только по одному за раз.
Проверяйте исправления Проверьте программу сами,
попросите сделать это кого-то другого или проанализируй- те программу вместе. Выполните те же триангуляционные тесты, что и при диагностике проблемы, и проверьте, все ли аспекты проблемы устранены. Если решена только часть проблемы, вы об этом узнаете.
Проверьте всю программу на предмет того, не привели ли сделанные изменения к побочным эффектам. Самый легкий и эффективный способ обнаружения по- бочных эффектов — автоматизированное регрессивное тестирование програм- мы в среде JUnit, CppUnit или аналогичной.
Добавляйте в набор тестов блочные тесты, приводящие к проявлению
имеющихся дефектов Обнаружив ошибку, на которую не смогли указать име- ющиеся тесты, добавьте в набор тестов новый тест, позволяющий предотвратить возвращение этой ошибки.
Поищите похожие дефекты Обнаружив один дефект, поищите аналогичные дефекты. Дефекты часто появляются группами, и, обращая внимание на типы своих дефектов, вы сможете исправлять все дефекты конкретного типа. Поиск похожих
Перекрестная ссылка Об авто- матизированном регрессивном тестировании см. подраздел
«Повторное (регрессивное) те- стирование» раздела 22.6.

ГЛАВА 23 Отладка
543
дефектов требует глубокого понимания проблемы. Если вы не можете сообразить,
как искать похожие дефекты, значит, вы еще не полностью понимаете проблему.
23.4. Психологические аспекты отладки
Отладка предъявляет к интеллекту не меньшие требования,
чем любые другие этапы разработки ПО. Самолюбие гово- рит вам, что ваш код не может содержать дефектов, даже если вы уже встречали их в нем. Выдвигая гипотезы, собирая дан- ные, анализируя гипотезы и методично отказываясь от них,
вы должны думать строго, стать немыслимым формалистом.
Отлаживая собственный код, вы должны быстро переклю- чаться между гибким творческим мышлением, характерным для проектирования, и жестким критичным мышлением, нужным для отладки. Читая код, стремитесь забыть о том, что он вам известен, и увидеть то, что написано на самом деле, а не то, что вы ожидаете увидеть.
«Психологическая установка» и слепота при отладке
Встречая в программе элемент
Num, что вы видите? Неправильно написанное слово
«Numb»? Или аббревиатуру слова «Number»? Скорее всего второе. Это одно из проявлений «психологической установки»: вы видите то, что ожидаете увидеть. Что написано тут?
Этот казус уже стал классическим: люди часто замечают только один артикль «the».
Они видят то, что ожидают увидеть. Ниже описаны другие похожие факты.

Студенты, изучающие циклы
while, часто считают, что условие цикла оцени- вается непрерывно, т. е. ожидают, что цикл завершится сразу, как только усло- вие станет ложным, а не после проверки условия (Curtis et al., 1986). Они ду- мают, что цикл
while должен соответствовать слову «пока» в естественном языке.

Программист, который неумышленно использовал и переменную
SYSTSTS, и переменную SYSSTSTS, думал, что имеет дело с одной перемен ной. Он не обнаружил проблему, пока программа не была выполнена сотни раз и не была написана книга, содержащая ошибочные результаты (Wein- berg, 1998).

Программисты, сталкивающиеся с кодом:
if ( x < y )
swap = x;
x = y;
y = swap;
иногда воспринимают его как:
Дополнительные сведения Пре- красное обсуждение психологи- ческих аспектов отладки и мно- гих других областей разработ- ки ПО вы найдете в книге «The
Psychology of Computer Prog- ramming» (Weinberg, 1998).

544
ЧАСТЬ V Усовершенствование кода if ( x < y ) {
swap = x;
x = y;
y = swap;
}
Люди ожидают, что новый феномен будет напоминать аналогичные феномены,
виденные ими ранее. Они ожидают, что новая управляющая стурктура будет ра- ботать так же, как и старые структуры, что оператор
while языка программирова- ния будет соответствовать слову «пока», а имена переменных будут такими же,
какими были раньше. Вы видите то, что ожидаете увидеть, и поэтому не замечае- те отличия, такие как неправильное написание слова «структура» в предыдущем предложении.
Какое отношение психологическая установка имеет к отладке? Во-первых, она под- черкивает важность грамотных методик программирования. Разумное форматиро- вание и комментирование, удачные имена переменных, методов и другие элемен- ты стиля программирования помогают структурировать фоновые условия програм- мирования так, чтобы вероятные дефекты четко выделялись на общем фоне.
Во-вторых, психологическая установка влияет на выбор частей программы, изу- чаемых при обнаружении ошибки. Исследования показали, что программисты,
отлаживающие код максимально эффективно, во время отладки мысленно отде- ляют нерелевантные фрагменты программы (Basili, Selby, and Hutchens, 1986). Это позволяет им сужать область поиска и находить дефекты быстрее. Однако при этом можно по ошибке «отложить в сторону» часть программы, содержащую дефект.
В результате вы будете искать дефект в правильном фрагменте кода, игнорируя фрагмент, который на самом деле содержит дефект. Вы пойдете по неверному пути и должны будете вернуться к перекрестку. Некоторые советы из раздела 23.2 по- могут преодолеть эту «слепоту при отладке».
«Психологическая дистанция»
Психологическую дистанцию можно определить как лег- кость различения двух элементов. Если дать кому-нибудь длинный список слов и сказать, что все они имеют отно- шение к уткам, человек может с легкостью перепутать сло- ва «Queck» и «Quack», потому что они кажутся похожими. Психологическая дис- танция между ними мала. Гораздо труднее перепутать «Tuack» и «Quack», хотя они тоже различаются только одной буквой. Слово «Tuack» похоже на «Quack» мень- ше, чем «Queck», потому что первая буква слова сильнее бросается в глаза, чем буква в середине.
Вот примеры психологических дистанций между именами переменных (табл. 23-1):
Перекрестная ссылка Советы по выбору ясных имен переменных см. в разделе 11.7.

ГЛАВА 23 Отладка
545
Табл. 23-1. Примеры психологических дистанций между именами переменных
Первая переменная
Вторая переменная
Психологическая дистанция
stoppt stcppt
Почти незаметна shiftrn shiftrm
Почти отсутствует dcount bcount
Небольшая claims1
claims2
Небольшая product sum
Большая
Приступая к отладке, будьте готовы к проблемам, обусловленным недостаточной психологической дистанцией между похожими именами переменных и методов.
Выбирайте во время конструирования имена, ясно отличающиеся от других имен,
и вы забудете об этих проблемах.
23.5. Инструменты отладки —
очевидные и не очень
Отладку можно значительно упростить, используя доступ- ные инструменты. Инструментов, способных забить осино- вый кол в сердце дефекта-вампира, еще не существует, но с каждым годом они становятся все лучше и лучше.
Утилиты сравнения исходного кода
Утилиты сравнения исходного кода (такие как Diff) полезны при исправлении ошибок. Если после внесения нескольких изменений некоторые из них нужно отменить, но вы плохо помните, что именно вы изменяли, утилита сравнения исходного кода освежит вашу память, указав на различия кода. Если вы обнару- жили в новой версии кода дефект, которого не было в предыдущей версии, про- сто сравните соответствующие файлы.
Предупреждающие сообщения компилятора
Одним из самых простых и эффективных инструментов отладки явля- ется сам компилятор.
Задайте в компиляторе максимально строгий уровень диагностики и
устраняйте все ошибки и предупреждения Игнорировать сообщения ком- пилятора об ошибках глупо, но отключать вывод предупреждений еще глупее. Детям иногда кажется, что, если они закроют глаза и перестанут вас видеть, вы пропа- дете. Отключая вывод предупреждений, вы совершаете такую же ошибку: вы лишь перестаете их видеть, но их причины никуда не исчезают.
Исходите из того, что разработчики компилятора знают язык гораздо лучше вас.
Если они о чем-то вас предупреждают, рассматривайте это как возможность уз- нать о языке что-то новое. Стремитесь понять подлинный смысл каждого предуп- реждения.
Рассматривайте предупреждения как ошибки Некоторые компиляторы по- зволяют рассматривать предупреждения как ошибки. Одно из достоинств этой
Перекрестная ссылка Граница между инструментами тестиро- вания и отладки размыта. Об инструментах тестирования см.
раздел 22.5, а об инструментах разработки ПО — главу 30.

546
ЧАСТЬ V Усовершенствование кода функции в том, что она повышает важность предупреждений. Как перевод часов на пять минут вперед заставляет думать, что сейчас на пять минут больше, чем на самом деле, так и указание компилятору считать предупреждения ошибками зас- тавляет воспринимать их более серьезно. Кроме того, эта функция часто влияет на процесс компиляции программы. При компиляции и компоновке программы предупреждения в отличие от ошибок обычно не предотвращают компоновку. Если вы хотите проверить предупреждения перед компоновкой, прикажите компиля- тору рассматривать предупреждения как ошибки.
Стандартизуйте параметры компиляции в масштабе всего проекта
Разработайте стандарт, требующий, чтобы все участники проекта компилирова- ли код, используя одинаковые параметры. Иначе при интеграции кода, скомпи- лированного с использованием разных параметров, вы утонете в сообщениях об ошибках и сами узнаете, что такое интеграционный кошмар. Стандарт легко на- вязать, создав один общий make-файл или сценарий сборки программы.
Утилиты расширенной проверки синтаксиса и логики
Существуют инструменты, проверяющие код тщательнее, чем компилятор. Так,
программисты на C используют утилиту lint, которая старательно ищет неиници- ализированные переменные (возникающие, например, при написании
= = вмес- то
=) и похожие тонкие проблемы.
Инструменты профилирования выполнения программы
Вам может показаться, что инструменты профилирования не имеют отношения к отладке, но на самом деле несколько минут, потраченных на изучение профиля программы, могут указать на некоторые неожиданные (и скрытые) дефекты.
Например, при работе над одной из программ у меня возникло подозрение, что метод управления памятью снижает быстродействие программы. Модуль управ- ления памятью изначально был небольшим компонентом, использующим линей- но упорядоченный массив указателей на области памяти. Я заменил линейно упо- рядоченный массив на хэш-таблицу, ожидая, что время выполнения кода сокра- тится минимум вдвое. Однако при профилировании кода я не обнаружил изме- нения быстродействия. Тщательнее изучив код, я обнаружил дефект в алгоритме выделения памяти, приводивший к огромным тратам времени. Узкое место было обусловлено не линейным поиском, а дефектом. Алгоритм поиска вообще можно было не оптимизировать. Исследуйте результаты работы инструмента профили- рования, чтобы гарантировать, что каждая часть программы выполняется за ра- зумный интервал времени.
Среды тестирования и леса
Как уже было сказано в разделе 23.2 в отношении поиска дефектов, выделение проблемного фрагмента кода и его тестирование в изоляции от других фрагментов часто ока- зывается самым эффективным способом изгнания бесов из дефектной программы.
Перекрестная ссылка О лесах см. подраздел «Создание лесов для тестирования отдельных классов» раздела 22.5.

ГЛАВА 23 Отладка
547
Отладчики
Коммерческие отладчики непрерывно совершенствуются и могут значительно изменить ваш способ программирования. Хорошие отладчики позволяют преры- вать выполнение программы на конкретной строке, при достижении конкретной строки в
n-й раз, при изменении глобальной переменной или при присвоении переменной конкретного значения. Они позволяют выполнять код строка за стро- кой с «перешагиванием» через методы или с их «посещением», возвращаться к началу дефектного фрагмента, а также регистрировать выполнение отдельных операторов в журнале, что похоже на разбрасывание по всей программе команд печати «Я здесь!».
Хорошие отладчики позволяют полностью исследовать данные, в том числе струк- турированные и динамически выделенные. С их помощью легко просмотреть со- держание связного списка указателей или динамически выделенного массива. Они поддерживают типы данных, определенные пользователем. Они позволяют выпол- нить нерегламентированный запрос данных, присвоить им новые значения и про- должить выполнение программы.
Вы можете работать с высокоуровневым языком или ассемблерным кодом, сге- нерированным компилятором. Если вы используете несколько языков, отладчик автоматически выводит любой фрагмент кода на соответствующем языке. Вы можете изучить цепочку вызовов методов и быстро увидеть исходный код любо- го метода. В среде отладчика вы можете изменять параметры программы.
Лучшие отладчики запоминают параметры отладки (точки прерывания, отслежи- ваемые переменные и т. д.) каждой отдельной программы, чтобы их не нужно было задавать заново.
Системные отладчики работают на системном, а не прикладном уровне, не влияя на выполнение отлаживаемой программы. Это важно, если вы отлаживаете про- грамму, чувствительную ко времени выполнения или объему доступной памяти.
Если учесть все достоинства отладчиков, может показаться странным, что кто-то их критикует. И все же некоторые из самых уважаемых людей в мире компьютерных наук реко- мендуют их не использовать. Они советуют полагаться на свой ум и избегать инструментов отладки вообще. Они утверждают, что инструменты отладки — это костыли и что вы решите проблемы быстрее и лучше, размышляя о них, а не опираясь на инструменты. Они утверждают, что при по- иске дефектов программу нужно выполнять в уме, а не в отладчике.
Какими бы ни были эмпирические данные, суть нападок на отладчики некоррек- тна. Если инструмент допускает неграмотное применение, это не значит, что от него надо отказаться. Было бы глупо запретить аспирин из-за возможности пере- дозировки. Риск пораниться не заставил бы вас прекратить подстригать лужайку перед домом. Любой эффективный инструмент можно использовать правильно и неправильно. Отладчик — не исключение.
Интерактивный отладчик — ве- ликолепный пример инструмен- та, который не нужен: он поощ- ряет хакерство методом проб и ошибок, а не систематичное проектирование и позволяет непрофессионалам скрыть свою некомпетентность.
Харлан Миллз
(Harlan Mills)

548
ЧАСТЬ V Усовершенствование кода
Отладчик не заменит грамотного рассуждения. Но иногда никакие мыс- ли не заменят хороший отладчик. Наиболее эффективная комбинация —
ясный ум и хороший отладчик.
Контрольный список: отладка
Методики поиска дефектов
 Формулируя гипотезу, используйте все имеющиеся данные.
 Детализируйте тесты, приводящие к ошибке.
 Проверяйте код при помощи блочных тестов.
 Используйте разные доступные инструменты.
 Воспроизведите ошибку несколькими разными способами.
 Генерируйте больше данных для формулирования большего числа гипотез.
 Используйте результаты отрицательных тестов.
 Используйте «мозговой штурм» для построения нескольких гипотез.
 Составьте список подходов, которые следует попробовать.
 Сократите подозрительную область кода.
 С подозрением относитесь к классам и методам, которые содержали дефекты ранее.
 Проверьте код, который был изменен недавно.
 Расширьте подозрительный фрагмент кода.
 Выполняйте интеграцию инкрементно.
 Проверяйте наличие распространенных дефектов.
 Обсудите проблему с кем-то другим.
 Отдохните от проблемы.
 Установите сроки быстрой и грязной отладки.
 Составьте список методик грубой силы и используйте их.
Методики поиска и исправления синтаксических ошибок
 Не полагайтесь на номера строк в сообщениях компилятора.
 Не доверяйте сообщениям компилятора.
 Не доверяйте второму сообщению компилятора.
 Разделяй и властвуй.
 Используйте редактор с проверкой синтаксиса для поиска неверно разме- щенных символов комментария и кавычек.
Методики устранения дефектов
 Прежде чем браться за решение проблемы, поймите ее.
 Не ограничивайтесь пониманием проблемы — поймите программу.
 Подтвердите диагноз проблемы.
 Расслабьтесь.
 Сохраняйте первоначальный исходный код.
 Устраняйте проблему, а не ее симптомы.
 Изменяйте код только при наличии веских оснований.
 Вносите в код по одному изменению за раз.
 Проверяйте исправления.
 Добавляйте в набор тестов блочные тесты, приводящие к проявлению име- ющихся дефектов.
 Поищите похожие дефекты.
http://cc2e.com/2368

1   ...   63   64   65   66   67   68   69   70   ...   104


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