Многие люди утверждают, что «комментарии должны объяснять« почему », а не« как »». Другие говорят, что «код должен быть самодокументированным», а комментарии должны быть скудными. Роберт К. Мартин утверждает, что (перефразируя мои собственные слова) часто «комментарии - это извинения за плохо написанный код».
Мой вопрос заключается в следующем:
Что плохого в объяснении сложного алгоритма или длинного и запутанного фрагмента кода с описательным комментарием?
Таким образом, вместо того, чтобы другие разработчики (включая вас), должны были построчно читать весь алгоритм, чтобы выяснить, что он делает, они могут просто прочитать дружеский описательный комментарий, который вы написали на простом английском языке.
Английский «разработан», чтобы его могли легко понять люди. Java, Ruby или Perl, однако, были разработаны, чтобы сбалансировать удобочитаемость и читаемость компьютером, тем самым ставя под угрозу читабельность текста человеком. Человек может понять часть английского языка намного быстрее, чем он / она может понять часть кода с тем же значением (если операция не тривиальна).
Итак, после написания сложного фрагмента кода, написанного на частично читаемом человеком языке программирования, почему бы не добавить описательный и краткий комментарий, объясняющий работу кода на дружественном и понятном английском языке?
Некоторые скажут: «Код не должен быть трудным для понимания», «сделать функции маленькими», «использовать описательные имена», «не писать код для спагетти».
Но мы все знаем, что этого недостаточно. Это простые рекомендации - важные и полезные - но они не меняют того факта, что некоторые алгоритмы являются сложными. И поэтому их трудно понять, читая их построчно.
Неужели так сложно объяснить сложный алгоритм несколькими комментариями о его общей работе? Что плохого в объяснении сложного кода комментарием?
Ответы:
С точки зрения непрофессионала:
Нижняя линия:
Объяснять себя хорошо, не нужно делать это лучше.
источник
Существует множество разных причин, по которым код может быть сложным или запутанным. В наиболее распространенных причинах , лучше всего решается с помощью рефакторинга кода , чтобы сделать его менее запутанным, не добавляя комментарии любого рода.
Тем не менее, есть случаи, когда правильно выбранный комментарий является лучшим выбором.
Если сам алгоритм сложен и запутан, а не только его реализация - та, которую пишут в математических журналах и когда-либо называли Алгоритмом Мбого, - тогда вы помещаете комментарий в самом начале реализации, читая что-то вроде «Это алгоритм Mbogo для рефробничирования виджетов, первоначально описанный здесь: [URL-адрес статьи]. Эта реализация содержит уточнения Алисы и Кэрол [URL-адрес другой статьи]». Не пытайтесь вдаваться в подробности; если кому-то нужно больше подробностей, ему, вероятно, нужно прочитать всю статью.
Если вы взяли что-то, что может быть записано в виде одной или двух строк в какой-то специализированной записи, и расширили его до большого объема императивного кода, поместите эти одну или две строки специальной записи в комментарии над функцией - хороший способ скажи читателю, что он должен делать. Это исключение из аргумента «но что, если комментарий не синхронизируется с кодом», потому что в специализированной нотации, вероятно, гораздо проще находить ошибки, чем в коде. (Это наоборот, если вы написали спецификацию на английском языке.) Хороший пример здесь: https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.cpp#1057 ...
Если код в целом прост, но содержит одну или две вещи, которые выглядят чрезмерно запутанными, ненужными или просто неправильными, но должны быть такими по причинам, то вы помещаете комментарий сразу над подозрительно выглядящим битом, в котором Вы указываете причины . Вот простой пример, где единственное, что нужно объяснить, - это почему константа имеет определенное значение.
источник
4
должно бытьCHAR_BIT / 2
;-)CHAR_BITS
было 16, а sizeof (size_t) было 2, но максимальное значение size_t было, например, 2 ^ 20 [size_t, содержащее 12 битов заполнения]?reallocarray
, и OpenBSD, как правило, не верит в удовлетворение возможностей, которых нет в их ABI.int
. Как это даноuint32_t x,y,z;
, значение(x-y) > z
зависит от размераint
. Кроме того, язык, предназначенный для написания надежного кода, должен позволять программистам различать тип, в котором вычисления должны превышать диапазон типа, и должен скрытно переноситься, по сравнению с тем, в котором вычисления, превышающие диапазон типа, должны прерываться, по сравнению с тем, где вычисления не ожидается превышение диапазона типа, но ...Это не вопрос правильного или неправильного, а «лучшая практика», как определено в статье Википедии :
Поэтому лучше всего сначала попытаться улучшить код и использовать английский, если это невозможно.
Это не закон, но гораздо чаще встречается закомментированный код, требующий рефакторинга, чем реорганизованный код, требующий комментариев, это отражается в лучших практиках.
источник
//This code seriously needs a refactor
Настанет день, когда ваш красивый, отлично разработанный, хорошо структурированный и читаемый код не будет работать. Или это не будет работать достаточно хорошо. Или возникнет особый случай, когда он не работает и нуждается в корректировке.
В этот момент вам нужно будет что-то изменить, чтобы все работало правильно. Особенно в тех случаях, когда существуют проблемы с производительностью, но также часто в сценариях, когда одна из библиотек, API, веб-сервисов, гемов или операционных систем, с которыми вы работаете, не работает должным образом, вы можете в конечном итоге сделать предложения, которые не обязательно нелегкий, но не интуитивный или неочевидный.
Если у вас нет комментариев, объясняющих, почему вы выбрали такой подход, очень велика вероятность того, что кто-то в будущем (и кто-то может даже быть вами) будет смотреть на код, посмотреть, как его можно «исправить» для что-то более читаемое и элегантное и непреднамеренно отменяет ваше исправление, потому что это не похоже на исправление.
Если бы все всегда писали идеальный код, то было бы очевидно, что код, который выглядит несовершенным, работает на основе хитрого вмешательства из реального мира, но это не так. Большинство программистов часто пишут запутанный или несколько запутанный код, поэтому, когда мы сталкиваемся с этим, это естественная склонность приводить его в порядок. Я клянусь, что мое прошлое я идиот, когда читаю старый код, который я написал.
Поэтому я не считаю комментарии извинением за плохой код, но, возможно, объяснением того, почему вы не сделали очевидного. Наличие
// The standard approach doesn't work against the 64 bit version of the Frobosticate Library
позволит будущим разработчикам, включая вас самих, обратить внимание на эту часть кода и провести тестирование на этой библиотеке. Конечно, вы также можете поместить комментарии в свои коммиты контроля версий, но люди будут смотреть на них только после того, как что-то пойдет не так. Они будут читать комментарии к коду при изменении кода.Люди, которые говорят нам, что мы всегда должны писать теоретически совершенный код, не всегда люди с большим опытом программирования в реальных условиях. Иногда вам нужно написать код, который выполняет до определенного уровня, иногда вам нужно взаимодействовать с несовершенными системами. Это не значит, что вы не можете сделать это элегантным и хорошо написанным способом, но неочевидные решения требуют объяснения.
Когда я пишу код для хобби-проектов, которые, как я знаю, больше никто не прочтет, я все равно комментирую части, которые меня смущают - например, любая трехмерная геометрия включает математику, с которой я не совсем дома - потому что я знаю, когда возвращаюсь через шесть месяцев я полностью забуду, как это делать. Это не извинение за плохой код, это признание личных ограничений. Все, что я хотел бы сделать, оставив это без комментариев, это создать больше работы для себя в будущем. Я не хочу, чтобы мое будущее я переучивалось без необходимости, если я могу избежать этого сейчас. Какую возможную ценность это будет иметь?
источник
Потребность в комментариях обратно пропорциональна уровню абстракции кода.
Например, язык ассемблера для большинства практических целей непонятен без комментариев. Вот выдержка из небольшой программы, которая вычисляет и печатает термины ряда Фибоначчи :
Даже с комментариями, это может быть довольно сложно, чтобы впустить.
Современный пример: регулярные выражения часто представляют собой конструкции с очень низкой абстракцией (строчные буквы, цифры 0, 1, 2, новые строки и т. Д.). Они, вероятно, нуждаются в комментариях в виде примеров (Боб Мартин, IIRC, признает это). Вот регулярное выражение, которое (я думаю) должно соответствовать HTTP (S) и FTP URL:
По мере развития языков в иерархии абстракций программист может использовать вызывающие абстракции (имена переменных, имена функций, имена классов, имена модулей, интерфейсы, обратные вызовы и т. Д.) Для предоставления встроенной документации. Пренебрежение этим преимуществом и использование комментариев к статье над ним - это лень, плохая услуга и неуважение к сопровождающему.
Я имею в виду Numerical Recipes в C переведен в основном дословно Numerical Recipes в C ++ , который я заключаю начал как Numerical Recipes (в FORTAN), со всеми переменными
a
,aa
,b
,c
,cc
и т.д. поддерживается с помощью каждой версии. Алгоритмы могли быть правильными, но они не использовали абстракции, предоставляемые языками. И они меня убили. Пример из статьи доктора Доббса - Быстрое преобразование Фурье :Как особый случай абстракции, у каждого языка есть идиомы / фрагменты канонического кода для определенных общих задач (удаление динамического связанного списка в C), и независимо от того, как они выглядят, они не должны документироваться. Программисты должны выучить эти идиомы, поскольку они неофициально являются частью языка.
Итак, отнимите: неидиоматический код, построенный из низкоуровневых строительных блоков, которых нельзя избежать, требует комментариев. И это необходимо WAAAAY меньше, чем это происходит.
источник
dec dword [term] ; decrement loop counter
. С другой стороны, в вашем примере на ассемблере отсутствует комментарий перед каждым «абзацем кода», объясняющий, что делает следующий блок кода. В этом случае комментарий обычно будет эквивалентен одной строке в псевдокоде, например;clear the screen
, после 7 строк, которые фактически требуется для очистки экрана.^(((ht|f)tps?)\:\/\/)?(www\.)*[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$
? Будьте в курсе числовых адресов."The need for comments is inversely proportional to the abstraction level of the code."
почти все подводит итог.Я не верю, что что-то не так с комментариями в коде. Идея, что комментарии как-то плохи, на мой взгляд, происходит из-за того, что некоторые программисты зашли слишком далеко. В этой отрасли очень много увлечений, особенно экстремальных взглядов. Где-то по пути прокомментированный код стал эквивалентен плохому коду, и я не уверен почему.
У комментариев действительно есть проблемы - вы должны держать их в курсе, когда вы обновляете код, на который они ссылаются, что происходит слишком редко. Wiki или что-то более подходящее для подробной документации о вашем коде. Ваш код должен быть читаемым без комментариев. В примечаниях к управлению версиями или ревизиям следует описывать внесенные вами изменения кода.
Однако ни одно из вышеперечисленного не лишает законной силы использование комментариев. Мы не живем в идеальном мире, поэтому, когда что-то из вышеперечисленного по какой-либо причине терпит неудачу, я бы предпочел получить некоторые комментарии.
источник
Я думаю, что вы слишком много читаете о том, что он говорит. Ваша жалоба состоит из двух частей:
(1) неизбежно. Я не думаю, что Мартин не согласится с тобой. Если вы пишете что-то вроде быстрого обратного квадратного корня , вам понадобятся некоторые комментарии, даже если это просто «злой взлом с плавающей запятой». За исключением чего-то простого, например DFS или бинарного поиска, маловероятно, что человек, читающий ваш код, будет иметь опыт работы с этим алгоритмом, и поэтому я думаю, что в комментариях должно быть хотя бы упоминание о том, что это такое.
Большая часть кода не (1), однако. Редко вы будете писать программное обеспечение, которое представляет собой не что иное, как свернутые вручную реализации мьютекса, непонятные операции линейной алгебры с плохой поддержкой библиотек и новые алгоритмы, известные только исследовательской группе вашей компании. Большая часть кода состоит из вызовов библиотеки / фреймворка / API, ввода-вывода, шаблонного кода и модульных тестов.
Это тот код, о котором говорит Мартин. И он отвечает на ваш вопрос цитатой из Кернигана и Плаугера в верхней части главы:
Если в вашем коде есть длинные извилистые разделы, вы не смогли сохранить ваш код в чистоте . Лучшее решение этой проблемы - не писать комментарий в начале файла, чтобы помочь будущим разработчикам разобраться в нем; лучшее решение - переписать его.
И это именно то, что говорит Мартин:
Это ваше (2). Мартин соглашается с тем, что длинный, запутанный код действительно нуждается в комментариях - но он возлагает вину за этот код на плечи программиста, который его написал, а не на какую-то туманную идею, что «мы все знаем, что этого недостаточно». Он утверждает, что:
источник
Ничего как такового. Документирование вашей работы - хорошая практика.
Тем не менее, у вас есть ложная дихотомия: написание чистого кода против написания документированного кода - эти два понятия не противоречат друг другу.
На чем вам следует сосредоточиться - это упрощать и абстрагировать сложный код в более простой код, вместо того, чтобы думать «сложный код - это хорошо, пока он комментируется».
В идеале ваш код должен быть простым и документированным.
Правда. Вот почему все ваши общедоступные алгоритмы API должны быть объяснены в документации.
В идеале, после написания сложного фрагмента кода вы должны (не исчерпывающий список):
Ни один из этих шагов не является тривиальным (то есть каждый может занять несколько часов), и вознаграждение за их выполнение не является немедленным. Как таковые, эти шаги (почти) всегда скомпрометированы (разработчики сокращают углы, менеджеры сокращают углы, сроки, рыночные ограничения / другие реальные условия, отсутствие опыта и т. Д.).
Вы никогда не должны полагаться на чтение реализации, чтобы выяснить, что делает API. Когда вы делаете это, вы реализуете клиентский код на основе реализации (а не интерфейса), и это означает, что ваше соединение модулей уже убито до чертиков, вы потенциально вводите недокументированные зависимости с каждой новой строкой кода, которую вы пишете, и уже добавив технический долг.
Нет - это хорошо. Однако добавить несколько строк комментариев недостаточно.
Тот факт, что у вас не должно быть сложного кода, если этого можно избежать.
Чтобы избежать сложного кода, формализуйте свои интерфейсы, тратите в ~ 8 раз больше на разработку API, чем тратите на реализацию (Степанов предложил потратить на интерфейс не менее 10 раз по сравнению с реализацией), и приступайте к разработке проекта со знанием того, что Вы создаете проект, а не просто пишете какой-то алгоритм.
Проект включает в себя документацию API, функциональную документацию, измерения кода / качества, управление проектом и так далее. Ни один из этих процессов не является одноразовым, быстрым шагом (все они требуют времени, требуют обдумывания и планирования, и все они требуют, чтобы вы периодически возвращались к ним и пересматривали / дополняли их подробностями).
источник
Я бы посчитал это незначительным злоупотреблением "комментариями". Если программист хочет прочитать что-то вместо всего алгоритма, то для этого предназначена документация по функциям. Итак, документация по функции может фактически появляться в комментариях в источнике (возможно, для извлечения инструментами doc), но хотя синтаксически это комментарий для вашего компилятора, вы должны рассматривать их как отдельные вещи с разными целями. Я не думаю, что «комментарии должны быть скудными» обязательно означают «документация должна быть скудной» или даже «уведомления об авторских правах должны быть скудными»!
Комментарии в функции предназначены для чтения, а также для кода. Таким образом, если в вашем коде есть несколько строк, которые трудно понять, и вы не можете сделать их легко понятными, тогда для читателя полезно использовать комментарий в качестве заполнителя для этих строк. Это может быть очень полезно, когда читатель просто пытается понять суть, но есть пара проблем:
Существуют исключения, но большинство читателей должны понимать сам код. Комментарии должны быть написаны, чтобы помочь этому, а не заменить его, поэтому вам обычно рекомендуется, чтобы в комментариях говорилось «почему вы это делаете». Читатель, который знает мотивы для следующих нескольких строк кода, имеет больше шансов увидеть, что они делают и как.
источник
Часто нам приходится делать сложные вещи. Это, безусловно, правильно документировать их для будущего понимания. Иногда правильное место для этой документации находится в коде, где документация может быть обновлена с кодом. Но, безусловно, стоит рассмотреть отдельную документацию. Это также может быть легче представить другим людям, включая диаграммы, цветные рисунки и так далее. Тогда комментарий просто:
или даже просто
Конечно, люди довольны именованными функциями
MatchStringKnuthMorrisPratt
илиencryptAES
илиpartitionBSP
. Более неясные имена заслуживают объяснения в комментарии. Вы также можете добавить библиографические данные и ссылку на статью, с которой вы реализовали алгоритм.Если алгоритм является сложным, новым и неочевидным, он определенно стоит документа, даже если только для внутреннего обращения компании. Проверьте документ в системе контроля версий, если вы беспокоитесь о его потере.
Есть еще одна категория кода, которая не столько алгоритмическая, сколько бюрократическая. Вам нужно настроить параметры для другой системы или взаимодействовать с чужими ошибками:
источник
doPRD239Algorithm
который говорит мне ничего о функции без необходимости искать алгоритм, причинаMatchStringKnuthMorrisPratt
иencryptAES
работа в том, что они начинают с описания того, что они делают, а затем описывают методологию.Я не помню , где я читал, но там есть острая и четкая линия между тем, что должно появиться в вашем коде и что должно появиться в качестве комментария.
Я считаю, что вы должны прокомментировать свое намерение, а не свой алгоритм . Т.е. комментируйте то, что вы хотели сделать, а не то, что вы делаете .
Например:
Здесь нет попытки указать, что выполняет каждый шаг, все, что он заявляет, - это то, что он должен делать.
PS: я нашел источник, на который ссылался - Ужасы кодирования: код рассказывает вам, как, комментарии говорят вам, почему
источник
Future
и указывает на то, что заget()
ним следует проверка, чтобыnull
определить, был лиFuture
уже запущен - правильно документирует намерение, а не процесс .В самом деле? С каких пор?
Хорошо разработанного кода с хорошими именами в большинстве случаев более чем достаточно. Аргументы против использования комментариев хорошо известны и документированы (как вы ссылаетесь).
Но это руководящие принципы (как и все остальное). В редком случае (по моему опыту, примерно раз в 2 года), когда дела будут ухудшаться, если их преобразовать в более мелкие разборчивые функции (из-за потребностей в производительности или согласованности), тогда продолжайте - добавьте несколько длинных комментариев, объясняющих, что на самом деле делать (и почему вы нарушаете лучшие практики).
источник
Основная цель кода - дать команду компьютеру что-то сделать, поэтому хороший комментарий никогда не заменит хороший код, потому что комментарии не могут быть выполнены.
При этом комментарии в источнике являются одной из форм документации для других программистов (включая вас). Если комментарии касаются более абстрактных вопросов, чем то, что делает код на каждом шаге, вы справляетесь лучше, чем в среднем. Этот уровень абстракции зависит от используемого вами инструмента. Комментарии, сопровождающие процедуры на ассемблере, обычно имеют более низкий уровень «абстракции», чем, например, этот APL
A←0⋄A⊣{2⊤⍵:1+3×⍵⋄⍵÷2}⍣{⍺=A+←1}⎕
. Я думаю, что это, вероятно, заслуживает комментария о проблеме, которую он призван решить, ммм?источник
Если код тривиален, он не нуждается в пояснительном комментарии. Если код нетривиален, пояснительный комментарий, скорее всего, также будет нетривиальным.
Теперь, проблема с нетривиальным естественным языком заключается в том, что многие из нас не очень хорошо умеют читать или писать. Я уверен, что ваши письменные коммуникативные навыки превосходны, но, тем не менее, кто-то с меньшим пониманием письменного языка может неправильно понять ваши слова.
Если вы очень стараетесь писать на естественном языке, который не может быть неверно истолкован, вы получите что-то вроде юридического документа (и, как мы все знаем, они более многословны и трудны для понимания, чем код).
Код должен быть наиболее кратким описанием вашей логики, и не должно быть много споров о значении вашего кода, потому что ваш компилятор и платформа имеют последнее слово.
Лично я бы не сказал, что вы никогда не должны писать комментарии. Только то, что вы должны учитывать, почему ваш код нуждается в комментарии, и как вы можете это исправить. Это, кажется, общая тема в ответах здесь.
источник
Еще один момент, о котором еще не говорилось, заключается в том, что иногда точное комментирование того, что делает фрагмент кода, может быть полезным в тех случаях, когда язык использует определенный синтаксис для нескольких целей. Например, предполагая, что все переменные имеют тип
float
, рассмотрим:Результатом явного приведения
float
кfloat
является принудительное округление результата с одинарной точностью; таким образом, комментарий можно рассматривать просто как сообщение о том, что делает код. С другой стороны, сравните этот код с:Здесь цель приведения состоит в том, чтобы не допустить, чтобы компилятор подавлял при наиболее эффективном способе точного вычисления (f2 / 10) [это более точно, чем умножение на 0,1f, и на большинстве машин это быстрее, чем деление на 10,0f].
Без комментария кто-то, кто просматривал предыдущий код, мог бы подумать, что приведение было добавлено из-за ошибочного убеждения, что это необходимо для того, чтобы компилятор не кричал и что он не нужен. Фактически, приведение служит для того, чтобы делать в точности то, что говорит языковая спецификация: заставить результат вычисления округляться до одинарной точности даже на машинах, где округление будет более дорогим, чем сохранение результата с более высокой точностью. Учитывая, что приведение к
float
может иметь несколько различных значений и целей, наличие комментария, указывающего, какое значение предназначено в конкретном сценарии, может помочь прояснить, что фактическое значение совпадает с намерением.источник
someFloatProperty
наиболее точное представление оf2/10
том, что он может; таким образом, основная цель второго приведения - просто скомпилировать код . В первом примере, однако, приведение явно не требуется для его обычной цели (изменение одного типа времени компиляции на другой), так как операнды уже естьfloat
. Комментарий служит ясно , что приведение в необходимом для вторичной цели (округление).(float)
актеры во втором примере. Вопрос о буквальной константе0.1
. Вы объяснили (в следующем абзаце текста), почему мы пишем0.1
: «это точнее, чем умножить на 0,1f». Я предполагаю, что это те слова, которые должны быть в комментарии.double
для констант или промежуточных вычислений, значение которых не может быть представлено какfloat
[хотя в языках, которые требуют раздражающих явных приведений типа double-to-float, лень может потребоваться использованиеfloat
констант не для скорости, а для минимизации раздражения].Комментарии, которые объясняют, что делает код, являются формой дублирования. Если вы измените код, а затем забудете обновить комментарии, это может привести к путанице. Я не говорю, не используйте их, просто используйте их разумно. Я подписываюсь на принцип дядюшки Боба: «Только комментируйте то, что код не может сказать».
источник