Что такое самодокументированный код и может ли он заменить хорошо документированный код?
У меня есть коллега, который настаивает на том, что его код не нуждается в комментариях, это "самодокументирование".
Я рассмотрел его код, и, хотя он более понятен, чем код, который я видел у других, я все же не согласен с тем, что самодокументированный код является таким же полным и полезным, как и комментированный и документированный код.
Помоги мне понять его точку зрения.
- Что такое самодокументируемый код
- Может ли он действительно заменить хорошо прокомментированный и документированный код
- Есть ли ситуации, когда это лучше, чем хорошо документированный и прокомментированный код
- Существуют ли примеры, когда код не может самодокументироваться без комментариев
Может быть, это только мои собственные ограничения, но я не понимаю, как это может быть хорошей практикой.
Это не должно быть аргументом - пожалуйста, не приводите причины, по которым хорошо прокомментированный и документированный код имеет высокий приоритет - есть много ресурсов, показывающих это, но они не убедительны для моего коллеги. Я считаю, что мне нужно более полно понять его точку зрения, чтобы убедить его в обратном. Если нужно, начните новый вопрос, но не спорьте здесь.
Вау, быстрый ответ! Пожалуйста, прочитайте все существующие ответы и предоставьте комментарии к ответам, а не добавляйте новые ответы, если ваш ответ на самом деле существенно не отличается от любого другого ответа здесь.
Кроме того, те из вас, кто спорит против самодокументированного кода, - это прежде всего, чтобы помочь мне понять точку зрения (то есть, положительные аспекты) самодокументированных евангелистов кода. Я ожидаю, что другие будут опускать вас, если вы не останетесь в теме.
49 ответов
На мой взгляд, любой код должен быть самодокументированным. В хорошем, самодокументированном коде вам не нужно объяснять каждую строку, потому что каждый идентификатор (переменная, метод, класс) имеет четкое семантическое имя. Наличие большего количества комментариев, чем необходимо, фактически затрудняет (!) Чтение кода, поэтому, если ваш коллега
- записывает комментарии документации (Doxygen, JavaDoc, комментарии XML и т. д.) для каждого класса, члена, типа и метода AND
- четко комментирует любые части кода, которые не являются самодокументируемыми
- записывает комментарий для каждого блока кода, который объясняет намерение или действия кода на более высоком уровне абстракции (т. е. найти все файлы размером более 10 МБ вместо циклического перебора всех файлов в каталоге, проверьте, не превышает ли размер файла более 10 МБ, вернуть доходность, если истина)
его код и документация в порядке, на мой взгляд. Обратите внимание, что самодокументированный код не означает, что не должно быть никаких комментариев, но только то, что не должно быть лишних комментариев. Дело, однако, в том, что при чтении кода (включая комментарии и комментарии к документации) следует немедленно понять, что делает код и почему. Если "самодокументируемый" код требует больше времени для понимания, чем закомментированный код, он на самом деле не самодокументируется.
Ну, поскольку речь идет о комментариях и коде, давайте посмотрим на некоторый реальный код. Сравните этот типичный код:
float a, b, c; a=9.81; b=5; c= .5*a*(b^2);
К этому самодокументированному коду, который показывает, что делается:
const float gravitationalForce = 9.81;
float timeInSeconds = 5;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);
А затем к этому документированному коду, который лучше объясняет, почему это делается:
/* compute displacement with Newton's equation x = vₒt + ½at² */
const float gravitationalForce = 9.81;
float timeInSeconds = 5;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);
И окончательная версия кода в виде документации с нулевыми комментариями:
float computeDisplacement(float timeInSeconds) {
const float gravitationalForce = 9.81;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);
return displacement;
}
Вот пример плохого стиля комментирования:
const float a = 9.81; //gravitational force
float b = 5; //time in seconds
float c = (1/2)*a*(b^2) //multiply the time and gravity together to get displacement.
В последнем примере комментарии используются, когда переменные должны были иметь описательные имена, а результаты операции суммируются, когда мы можем ясно видеть, что это за операция. Я бы предпочел второй пример самодокументированному этому, и, возможно, именно об этом говорит ваш друг, когда говорит самодокументированный код.
Я бы сказал, что это зависит от контекста того, что вы делаете. Для меня самодокументированный код, вероятно, является достаточным в этом случае, но также полезен комментарий, подробно описывающий методологию, лежащую в основе проделанной работы (в этом примере - уравнение).
Сам код всегда будет самым современным объяснением того, что делает ваш код, но, по моему мнению, ему очень сложно объяснить намерения, что является наиболее важным аспектом комментариев. Если он написан правильно, мы уже знаем, что делает код, нам просто нужно знать, почему он это делает!
Кто-то однажды сказал
1) Пишите комментарии только для кода, который трудно понять.
2) Старайтесь не писать код, который трудно понять.
Идея "самодокументируемого" кода заключается в том, что реальная логика программы в коде достаточно проста, чтобы объяснить каждому, кто читает код, не только то, что код делает, но и почему.
На мой взгляд, идея истинного самодокументированного кода - это миф. Код может рассказать вам логику того, что происходит, но он не может объяснить, почему это делается определенным образом, особенно если существует несколько способов решения проблемы. Только по этой причине он никогда не сможет заменить хорошо прокомментированный код.
Я думаю, что уместно задать вопрос, является ли конкретная строка кода самодокументированной, но, в конце концов, если вы не понимаете структуру и функцию фрагмента кода, то в большинстве случаев комментарии не помогут. Возьмем, к примеру, фрагмент "правильно прокомментированного" кода amdfan:
/* compute displacement with Newton's equation x = v0t + ½at^2 */
const float gravitationalForce = 9.81;
float timeInSeconds = 5;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);
Этот код хорош, но следующее является в равной степени информативным в большинстве современных программных систем и явно признает, что использование ньютоновских вычислений является выбором, который может быть изменен, если какая-то другая физическая парадигма будет более подходящей:
const float accelerationDueToGravity = 9.81;
float timeInSeconds = 5;
float displacement = NewtonianPhysics.CalculateDisplacement(accelerationDueToGravity, timeInSeconds);
По моему личному опыту, очень мало "нормальных" ситуаций кодирования, когда вам абсолютно необходимы комментарии. Как часто, к примеру, вы запускаете собственный алгоритм? По сути, все остальное - это вопрос структурирования вашей системы, чтобы кодировщик мог понять используемые структуры и выбор, который побудил систему использовать эти конкретные структуры.
Я забыл, откуда я это взял, но:
Каждый комментарий в программе - это как извинение перед читателем. "Мне жаль, что мой код настолько непрозрачен, что вы не можете понять его, глядя на него". Мы просто должны признать, что мы не идеальны, но стремимся быть идеальными и продолжать извиняться, когда это необходимо.
Самодокументированный код - хороший пример "СУХОГО" (не повторяйте себя). Не дублируйте информацию в комментариях, которая есть или может быть в самом коде.
Вместо того, чтобы объяснять, для чего используется переменная, переименуйте переменную.
Вместо того, чтобы объяснять, что делает короткий фрагмент кода, извлеките его в метод и дайте ему описательное имя (возможно, сокращенную версию текста вашего комментария).
Вместо того, чтобы объяснять, что делает сложный тест, извлеките его и в метод и дайте ему хорошее имя.
И т.п.
После этого вы получите код, который не требует такого большого количества объяснений, он сам объясняется, поэтому вы должны удалить комментарии, которые просто повторяют информацию в коде.
Это не означает, что у вас нет никаких комментариев, есть некоторая информация, которую вы не можете вставить в код, например, информация о намерениях ("почему"). В идеальном случае код и комментарии дополняют друг друга, каждый добавляет уникальное объяснительное значение, не дублируя информацию в другом.
Прежде всего, приятно слышать, что код вашего коллеги на самом деле яснее, чем другой код, который вы видели. Это означает, что он, вероятно, не использует "самодокументирование" в качестве оправдания за то, что слишком ленив, чтобы комментировать свой код.
Самодокументированный код - это код, который не требует комментариев в свободном тексте для информированного читателя, чтобы понять, что он делает. Например, этот фрагмент кода самодокументируется:
print "Hello, World!"
и так это:
factorial n = product [1..n]
и так это:
from BeautifulSoup import BeautifulSoup, Tag
def replace_a_href_with_span(soup):
links = soup.findAll("a")
for link in links:
tag = Tag(soup, "span", [("class", "looksLikeLink")])
tag.contents = link.contents
link.replaceWith(tag)
Эта идея "информированного читателя" очень субъективна и ситуативна. Если у вас или у кого-то еще возникают проблемы с соблюдением кодекса вашего коллеги, тогда ему следует пересмотреть свою идею информированного читателя. Некоторый уровень знакомства с языком и используемыми библиотеками должен быть принят для того, чтобы вызвать самодокументирование кода.
Лучший аргумент, который я видел при написании "самодокументируемого кода", заключается в том, что он позволяет избежать проблемы свободного текста комментариев, не согласных с кодом, как он написан. Лучшая критика заключается в том, что хотя код может описывать, что и как он делает сам по себе, он не может объяснить, почему что-то делается определенным образом.
Самодокументированный код - это хорошая практика, и при правильном выполнении он может легко передать смысл кода, не читая слишком много комментариев. особенно в ситуациях, когда домен хорошо понимают все в команде.
Сказав это, комментарии могут быть очень полезны для новичков или для тестировщиков или для создания файлов документации / помощи.
Самодокументируемый код + необходимые комментарии будут иметь большое значение для помощи людям в командах.
С целью:
- Самодокументированный код - это код, который четко выражает свое намерение читателю.
- Не совсем. Комментарии всегда полезны для комментариев о том, почему была выбрана конкретная стратегия. Однако комментарии, которые объясняют, что делает часть кода, указывают на код, который недостаточно самодокументирован и может использовать некоторый рефакторинг.
- Комментарии врут и устаревают. Код
всегда говорит, скорее всего, скажет правду. - Я никогда не видел случая, чтобы код не был достаточно понятен без комментариев; однако, как я уже говорил ранее, иногда необходимо / полезно добавить комментарий о причине.
Тем не менее, важно отметить, что действительно самодокументируемый код требует много самостоятельной и командной дисциплины. Вы должны научиться программировать более декларативно, и вы должны быть очень скромными и избегать "умного" кода в пользу кода, который настолько очевиден, что кажется, что любой мог его написать.
Когда вы читаете "самодокументированный код", вы видите, что он делает, но вы не всегда можете догадаться, почему он делает именно так.
Существует множество не связанных с программированием ограничений, таких как бизнес-логика, безопасность, требования пользователей и т. Д.
Когда вы выполняете техническое обслуживание, эта обратная информация становится очень важной.
Просто моя щепотка соли...
Например, рассмотрим следующий фрагмент:
/**
* Sets the value of foobar.
*
* @foobar is the new vaue of foobar.
*/
public void setFoobar(Object foobar) {
this.foobar = foobar;
}
В этом примере у вас есть 5 строк комментариев на 3 строки кода. Еще хуже - комментарии не добавляют ничего, что вы не видите, читая код. Если у вас есть 10 таких методов, вы можете получить "слепоту к комментариям" и не заметить один метод, который отличается от шаблона.
Если бы, конечно, лучшая версия была бы:
/**
* The serialization of the foobar object is used to synchronize the qux task.
* The default value is unique instance, override if needed.
*/
public void setFoobar(Object foobar) {
this.foobar = foobar;
}
Тем не менее, для тривиального кода я предпочитаю не иметь комментариев. Намерение и общая организация лучше объяснены в отдельном документе вне кода.
Разница между "что" и "как".
- Вы должны документировать "что" делает рутина.
- Вы не должны документировать, "как" это делает, за исключением особых случаев (например, обратиться к конкретному алгоритму бумаги). Это должно быть самодокументировано.
Одна вещь, которую вы можете указать своему коллеге, это то, что независимо от того, насколько самодокументирован его код, если другие альтернативные подходы были рассмотрены и отброшены, эта информация будет потеряна, если он не прокомментирует код с этой информацией. Иногда так же важно знать, что альтернатива рассматривалась и почему она была отвергнута, а комментарии к коду, скорее всего, выживут со временем.
Самодокументированный код обычно использует имена переменных, которые точно соответствуют тому, что делает код, так что легко понять, что происходит
Однако такой "самодокументированный код" никогда не заменит комментарии. Иногда код слишком сложен, и самодокументируемого кода недостаточно, особенно в плане удобства сопровождения.
У меня когда-то был профессор, который твердо верил в эту теорию. На самом деле самое лучшее, что я когда-либо помню, чтобы он говорил: "Комментарии для сестренок"
Сначала мы застали всех врасплох, но это имеет смысл.
Тем не менее, ситуация такова, что, хотя вы можете понимать, что происходит в коде, но кто-то менее опытный, чтобы вы могли идти за вами и не понимать, что происходит. Это когда комментарии становятся важными. Я знаю много раз, что мы не считаем их важными, но очень мало случаев, когда комментарии не нужны.
Слышали ли вы о проекте WEB Дональда Кнута по реализации его концепции грамотного программирования? Это больше, чем самодокументированный код; это больше похоже на документацию, которую можно скомпилировать и выполнить как код. Я не знаю, сколько это используется сегодня, хотя.
Я удивлен, что никто не привел в действие " Грамотное программирование", метод, разработанный в 1981 году Дональдом Кнутом из TeX и известностью "Искусство компьютерного программирования".
Предпосылка проста: так как код должен понимать человек, а компилятор просто выбрасывает комментарии, почему бы не дать всем то, что им нужно - полное текстовое описание цели кода, не зависящее от требований языка программирования, для читателя и чистый код для компилятора.
Инструменты грамотного программирования делают это, предоставляя вам специальную разметку для документа, которая сообщает инструментам, какая часть должна быть источником, а что текст. Позже программа извлекает части исходного кода из документа и собирает файл кода.
Я нашел пример в Интернете: http://moonflare.com/code/select/select.nw или HTML-версия http://moonflare.com/code/select/select.html
Если вы можете найти книгу Кнута об этом в библиотеке (Дональд Э. Кнут, "Литературное программирование", Стэнфорд, Калифорния: Центр изучения языка и информации, 1992, CSLI Lecture Notes, № 27.), вам следует прочитать ее.
Это самодокументированный код, полный рассуждений и все. Даже делает хороший документ, Все остальное просто хорошо написано в комментариях:-)
В компании, где я работал, одна из программистов прикрепила к ее монитору следующее.
"Документируй свой код, как тот, кто его поддерживает, - гомосексуальный маньяк, который знает, где ты живешь".
Мой взгляд написан в этом посте:
Один единственный совет, чтобы документировать ваш код.
Выдержка:
Вместо того, чтобы писать множество комментариев, объясняющих тонкое поведение вашей программы, почему бы не перестроить логику так, чтобы она стала очевидной? Вместо того, чтобы документировать, что делает метод, почему бы не выбрать четкое имя для этого метода? Вместо того, чтобы пометить свой код для обозначения незавершенной работы, почему бы просто не выбросить NotImplementedException()? Вместо того, чтобы беспокоиться о том, звучат ли ваши комментарии достаточно вежливо для вашего босса, ваших коллег или любого, кто читает код, почему бы просто не перестать беспокоиться, вообще не написав их?
Чем яснее ваш код, тем легче его поддерживать, расширять, работать над ним в будущих выпусках. Чем менее ординарен ваш код, тем меньше нужно его комментировать. Чем больше комментариев, тем выше стоимость обслуживания.
Точка зрения, что код самодокументируется, сводит меня с ума. Конкретная строка кода или вспомогательный алгоритм может действительно самодокументироваться, но его цель в большем изображении просто нет.
Я был так разочарован этим месяц или два назад, что написал целый пост в блоге, описывающий мою точку зрения. Опубликовать здесь.
Я хотел бы предложить еще одну перспективу для многих действительных ответов:
Что такое исходный код? Что такое язык программирования?
Машины не нуждаются в исходном коде. Они счастливы запустить сборку. Языки программирования для нашей выгоды. Мы не хотим писать ассемблер. Нам нужно понять, что мы пишем. Программирование - это написание кода.
Должны ли вы быть в состоянии прочитать то, что вы пишете?
Исходный код не написан на человеческом языке. Это было опробовано (например, FORTRAN), но это не совсем успешно.
Исходный код не может иметь двусмысленности. Вот почему мы должны придать ему больше структуры, чем мы делаем с текстом. Текст работает только с контекстом, который мы воспринимаем как должное, когда используем текст. Контекст в исходном коде всегда explisit. Подумайте, "используя" в C#.
Большинство языков программирования имеют избыточность, так что компилятор может поймать нас, когда мы не согласованы. Другие языки используют больше выводов и стараются устранить эту избыточность.
Имена типов, имена методов и имена переменных не нужны компьютерам. Они используются нами для ссылок. Компилятор не понимает семантику, это нам нужно использовать.
Языки программирования являются лингвистическим мостом между человеком и машиной. Это должно быть доступно для нас и доступно для них. Вторичные требования - это должно быть читаемым для нас. Если мы хорошо разбираемся в семантике, где это разрешено, и хорошо структурируем код, исходный код должен быть легко читаемым даже для нас. Лучший код не нуждается в комментариях.
Но сложность скрывается в каждом проекте, вы всегда должны решить, где поставить сложность, а какие верблюды проглотить. Это те места, где можно использовать комментарии.
Реальная проблема с так называемым самодокументируемым кодом состоит в том, что он передает то, что он фактически делает. Хотя некоторые комментарии могут помочь кому-то лучше понять код (например, шаги алгоритмов и т. Д.), Он в некоторой степени избыточен, и я сомневаюсь, что вы убедите своего коллегу.
Тем не менее, что действительно важно в документации, так это то, что непосредственно не видно из кода: основное намерение, предположения, воздействия, ограничения и т. Д.
Быть способным определить, что код выполняет X с первого взгляда, гораздо проще, чем определить, что код не выполняет Y. Он должен документировать Y...
Вы можете показать ему пример кода, который выглядит хорошо, очевиден, но на самом деле не охватывает, например, все основы ввода, и посмотрите, найдет ли он его.
Я бы сказал - как многие из вас - что для того, чтобы действительно самодокументироваться, код должен показывать какую-то форму намерения. Но я удивлен, что никто еще не упомянул BDD - Behavior Driven Development. Отчасти идея заключается в том, что у вас есть автоматические тесты (код), объясняющие цель вашего кода, что иначе трудно сделать очевидным.
Хорошее доменное моделирование + хорошие имена (переменные, методы, классы) + примеры кода (модульные тесты из вариантов использования) = самодокументирующее программное обеспечение
При написании математического кода я иногда находил полезным писать длинные, похожие на эссе комментарии, объясняя математику, условные обозначения, которые использует код, и то, как все это сочетается. Мы говорим здесь сотни строк документации.
Я пытаюсь сделать свой код как можно более самодокументированным, но когда я вернусь к работе над ним через несколько месяцев, мне действительно нужно прочитать объяснение, чтобы не создавать из него хэш.
Теперь, конечно, такого рода крайние меры не нужны в большинстве случаев. Я думаю, что мораль этой истории такова: разный код требует разного количества документации. Некоторый код может быть написан настолько ясно, что он не нуждается в комментариях - поэтому пишите это так четко и не используйте комментарии там!
Но большому количеству кода нужны комментарии, чтобы иметь смысл, поэтому напишите его как можно более четко, а затем используйте столько комментариев, сколько нужно...
Я думаю, что самодокументированный код является хорошей заменой для комментариев. Если вам требуются комментарии для объяснения того, как или почему код такой, какой он есть, то у вас есть имя функции или переменной, которые следует изменить, чтобы они были более понятными. Кодировщик может решить, будет ли он восполнять недостаток комментарием или переименовывать некоторые переменные и функции, а также рефакторинг кода.
Однако она не может заменить вашу документацию, потому что документация - это то, что вы даете другим, чтобы объяснить, как использовать вашу систему, а не как она работает.
Изменить: Я (и, вероятно, все остальные), вероятно, должен иметь положение, что приложение цифровой обработки сигналов (DSP) должно быть очень хорошо прокомментировано. Это происходит главным образом потому, что приложения DSP по существу равны 2 для циклов, снабженных массивами значений, и добавляет / умножает / и т. Д. Указанные значения... для изменения программы вы изменяете значения в одном из массивов... требуется пара комментариев, чтобы сказать, что вы делаете в таком случае;)
Самодокументированный код - это простой выход из проблемы, так как со временем код, комментарии и документация расходятся. И это является дисциплинирующим фактором для написания ясного кода (если вы так строги к себе).
Для меня это правила, которым я стараюсь следовать:
- Код должен быть максимально простым и понятным для чтения.
- Комментарии должны содержать причины для принятия проектных решений, например: почему я использую этот алгоритм, или ограничения, которые имеет код, например: не работает, когда... (это должно быть обработано в контракте / утверждении в коде) (обычно в рамках функции / процедуры).
- Документация должна перечислять использование (вызывающие преобразования), побочные эффекты, возможные возвращаемые значения. Его можно извлечь из кода с помощью таких инструментов, как jDoc или xmlDoc. Поэтому он обычно находится за пределами функции / процедуры, но близко к коду, который он описывает.
Это означает, что все три средства документирования кода находятся близко друг к другу и, следовательно, с большей вероятностью будут изменены при изменении кода, но не будут совпадать в том, что они выражают.
Все будет в том, что команда ценит в своей документации. Я хотел бы предложить документирование почему / намерение, а не как важно, и это не всегда отражается в самодокументированном коде. получить / установить нет, это очевидно - но расчет, поиск и т. д. должны быть выражены.
Также имейте в виду разницу в вашей команде, если вы приехали из разных стран. Различия в дикции могут скрываться в именах методов:
BisectionSearch
BinarySearch
BinaryChop
Эти три метода, предоставленные разработчиками на трех разных континентах, делают одно и то же. Только прочитав комментарии, описывающие алгоритм, мы смогли выявить дублирование в нашей библиотеке.
Большинство документации / комментариев служат для помощи будущим усовершенствованиям / разработчикам кода, следовательно, делая код поддерживаемым. Чаще всего мы возвращаемся к нашему модулю позже, чтобы добавить новые функции или оптимизировать. В то время было бы легче понять код, просто читая комментарии, чем проходить через многочисленные контрольные точки. Кроме того, я бы скорее потратил время на размышления о новой логике, чем расшифровывая существующую.
Несколько причин, по которым дополнительные комментарии в дополнение к коду могут быть понятнее:
- Код, который вы просматриваете, был сгенерирован автоматически, и поэтому любые изменения в коде могут быть закрыты при следующей компиляции проекта.
- Менее простая реализация была заменена на увеличение производительности (развертывание цикла, создание таблицы поиска для дорогостоящих вычислений и т. Д.)