[Перевод] Комментирование кода: хороший, плохой, злой

wa_huylma7nmrwrnfek5zwzwobi.jpeg

Вы наверняка это слышали: «Хороший код является самодокументированным».

Я больше 20 лет зарабатываю написанием кода, и слышал эту фразу чаще всего. Это клише.

И как во многих других клише, здесь есть зерно истины. Но это истиной уже столько злоупотребляли, что большинство из тех, кто произносит эту фразу, не понимает, что она на самом деле означает.

Она истинна? Да.

Означает ли она, что вы никогда не должны комментировать код? Нет.

В этой статье мы рассмотрим разные аспекты комментирования кода.
Для новичков: существует два разных вида комментариев. Я называю их документирующими комментариями и поясняющими комментариями.

Документирующие комментарии


Документирующие комментарии предназначены для тех, кто будет скорее использовать ваш код, а не читать его. Если вы делаете библиотеку или фреймворк для других разработчиков, то вам понадобится что-то вроде документации API.

Чем дальше документация API от вашего исходного кода, тем вероятнее, что он со временем устареет или станет некорректным. Лучше всего встраивать документацию прямо в код, а затем извлекать её с помощью какого-нибудь инструмента.

Вот пример документирующего комментария из популярной JS-библиотеки Lodash:

   /**
    * Creates an object composed of keys generated from the results of running
    * each element of `collection` thru `iteratee`. The corresponding value of
    * each key is the number of times the key was returned by `iteratee`. The
    * iteratee is invoked with one argument: (value).
    *
    * @static
    * @memberOf _
    * @since 0.5.0
    * @category Collection
    * @param {Array|Object} collection The collection to iterate over.
    * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
    * @returns {Object} Returns the composed aggregate object.
    * @example
    *
    * _.countBy([6.1, 4.2, 6.3], Math.floor);
    * // => { '4': 1, '6': 2 }
    *
    * // The `_.property` iteratee shorthand.
    * _.countBy(['one', 'two', 'three'], 'length');
    * // => { '3': 2, '5': 1 }
    */
   var countBy = createAggregator(function(result, value, key) {
     if (hasOwnProperty.call(result, key)) {
       ++result[key];
     } else {
       baseAssignValue(result, key, 1);
     }
   });


Если сравните эти комментарии с онлайн-документацией библиотеки, то увидите, что там всё то же самое.

Когда пишете документирующие комментарии, удостоверьтесь, что делаете это в соответствии с подходящим стандартом, и что комментарии можно легко отличить от любых инлайновых поясняющих комментариев, которые вы тоже можете добавлять. Некоторые популярные и хорошо поддерживаемые стандарты и инструменты: JSDoc для JavaScript, DocFx для .NET, JavaDoc для Java.

К недостаткам документирующих комментариев можно отнести то, что они способны сильно «зашумлять» код, а программистам, которые активно участвуют в сопровождении кода, труднее их читать. Но зато большинство редакторов поддерживают «сворачивание блоков кода» (code folding), что позволяет скрывать комментарии и уделять всё внимание только коду.

nwat62ernfzqgxoej_ndz_et63a.gif
Сворачивание комментариев в коде Visual Studio.

Поясняющие комментарии


Поясняющие комментарии предназначены для всех (включая вас самих в будущем), кто будет сопровождать, рефакторить или расширять код.

Зачастую поясняющие комментарии являются признаком плохого кода. Их наличие говорит об излишней сложности кодовой базы. Поэтому старайтесь убирать поясняющие комментарии и упрощать код, потому что «хороший код — самодокументированный».

Вот пример плохого — хотя и очень забавного — поясняющего комментария:

/*
* Replaces with spaces
* the braces in cases
* where braces in places
* cause stasis.
**/
$str = str_replace(array("\{","\}")," ",$str);


Вместо того, чтобы украшать сбивающее с толку выражение умным стишком — написанным двустопным амфибрахием, не меньше, — автору следовало бы потратить время на функцию, делающую код более читабельным и простым в понимании. Например, можно сделать функцию removeCurlyBraces, вызываемую из функции sanitizeInput.

Не поймите неправильно, бывают ситуации — особенно при работе над очень тяжёлой задачей, — когда душа просит чуточку юмора. Но если пишешь смешной комментарий, уравновешивая плохой код, то вряд ли кто-то захочет потом его рефакторить или исправлять.

Вы действительно хотите лишить других программистов удовольствия от чтения вашего остроумного маленького стишка? Большинство из них посмеются и займутся своими делами, игнорируя недостатки кода.

Но бывают ситуации, когда натыкаешься на избыточный комментарий. Если код и правда прост и очевиден, не нужно добавлять комментарии.

Например, не делайте так:

/*
set the value of the age integer to 32
*/
int age = 32;


Но бывает и так: что бы вы ни делали с кодом, поясняющий комментарий оказывается оправданным. Обычно это случается, когда нужно добавить какой-то контекст к неочевидному решению. Вот хороший пример из Lodash:

function addSetEntry(set, value) {  
 /*
  Don't return `set.add` because it's not chainable in IE 11.
 */  
 set.add(value);    
 return set;  
}


Или бывают такие ситуации: после долгих размышлений и экспериментов понимаешь, что решение, казавшееся наивным, на самом деле лучше всего. В будущем другие программисты практически неизбежно решат, что они умнее вас, и начнут переделывать код, чтобы потом осознать, что ваш способ оказался наилучшим.

Иногда таким программистом можете оказаться вы сами.

В таких ситуациях лучше сэкономить чужое время и написать комментарий.

Этот комментарий-заглушка прекрасно иллюстрирует описанное:

/**
Dear maintainer:
 
Once you are done trying to 'optimize' this routine,
and have realized what a terrible mistake that was,
please increment the following counter as a warning
to the next guy:
 
total_hours_wasted_here = 42
**/


Конечно, это скорее развлечёт, чем поможет. Но вы ДОЛЖНЫ оставлять комментарии, предостерегающие других от поиска, казалось бы, очевидно «лучшего решения», если вы уже испробовали и отвергли другие варианты. При этом комментарий должен описывать, что вы пытались сделать и почему отказались от таких решений.

Простой пример в JavaScript:

/*
don't use the global isFinite() because it returns true for null values
*/
Number.isFinite(value)


Злой


Итак, вы прочитали про хорошего и плохого, а что насчёт злого?

К сожалению, в любой профессии можно почувствовать разочарование, и когда пишешь код ради заработка, может возникнуть соблазн выразить это разочарование в комментариях.

Если поработать с достаточным количеством кодовых баз, то вам встретятся комментарии от циничных и депрессивных до мрачных и злобных.

От кажущихся безобидными…

/*
This code sucks, you know it and I know it.  
Move on and call me an idiot later.
*/


…до намеренно оскорбительных

/*
Class used to workaround Richard being a f***ing idiot
*/


Такие комментарии могут казаться забавными, или на время помогают уменьшить разочарование, но если они попадают в production, то дискредитируют профессионализм автора и его нанимателя, выставляют их в дурном свете.

Не делайте этого.

© Habrahabr.ru