Совершенный код. Совершенный код. Мастер-класс. Стив Макконнелл. Руководство по стилю программирования и конструированию по
Скачать 5.88 Mb.
|
ГЛАВА 32 Самодокументирующийся код 767 моих комментариев исчезает. После рефакторинга мой код может включать 20 или 30 вызовов методов, не нуждающихся в каких бы то ни было комментариях. Хороший программист способен определять цель автора по самому коду; к тому же какой толк в чтении о чьей#то цели, если известно, что код содержит ошибку? Главкон умолкает, удовлетворенный своим вкладом в беседу. Калликл кивает. — Похоже, вам никогда не приходилось изменять чужой код, — говорит Исмена. Калликл делает вид, что его очень заинтересовали плитки на потолке. — Почему бы вам не попробовать прочитать собственный код через шесть меся# цев или год после его написания? Вы можете развивать и навык чтения кода, и навык его комментирования. Никто не заставляет вас выбирать что#то одно. Если вы чи# таете роман, вам, может, и не нужны названия глав. Но при чтении технической книги вам, наверное, хотелось бы иметь возможность быстро найти то, что вы ищете. Тогда мне не пришлось бы переходить в режим сверхсосредоточенности и читать сотни строк кода для нахождения двух строк, которые я хочу изменить. — Хорошо, я понимаю, что возможность быстрого просмотра кода была бы удоб# ной, — говорит Главкон. Он видел некоторые из программ Исмены, и они не ос# тавили его равнодушным. — Но как быть с другим утверждением Калликла — что комментарии устаревают по мере изменений кода? Я программирую лишь пару лет, но даже я знаю, что никто не обновляет свои комментарии. — Ну, и да, и нет, — говорит Исмена. — Если вы считаете комментарии неприкос# новенными, а код подозрительным, у вас серьезные проблемы. На самом деле не# соответствие между комментарием и кодом обычно говорит о том, что неверно и то, и другое. Если какие#то комментарии плохи, это не означает, что само ком# ментирование плохо. Пойду налью себе еще чашку кофе. Исмена выходит из комнаты. — Мое главное возражение против комментариев, — заявляет Калликл, — в том, что они тратят ресурсы. — Можете ли вы предложить способ минимизации времени написания коммен# тариев? — спрашивает Сократ. — Проектирование методов на псевдокоде, преобразование псевдокода в коммента# рии и написание соответствующего им кода, — говорит Главкон. — OK, это сработает, если комментарии не будут повторять код, — утверждает Кал# ликл. — Написание комментария заставляет вас лучше подумать над тем, что делает ваш код, — говорит Исмена, возвращаясь с новой чашкой кофе. — Если комментарии писать трудно, это означает, что код плох или вы недостаточно хорошо его по# нимаете. В обоих случаях вы должны поработать над кодом еще, так что время, потраченное на его комментирование, не пропадает — оно указывает вам на не# обходимую работу. — Хорошо, — подводит итоги Сократ. — Не думаю, что у нас остались еще вопро# сы. Похоже, Исмена сегодня была самой убедительной. Мы будем поощрять ком# ментирование, но не будем относиться к нему простодушно. Мы будем выполнять обзоры кода, чтобы все поняли, какие комментарии на самом деле полезны. Если у вас возникнут проблемы с пониманием кода другого программиста, подскажи# те ему, как он может его улучшить. 768 ЧАСТЬ VII Мастерство программирования 32.4. Советы по эффективному комментированию Что делает следующий метод? Загадочный метод номер один (Java) // вывод сумм чисел 1..n для всех n от 1 до num current = 1; previous = 0; sum = 1; for ( int i = 0; i < num; i++ ) { System.out.println( “Sum = “ + sum ); sum = current + previous; previous = current; current = sum; } Этот метод вычисляет первые num чисел Фибоначчи. Стиль кодирования этого метода чуть лучше, чем стиль метода, указанного в начале главы, но комментарий неверен, и если вы слепо доверяете комментариям, то, пребывая в блаженном неведении, пойдете в неверном направлении. А что скажете по поводу этого метода? Загадочный метод номер два (Java) // присваивание переменной “product” значения переменной “base” product = base; // цикл от 2 до “num” for ( int i = 2; i <= num; i++ ) { // умножение “base” на “product” product = product * base; } System.out.println( “Product = “ + product ); Этот метод возводит целое число base в целую степень num. Комментарии в этом методе верны, но они не говорят о коде ничего нового. Это просто более много# словная версия самого кода. Наконец, еще один метод: Загадочный метод номер три (Java) // вычисление квадратного корня из Num с помощью аппроксимации НьютонаРафсона r = num / 2; while ( abs( r (num/r) ) > TOLERANCE ) { r = 0.5 * ( r + (num/r) ); } System.out.println( “r = “ + r ); Пока существуют плохо опреде- ленные цели, странные ошибки и нереалистичные сроки, будут существовать и Настоящие Про- граммисты, желающие немед- ленно приступить к Решению Проблемы и оставляющие доку- ментацию на потом. Да здрав- ствует Фортран! Эд Пост (Ed Post) ГЛАВА 32 Самодокументирующийся код 769 Этот метод вычисляет квадратный корень из num. Код неидеален, но коммента# рий верен. Какой метод понять было легче всего? Все они написаны довольно плохо — осо# бенно неудачны имена переменных. По сути эти методы иллюстрируют достоин# ства и недостатки внутренних комментариев. Комментарий Метода 1 неверен. Комментарии Метода 2 просто повторяют код и потому бесполезны. Только ком# ментарий Метода 3 оправдывает свое существование. Наличие плохих коммента# риев хуже, чем их отсутствие. Методы 1 и 2 лучше было бы оставить вообще без комментариев. В следующих подразделах я приведу советы по написанию эффективных коммен# тариев. Виды комментариев Комментарии можно разделить на шесть категорий, описанных ниже. Повторение кода Повторяющий комментарий переформулирует код иными словами и только за# ставляет больше читать, не предоставляя дополнительной информации. Объяснение кода Такие комментарии обычно служат для объяснения сложных, хитрых или неста# бильных фрагментов кода. В этих ситуациях они полезны, но обычно только потому, что код непонятен. Если код настолько сложен, что требует объяснения, почти всегда разумнее улучшить код, а не добавлять комментарии. Сделайте сам код более ясным, а потом добавьте в него резюмирующие комментарии или ком# ментарии цели. Маркер в коде Этот тип предназначен не для того, чтобы оставаться в коде. Такая пометка ука# зывает программисту на то, что работа еще не выполнена. Некоторые разработ# чики делают маркеры синтаксически некорректными (например, ******), чтобы о невыполненной работе напомнил компилятор. Другие включают в комментарии определенный ряд символов, не приводящий к ошибке компиляции и служащий для поиска нужного фрагмента. Мало что может сравниться с чувствами программиста, получившего от заказчика сообщение о проблеме в коде и увидевшего во время отладки что#нибудь вроде: return NULL; // ****** НЕ СДЕЛАНО! ИСПРАВИТЬ ДО ВЫПУСКА ПРОГРАММЫ!!! Если вы поставили заказчикам дефектную программу, это плохо; если же вы зна% ли, что она дефектна, это просто ужасно. Стандартизуйте стиль комментариев#маркеров, иначе одни программисты будут использовать для этого символы *******, другие — !!!!!!, третьи — TBD, а четвертые — что#то еще. Применение разных нотаций повышает вероятность ошибок при механическом поиске незавершенных фрагментов кода или вообще делает его невозможным. Стандартизация стиля маркирования позволяет сделать механичес# 770 ЧАСТЬ VII Мастерство программирования кий поиск незавершенных фрагментов одним из действий контрольного списка перед выпуском программы и предотвратить проблему ИСПРАВИТЬ ДО ВЫПУС% КА!!!. Некоторые редакторы поддерживают теги «to do» и позволяют легко искать их. Резюме кода Резюмирующие комментарии выражают суть нескольких строк кода в одном#двух предложениях. Эти комментарии более полезны, чем повторяющие, потому что программист, читающий программу, может просматривать их быстрее, чем код. Резюмирующие комментарии особенно полезны, если программу будет изменять не только ее автор. Описание цели кода Комментарий уровня цели объясняет намерения автора кода. Такие комментарии относятся скорее к уровню проблемы, чем к уровню ее решения. Например, ком# ментарий: получение информации о текущем сотруднике является комментарием цели, тогда как: обновление объекта employeeRecord является резюмирующим комментарием, сформулированным в терминах реше# ния. Шестимесячное исследование, проведенное в IBM, показало, что програм# мисты, отвечавшие за сопровождение программы, «чаще всего говорили, что труднее всего было понять цель автора кода» (Fjelstad and Hamlen, 1979). Раз# личие между комментариями цели и резюмирующими не всегда очевидно и обычно не играет особой роли. В этой главе вы найдете массу примеров комментариев цели. Информация, которую невозможно выразить в форме кода Кое#какую информацию, не выразимую в форме кода, все#таки нужно включить в программу. Эта категория комментариев включает уведомления об авторских пра# вах и конфиденциальности данных, номера версий и другие детали, замечания о структуре кода, ссылки на релевантные документы требований или архитектуры, ссылки на Интернет#ресурсы, соображения по оптимизации, комментарии, нужные таким инструментам редактирования, как Javadoc, Doxygen и т. д. К трем видам комментариев, приемлемых в готовом коде, относятся резюмирую# щие комментарии, комментарии цели и информация, не выразимая в форме кода. Эффективное комментирование Эффективное комментирование отнимает не так много времени. Избыток ком# ментариев не менее плох, чем недостаток, а оптимальной середины можно до# стичь без особых проблем. Написание комментариев может отнимать много времени по двум причинам. Во# первых, стиль комментирования может быть трудоемким или нудным. Если это ГЛАВА 32 Самодокументирующийся код 771 так, измените стиль. Стиль комментирования, требующий значительных усилий, очень трудно сопровождать. Если комментарии трудно изменять, их просто не будут изменять, из#за чего они станут неверными и обманчивыми, что хуже, чем пол# ное отсутствие комментариев. Во#вторых, комментирование может быть сложным из#за трудностей с формули# рованием действий программы в словах. Обычно это говорит о том, что вы не понимаете работу программы. Время, уходящее на «комментирование», на самом деле тратится на лучшее понимание программы, и его все равно придется потра# тить, комментируете вы код или нет. Вот некоторые рекомендации по эффективному комментированию. Используйте стили, не препятствующие изменению комментариев Под# держивать слишком причудливый стиль надоедает. Попробуйте, например, опре# делить часть следующего комментария, которую никто не будет поддерживать: Пример стиля комментирования, который трудно поддерживать (Java) // Переменная Смысл // ————— // xPos .......... Координата X (в метрах) // yPos .......... Координата Y (в метрах) // ndsCmptng...... Требуется ли вычисление? (= 0, если вычисление требуется; // = 1, если вычисление не требуется) // ptGrdTtl....... Общее число точек // ptValMax....... Максимальное значение в точке // psblScrMax..... Максимально возможная сумма Если вы подумали про точки ( .....), вы совершенно правы! Красиво, конечно, но спи# сок хорош и без них. Точки затрудняют изменение комментариев, и, если есть вы# бор (а он обычно есть), комментарии лучше сделать правильными, чем красивыми. Вот пример другого популярного стиля, трудного в сопровождении: Пример стиля комментирования, который трудно поддерживать (C++) /********************************************************************** * класс: GigaTron (GIGATRON.CPP) * * * * автор: Дуайт К. Кодер * * дата: 4 июля 2014 года * * * * Методы, управляющие самым передовым инструментом оценки кода. * * Точкой входа в эти методы является метод EvaluateCode(), * * расположенный в конце файла. * **********************************************************************/ Это симпатичный блочный комментарий. По оформлению ясно, что весь блок — единое целое; начало и окончание блока также бросаются в глаза. Что неясно, так это легкость изменения этого блока. При его изменении почти наверняка при# дется заново выстраивать аккуратные столбцы звездочек. На практике это озна# чает, что из#за слишком большого объема работы такой комментарий поддержи# 772 ЧАСТЬ VII Мастерство программирования вать не будут. Если можно выровнять столбцы звездочек одним нажатием клави# ши, прекрасно — можете использовать этот стиль. Проблема не в звездочках, а в том, что их трудно поддерживать. Следующий комментарий выглядит почти так же хорошо, а сопровождать его куда легче: Пример стиля комментирования, который легко поддерживать (C++) /********************************************************************** класс: GigaTron (GIGATRON.CPP) автор: Дуайт К. Кодер дата: 4 июля 2014 года Методы, управляющие самым передовым инструментом оценки кода. Точкой входа в эти метода является метод EvaluateCode(), расположенный в конце файла. **********************************************************************/ Вот стиль, особенно трудный в сопровождении: Пример стиля комментирования, который трудно поддерживать (Visual Basic) ‘ настройка перечисления Color ’ ++ ’ настройка перечисления Vegetable ’ ++ Трудно сказать, какой смысл имеют плюсы в начале и в конце каждой пунктир# ной линии, зато легко догадаться, что при каждом изменении комментария эту линию придется адаптировать, чтобы конечный плюс находился на своем месте. А если комментарий перейдет на вторую строку? Что тогда вы сделаете с плюсом? Выбросите из комментария какие#то слова, чтобы он занимал только одну стро# ку? Сделаете длину обеих строк одинаковой? При попытке согласованного при# менения этой методики проблемы быстро множатся. На подобных рассуждениях основан и популярный совет использовать в Java и C++ синтаксис // для однострочных и синтаксис /* ... */ — для более длинных ком# ментариев: Пример использования разного синтаксиса комментирования с разными целями (Java) // Это короткий комментарий. /* Это гораздо более длинный комментарий. Восемьдесят семь лет назад наши отцы основали на этом континенте новую нацию, взращенную в условиях свободы, преданную принципу, согласно которому все люди созданы равными. Сейчас мы ведем великую Гражданскую войну, в которой проверяется, может ли эта нация или любая другая, воспитанная в таком же духе и преданная таким же идеалам, существовать дальше. ГЛАВА 32 Самодокументирующийся код 773 Мы встретились сейчас на поле одной из величайших битв этой войны. Мы пришли сюда для того, чтобы отвести часть этого поля для последнего места успокоения тех, кто отдал здесь свои жизни ради того, чтобы эта нация могла жить. Очень правильно, что мы делаем это. */ Первый комментарий легко сопровождать, пока он короток. Если комментарий длиннее, создание столбцов двойных слэшей, ручное разбиение текста на стро# ки и другие подобные действия начинают утомлять, поэтому для многострочных комментариев больше подходит синтаксис /* ... */. Суть сказанного в том, что вам следует обращать внимание на то, как вы тратите свое время. Если вы вводите или удаляете дефисы для выравни# вания плюсов, вы не программируете — вы занимаетесь ерундой. Най# дите более эффективный стиль. В одном из предыдущих примеров дефисы и плюсы можно было бы удалить без ущерба для комментариев. Если вы хотите подчерк# нуть какие#то комментарии, найдите иной способ, но не дефисы с плюсами. На# пример, вы могли бы подчеркивать комментарии строками, состоящими из оди# накового числа дефисов. Такие строки не требовали бы сопровождения, а для их ввода можно было бы использовать макрос текстового редактора. Используйте для сокращения времени, уходящего на комментирование, процесс программирования с псев' докодом Формулирование кода в виде комментариев пе# ред его написанием обеспечивает целый ряд преимуществ. Когда вы завершите работу над кодом, комментарии уже будут готовы. Вам не нуж# но будет выделять время на комментирование. Создавая высокоуровневый псевдо# код перед написанием соответствующего низкоуровневого кода на языке программи# рования, вы также получите все выгоды проектирования. Интегрируйте комментирование в свой стиль разработки Альтернативой интеграции комментирования в стиль разработки является откладывание коммен# тирования на конец проекта, но у этого подхода слишком много недостатков: ком# ментирование становится самостоятельной задачей и кажется более объемной работой, чем написание комментариев небольшими порциями. Комментирование, выполняемое позднее, требует больше времени, потому что вы должны вспомнить или определить, что код делает, вместо того чтобы просто написать, о чем вы ду# маете прямо сейчас. Кроме того, оно менее точно, поскольку со временем вы за# бываете предположения или тонкости, имевшие место на этапе проектирования. Противники комментирования по мере написания кода часто утверждают: «если вы сосредоточены на коде, не следует отвлекаться на написание комментариев». Однако если написание кода требует столь сильной концентрации, что коммен# тирование нарушает ход мыслей, вам на самом деле нужно спроектировать фраг# мент сначала на псевдокоде и потом преобразовать псевдокод в комментарии. Код, требующий такой сильной концентрации, — тревожный симптом. Если проект трудно закодировать, упростите его до начала работы над комментариями или кодом. Если для организации своего мышления вы будете использовать псевдокод, кодирование станет легким, а комменти# рование автоматическим. Перекрестная ссылка О процес- се программирования с псевдо- кодом см. главу 9. 774 ЧАСТЬ VII Мастерство программирования Производительность не является разумной причиной отказа от коммен' тирования Одним периодически повторяющимся атрибутом технологических волн, обсуждавшихся в разделе 4.3, являются интерпретируемые среды, в которых комментарии вызывают чувствительное снижение производительности. В 1980#х это относилось к программам, написанным на Basic. В 1990#х — к asp#страницам. Сейчас похожая проблема связана с кодом JavaScript и другим кодом, который нужно передавать по сети. В каждом из этих случаев решением является не отказ от комментариев, а созда# ние готовой версии кода, отличающейся от разрабатываемой. Как правило, для этого код «пропускают» через утилиту, удаляющую комментарии. Оптимальная плотность комментариев По данным Кейперса Джонса, исследования, проведенные в IBM, показа# ли, что понятность кода достигала пика при одном комментарии при# мерно на 10 операторов. Как меньшая, так и более высокая плотность ком# ментариев осложняла понимание кода (Jones, 2000). Подобные данные можно использовать неверно, и в проектах иногда принима# ются стандарты типа «комментарии должны встречаться в программе не реже, чем каждые пять строк кода». Этот стандарт устраняет симптом написания недоста# точно ясного кода, но не причину. Если вы эффективно используете процесс программирования с псевдокодом, вы, вероятно, тоже в итоге получите один комментарий на каждые несколько строк кода. Однако плотность комментариев будет побочным эффектом самого процесса. Вместо концентрации на плотности комментариев сосредоточьтесь на их эффек# тивности. Если комментарии будут характеризовать цель написания кода и соот# ветствовать другим критериям, указанным в этой главе, комментариев будет до# статочно. 32.5. Методики комментирования Существует несколько методик комментирования, различающихся по тому, к ка# кому уровню относится комментарий: к программе, файлу, методу, абзацу кода или отдельной строке. Комментирование отдельных строк Если код хорош, необходимость комментирования отдельных строк возникает редко. Есть две возможных причины комментирования строки кода: строка довольно сложна и потому требует объяснения; строка когда#то содержала ошибку, и вы хотите отметить это. Вот некоторые советы по комментированию отдельных строк кода. Избегайте комментариев, высосанных из пальца Много лет назад я слы# шал историю о программисте, которого подняли с постели исправить неработав# шую программу. С автором программы, который к тому времени уже оставил ком# панию, связаться было невозможно. Программист раньше не работал с этой про# |