Совершенный код. Совершенный код. Мастер-класс. Стив Макконнелл. Руководство по стилю программирования и конструированию по
Скачать 5.88 Mb.
|
ГЛАВА 9 Процесс программирования с псевдокодом 217 Пример заголовка метода Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. Написав общий комментарий, добавьте высокоуровневый псевдокод: Пример псевдокода метода Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. Установить статус по умолчанию в “сбой”. Найти сообщение, соответствующее коду ошибки. Если код ошибки корректен Если работа в интерактивном режиме, вывести сообщение и указать успешный статус. Если работа в режиме командной строки, запротоколировать сообщение об ошибке и указать успешный статус. Если код ошибки некорректен, информировать пользователя об обнаружении внутренней ошибки. Вернуть статус Еще раз: этот псевдокод достаточно высокого уровня, он не содержит конструк# ций языка программирования, а объясняет последовательность действий на ес# тественном языке. Продумайте применение данных К структуре данных можно подходить с разных позиций. В нашем примере дан# ные простые, и манипуляция над ними не является суще# ственной частью метода. В противном случае важно проду# мать основные фрагменты данных до построения логики метода. Когда вы буде# те строить логику метода, структуры основных типов данных окажутся весьма полезны. Проверьте псевдокод Написав псевдокод и спроектиро# вав данные, уделите минутку просмотру написанного. Заду# майтесь, как бы вы объяснили это кому#то другому. Попросите кого#нибудь прочитать написанное или выслушать ваше объяснение. Вам может показаться глупым просить коллегу посмотреть на какие#то 11 строк псевдокода, но результат вас удивит. Псевдокод более явно обозначит ваши оши# бочные намерения, чем код на языке программирования. К тому же люди охот# ней просматривают несколько строк псевдокода своих коллег, чем 35 строк про# граммы на C++ или Java. Перекрестная ссылка Об ис- пользовании переменных см. главы 10–13. Перекрестная ссылка О методи- ках обзоров см. главу 21. 218 ЧАСТЬ II Высококачественный код Убедитесь, что вы имеете четкое представление о том, что и как делает метод. Если вы не понимаете его концептуально, на уровне псевдокода, какой же тогда у вас шанс разобраться в нем на уровне языка программирования? Если его не пони# маете вы, кто его поймет? Опишите несколько идей псевдокодом и выберите луч' шую (пройдите по циклу) Прежде чем кодировать, ре# ализуйте как можно больше своих идей в псевдокоде. При# ступив к кодированию, вы эмоционально вовлекаетесь в этот процесс, и вам труднее отказаться от плохого проекта и начать заново. Общая идея: раз за разом проходиться по псевдокоду, пока каждое его предложе# ние не станет настолько простым, что под ним можно будет вставить строку про# граммы, а псевдокод оставить в качестве документации. Часть псевдокода, напи# санного при первых проходах, может оказаться достаточно высокоуровневой и потребовать дальнейшей декомпозиции. Не забывайте это сделать. Если вам не понятно, как закодировать какой#то фрагмент, продолжайте работать с псевдо# кодом, пока это не прояснится. Продолжайте уточнение и декомпозицию, пока это не будет выглядеть как напрасная трата времени по сравнению с написанием настоящего кода. Кодирование метода Спроектировав метод, приступайте к его конструированию. Конструирование можно производить в стандартном порядке, а при необходимости отступить от него (рис. 9#3). Рис. 9'3. Вы пройдете все эти этапы, но не обязательно именно в такой последовательности Объявление метода Напишите интерфейсный оператор метода: объявление функции на C++, метода на Java, функции или подпрограммы на Microsoft Visual Basic и т. д. в зависимости от применяемого языка. Превратите существующий Перекрестная ссылка Об итера- циях см. раздел 34.8. ГЛАВА 9 Процесс программирования с псевдокодом 219 заголовочный комментарий в комментарий соответствующего языка и оставьте его над уже написанным псевдокодом. Вот интерфейсный оператор и заголовок нашего примера на C++: Пример интерфейса метода и заголовка, добавленных к псевдокоду (C++) Это заголовочный комментарий, превращенный в комментарий C++. /* Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. */ Это интерфейсный оператор. Status ReportErrorMessage( ErrorCode errorToReport ) Установить статус по умолчанию в “сбой”. Найти сообщение, соответствующее коду ошибки. Если код ошибки корректен Если работа в интерактивном режиме, вывести сообщение и указать успешный статус. Если работа в режиме командной строки, запротоколировать сообщение об ошибке и указать успешный статус. Если код ошибки некорректен, информировать пользователя об обнаружении внутренней ошибки. Вернуть статус. Изменение псевдокода на высокоуровневые комментарии Добавим первый и последний оператор: { и } на C++ и превратим псевдокод в комментарии: Пример первого и последнего оператора вокруг псевдокода (C++) /* Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. */ Status ReportErrorMessage( ErrorCode errorToReport ) { С этого места предложения псевдокода заменены на комментарии C++. // Установить статус по умолчанию в “сбой”. // Найти сообщение, соответствующее коду ошибки. // Если код ошибки корректен // Если работа в интерактивном режиме, вывести сообщение // и указать успешный статус. > > > 220 ЧАСТЬ II Высококачественный код // Если работа в режиме командной строки, запротоколировать // сообщение об ошибке и указать успешный статус. // Если код ошибки некорректен, информировать пользователя // об обнаружении внутренней ошибки. // Вернуть статус. } Теперь роль метода очевидна. Проектные работы закончены, и вы без всякого кода видите, как работает метод. Напишите код под каждым комментарием Добавьте код под каждой строкой комментария. Это напоминает на# писание курсовой работы: сначала вы пишете план, а затем, под каждым его пунктом, — абзац текста. Каждый коммен# тарий соответствует блоку или абзацу кода. Длина абзаца кода, как и длина абзаца литературного текста, зависит от высказываемой мысли, а его качество — от понимания автором сути. Пример добавления кода к комментариям (C++) /* Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. */ Status ReportErrorMessage( ErrorCode errorToReport ) { // Установить статус по умолчанию в “сбой”. Добавленный код. Status errorMessageStatus = Status_Failure; // Найти сообщение, соответствующее коду ошибки. Новая переменная errorMessage. Message errorMessage = LookupErrorMessage( errorToReport ); // Если код ошибки корректен. // Если работа в интерактивном режиме, вывести сообщение // и указать успешный статус. // Если работа в режиме командной строки, запротоколировать // сообщение об ошибке и указать успешный статус. // Если код ошибки некорректен, информировать пользователя // об обнаружении внутренней ошибки. // Вернуть статус. } Перекрестная ссылка В этом случае подходит литературная метафора, о которой см. под- раздел «Литературная метафо- ра: написание кода» раздела 2.3. > > ГЛАВА 9 Процесс программирования с псевдокодом 221 Это только начало написания кода. Поскольку используется переменная error% Message, ее нужно объявить. Если вы вносите комментарии после написания кода, двух строк комментария на две строки кода почти всегда будет достаточно. При данном же подходе важно семантическое содержание комментариев, а не число строк кода, к которым они относятся. Комментарии уже есть и описывают дей# ствия кода, так что оставьте их все. Далее нужно добавить код ко всем оставшимся комментариям: Пример законченного метода, созданного посредством Процесса Программирования Псевдокода (C++) /* Этот метод выводит сообщение об ошибке на основании кода ошибки, получаемого от вызывающей программы. Способ вывода сообщения зависит от режима работы, который он определяет сам. Он возвращает значение, указывающее на успешное завершение или сбой. */ Status ReportErrorMessage( ErrorCode errorToReport ) { // Установить статус по умолчанию в “сбой”. Status errorMessageStatus = Status_Failure; // Найти сообщение, соответствующее коду ошибки. Message errorMessage = LookupErrorMessage( errorToReport ); // Если код ошибки корректен. Отсюда начинаем добавлять код для каждого комментария. if ( errorMessage.ValidCode() ) { // Определяем метод обработки. ProcessingMethod errorProcessingMethod = CurrentProcessingMethod(); // Если работа в интерактивном режиме, вывести сообщение // и указать успешный статус. if ( errorProcessingMethod == ProcessingMethod_Interactive ) { DisplayInteractiveMessage( errorMessage.Text() ); errorMessageStatus = Status_Success; } // Если работа в режиме командной строки, запротоколировать // сообщение об ошибке и указать успешный статус. Этот код — хороший кандидат стать новым методом: DisplayCommandLineMessage(). else if ( errorProcessingMethod == ProcessingMethod_CommandLine ) { CommandLine messageLog; if ( messageLog.Status() == CommandLineStatus_Ok ) { messageLog.AddToMessageQueue( errorMessage.Text() ); messageLog.FlushMessageQueue(); errorMessageStatus = Status_Success; } > > 222 ЧАСТЬ II Высококачественный код Эти код и комментарий новые и являются результатом развертывания оператора if. else { // Не можем ничего делать, так как процедура // сама занимается обработкой ошибки. } Это тоже новый код и комментарий. else { // Не можем ничего делать, так как процедура // сама занимается обработкой ошибки. } } // Если код ошибки некорректен, извещаем пользователя // об обнаружении внутренней ошибки. else { DisplayInteractiveMessage( “Internal Error: Invalid error code in ReportErrorMessage()” ); } // Вернуть статус. return errorMessageStatus; } К каждому комментарию добавлена одна или несколько строк кода. Каждый блок кода выражает некоторое намерение, описанное комментариями. Все перемен# ные объявлены и определены рядом с местом их первого использования. Каждый комментарий обычно разворачивается в 2–10 строк кода. Теперь вернемся к спецификации и псевдокоду. Первоначальная спецификация из пяти предложений превратилась в 15 строк псевдокода, которые в свою оче# редь развернуты в метод размером в страницу. Хотя спецификация и была доста# точно подробной, создание метода потребовало проектировочных работ при написании псевдокода и кодировании. Это низкоуровневое проектирование и есть одна из причин, по которой «кодирование» является нетривиальной задачей. Проверьте, не нужна ли дальнейшая декомпозиция кода В некоторых слу# чаях вы увидите, что код, соответствующий одной изначальной строке псевдоко# да, существенно разросся. В таких ситуациях следует предпринять одно из следу# ющих действий. Преобразуйте код, соответствующий комментарию, в но# вый метод. Дайте методу имя и напишите код вызова этого метода. Если вы правильно применяли ППП, имя метода вы легко придумаете на основе псевдокода. Закончив работу с изначальным ко# дом, переходите к вновь созданным методам и применяйте ППП к ним. Применяйте ППП рекурсивно. Вместо того чтобы писать несколько десятков строк кода для одной строки псевдокода, разбейте эту строку псевдокода на несколько предложений и для каждой из них напишите код. Перекрестная ссылка О рефак- торинге см. главу 24. > > ГЛАВА 9 Процесс программирования с псевдокодом 223 Проверка кода Третий шаг после проектирования и реализации метода — его проверка. Все ошибки, которые вы пропустите на этом этапе, вы сможете обнаружить лишь при позднейшем тестировании, что обойдется вам дороже. Ошибка может не проявиться до окончательного кодирова# ния по нескольким причинам. Ошибка в псевдокоде может стать заметнее при детальной реализации. Конструкция, выглядящая элегантно в псевдокоде, на языке программиро# вания может стать топорной. Проработка детальной реали# зации может выявить ошибку архитектуры, проекта или требований. Наконец, код может содержать самые банальные ошибки программирования — никто не совер# шенен! По всем этим причинам пересмотрите код, прежде чем двигаться дальше. Умозрительно проверьте ошибки в методе Первая формальная проверка метода — умозрительная. Мысленно выполните все ветви метода. Сделать это не# просто, что и является одной из причин писать короткие методы. Проверьте все возможные ветви и исключительные условия. Проделайте это сами и с коллегами. Одно из основных различий между любителями и профессиональными программистами — различие, появляющееся при переходе от суеверия к пониманию. Под суеверием здесь я понимаю не иллюзию, что програм# ма выдает больше ошибок в полнолуние, а замену «прочувствования» программы ее пониманием. Если вы часто обнаруживаете, что подозреваете компилятор или аппаратные средства в ошибке, вы в плену суеверий. Давнишние исследования по# казали, что только около 5% всех ошибок связано с аппаратурой, компиляторами или ОС (Ostrand and Weyuker, 1984). Сейчас этот процент, видимо, еще меньше. Программист, достигший сферы понимания, обращает внимание прежде всего на свое творение, являющееся потенциальным источником 95% ошибок. Нужно знать роль каждой строки своей программы. Ничто не может называться верным толь# ко потому, что выглядит работоспособным. Если вы не знаете, почему это рабо# тает, вероятно, оно и не работает на самом деле. Итог: работающий метод — это еще не все. Если вы не знаете, как он ра# ботает, изучайте его, обсуждайте его, экспериментируйте с альтернатив# ными вариантами, пока не добьетесь понимания. Компиляция метода Проверив метод, скомпилируйте его. Может показаться неэффективным так долго откладывать компиляцию. Вероятно, вы уменьшите себе работу, скомпилировав метод ранее и позволив компилятору проверить необъяв# ленные переменные, обнаружить конфликты имен и т. д. Между тем, отложив трансляцию на более поздний срок, вы получите ряд преиму# ществ. Основная причина в том, что, когда вы компилируете новый код, в вас начинают тикать внутренние часики. После первой трансляции появляется мысль: «Еще всего одна компиляция, и дело сделано». Этот синдром «еще всего одной компиляции» подвигает вас к скороспелым, чреватым ошибками изменениям, которые в долгосрочном плане увеличивают общее время работы. Не спешите и не компилируйте программу, пока не будете уверены, что она верна. Перекрестная ссылка О поиске ошибок при построении архи- тектуры и выработке требований см. главу 3. 224 ЧАСТЬ II Высококачественный код Вот несколько советов по эффективной компиляции. Установите наивысший уровень предупреждений компилятора. Вы можете от# ловить изрядное число ошибок, лишь позволив компилятору их обнаруживать. Применяйте проверяющие средства. Встроенные проверяющие средства ком# пиляторов могут быть дополнены внешними, такими как lint для С. Даже не# компилируемый код, скажем, HTML и JavaScript, можно проверить соответству# ющими утилитами. Выясните причину всех сообщений об ошибках и предупреждений. Подумай# те, что сообщение говорит о вашем коде. Многие предупреждения зачастую указывают на низкое качество кода, и вам следует попытаться понять смысл каждого предупреждения. На практике предупреждения, которые вы видите раз за разом, вызывают одну из двух реакций: вы или не обращаете на них внима# ния, и они скрывают от вашего взгляда более важные предупреждения, или они попросту вас раздражают. Как правило, проще и безболезненней переписать код, решив проблему, вызывающую предупреждения, и, таким образом, изба# виться от них. Пройдите по коду отладчиком Скомпилировав метод, запустите его в отладчике и пройдите по каждой строке кода. Убедитесь, что каждая строка выполняется так, как вы ожи# даете. Следуя этому простому совету, вы сможете найти мно# го ошибок. Протестируйте код Протестируйте код, используя те# стовые примеры, которые вы запланировали или уже создали при разработке метода. Возможно, вы создали леса для поддержки тестирования, т. е. код, поддер# живающий методы при тестировании и не включаемый в конечный продукт. Леса могут представлять собой методы — тестовые сбруи, которые вызывают ваш ме# тод с тестовыми данными, или заглушки, вызываемые вашим методом. Удалите ошибки из метода Обнаруженные ошибки нужно удалить. Если к этому моменту ваш метод работает нестабильно, велика вероятность, что он таким и останет# ся. Обнаружив непонятное поведение метода, начните все заново. Не пытайтесь доводить его до ума — перепишите его. Изощренные переделки обычно говорят о неполном понимании и гарантируют возникновение ошибок как сейчас, так и в будущем. Полное перепроектирование нестабильного метода полностью оправ# данно. Мало что сравнится по эффективности с переписыванием проблемного метода — вы позабудете о бывших ошибках. Наведение глянца Проверив код, оцените его с учетом общих критериев, описанных в этой книге. Чтобы гарантировать соответствие качества метода высоким стандартам, сделай# те следующее. Проверьте интерфейс метода. Убедитесь, что применяются все входные и вы# ходные данные и используются все параметры (см. раздел 7.5). Перекрестная ссылка Подроб- ности см. в главе 22 и подраз- деле «Создание лесов для тес- тирования отдельных классов» раздела 22.5. Перекрестная ссылка Подроб- ности см. в главе 23. |