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

Я больше 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), что позволяет скрывать комментарии и уделять всё внимание только коду.


Сворачивание комментариев в коде 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, то дискредитируют профессионализм автора и его нанимателя, выставляют их в дурном свете.

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

Комментарии (25)


  1. Aquahawk
    07.05.2018 16:17

    А вам не кажется что код addSetEntry в принципе не должен существовать? Вместе со своим комментарием.


    1. AxisPod
      07.05.2018 16:20
      +2

      IE 11 тоже не должно существовать, но он существует.


      1. Aquahawk
        07.05.2018 16:27

        да ничего в нём особо страшного, я поддерживаю и его на webgl игре. За мелкими исключениями всё ок. Правда с DOM работы почти нет, один канвас, гетКонтекст и поехали.


        1. Areso
          08.05.2018 08:45

          Ослик и боль:
          caniuse.com/#search=server%20side%20events
          Метро-ослик тоже не поддерживает, кстати говоря.


          1. Aquahawk
            08.05.2018 10:54

            вебсокеты и вперёд, как в нормальных сетевых приложениях


    1. awesomer
      07.05.2018 16:28

      А вам не кажется что код addSetEntry в принципе не должен существовать?


      Почему нет? Возможно, это просто вырожденный частный случай. А в остальных местах аналогичные вызовы имеют смысл. Не повод ради одного частного случая — ломать всю единообразную систему.

      Компиляторы уже много лет как очень умные — в оптимизированном коде вы не найдете этого лишнего вызова call и лишнего движения на стек.


  1. IvanNochnoy
    07.05.2018 17:02

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

    Ой, да ладно. По крайней мере ясно, что автор этого комментария понимает, что код м**ацкий, имеет собственное мнение и не боится называть вещи своими именами. Это гораздо лучше, чем тихо писать говнокод, пока никто не заметил.


    1. awesomer
      07.05.2018 17:47
      +7

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

      Ну представим, вы где-то накосячили (бывает, не спорьте, косячат все).

      И 2 вида реакции более опытного коллеги на это:
      1) Я конечно знал, что ты жертва ЕГЭ, но чтобы до такой степени говно в продакшн гнать… Ты вообще понимаешь, что пишешь? И где только таких жопоруких рожают?
      или
      2) Слушай, похоже здесь не при всех условиях отработает.

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

      Во втором случае — сделать то, за что собственно вам и платят деньги, — исправить косяк.

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

      А вот это «код м**ацкий, имеет собственное мнение и не боится называть вещи своими именами.» высказанное в прямой не лицеприятной форме — это только для поднятия ЧСВ того, кто оскорбляет, а никак не для решения собственно самой проблемы.


      1. lxsmkv
        07.05.2018 20:25
        +4

        Сегодня, проходя мимо, случайно прочитал на доске из ретроспективы какой-то команды карточку: «качество кода индийских коллег тратит слишком много ресурсов наших сениоров». Европа, блин. Все культурно и аргументированно.


    1. tyomitch
      07.05.2018 17:47
      +3

      Когда я пытаюсь разобраться в чужом коде, то личные качества автора — последнее, что меня волнует, так что комментарии, проясняющие личные качества автора — для меня мусор.


  1. agmt
    07.05.2018 18:54
    +1

    Стишок про замену — очень странное решение. Мало того, что код гораздо красочнее говорит о том, что делается, так ещё и стиховую форму распознавать мозгу заметно труднее, чем стандартный порядок слов.


  1. ForestLabs
    07.05.2018 23:23
    +1

    Мне помнится комментарий в C++ коде достаточно распостраненного банковского продукта. «А вот здесь наступаем на дерьмо мамонта». В коде спец workaround. Да, кстати, в движке Quake 1, опубликованном, есть примерно такое — «лечим баг в карте q2u1”, примерно.


  1. Antervis
    08.05.2018 00:00
    +2

    бывают куски кода/логики, которые всегда лучше с комментариями:
    1. Оптимизации — краткое пояснение аля «это более быстрая версия вот этого», чтобы у забредших душ других программистов не было желания переписать на более простую, но медленную версию. Заодно и понять код будет проще
    2. Нетривиальная математика — краткое описание «этот алгоритм делает то-то» или указание (хотя бы) названия алгоритма могут сэкономить много времени читающего. Особенно это актуально когда в алгоритме есть специфичные модификации.
    3. Костыли — бывает так, что нет времени/возможности/сиюминутной необходимости сделать хорошо. С комментарием хоть будет понятно на что обратить внимание и что в первую очередь переделывать при работе с этим куском кода


  1. JediPhilosopher
    08.05.2018 01:02
    +4

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

    Наткнулся на какой-то баг/костыль/нюанс и потратил время на поиск решения? Оставлю тут комментарий чтобы в следующий раз не искать снова.

    Код содержит нетривиальную бизнес-логику, на придумывание которой ушло какое-то время? Оставлю комментарий с кратким описанием алгоритма. Так как 3-4 строчки текста прочитать быстрее и проще, чем читать несколько десятков строк кода, ходить туда-сюда по ссылкам на другие классы и файлы и пытаться понять что оно все делает.

    Некачественный legacy код в котором пришлось однажды разобраться? Рефакторить не всегда есть время и не всегда это целесообразно, а вот оставить пару строчек комментария на будущее, если вдруг придется снова сюда заглянуть — это копеечное усилие, экономящее кучу времени в будущем (мне или другому сотруднику).

    Я не верю в самодокументирующийся код. «Самодокументирующимся» бывает только абсолютно тривиальный код типа того же «int age = 32;». Сколько-нибудь сложную логику всегда приходится воспроизводить в голове и напрягаться чтобы понять что она делает. И все это вылетает из головы через несколько дней/недель. Зачем тратить на это время и силы каждый раз, если можно один раз написать 2-3 строчки комментария?

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


    1. mickvav
      08.05.2018 03:21
      +2

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


      1. lorc
        08.05.2018 13:36

        Это хорошо. Но баг трекеры имеют свойство отмирать. Или код может попасть к тому, у кого нет доступа к баг-трекеру (как самый радикальный вариант — код однажды станет open source).
        Поэтому я предпочитаю комментарии либо прямо в коде, либо в коммитах.

        Вообще, кстати, иногда помогает сделать git blame на неясном куске кода, чтобы узнать как и зачем он появился. Конечно, это работает только если команда придерживается адекватной политики описания коммитов, а не фигачит патчи типа «Couple of fixes», «More fixes» или «Added new feature to smthing».


      1. JediPhilosopher
        08.05.2018 13:40

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


    1. search
      08.05.2018 10:53

      Еще полезно оставлять ToDo с описанием того как грамотно исправить проблему. Если на момент создания костыля не хватало ресурсов для рефакторинга.


  1. VaalKIA
    08.05.2018 08:33

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

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


  1. Mabusius
    08.05.2018 10:25
    +1

    А бывает еще так:
    Подзывает меня наш сеньор, водит мышкой по моей строчке кода и задает вопрос, на который написан ответ в моем комментарии строчкой выше. Я спрашиваю «Did you read my comment?» «No, I don`t care».


  1. search
    08.05.2018 10:42

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


  1. amarao
    08.05.2018 11:52

    Комментарии — костыль для подпирания скудности языка.

    Задачей языков программирования является передача семантики через синтаксис. Чем богаче и выразительнее синтаксис, тем больше семантики (смысла) приходится на строку кода. Не «действий на строку кода», а «смысла». Если ассемблерные инструкции научиться записывать по 100 на строку, то семантические возможности ассемблера не поменяются, хотя по плотности «инструкций на строку» он превзойдёт многие другие языки.

    Новые языки программирования расширяют семантические возможности через системы типов данных, трейты, generic'и, реализацию типовых паттернов через кейворды языка.


  1. andi123
    08.05.2018 13:21
    +1

    Нужны не каменты, а «rationale» — разумное обоснование. И желательно для всех int age = 32;
    Иногда попадаются места в документации, где объясняется причины выбранных решений. Но чаще либо бесполезные каменты либо «самодокументированный код». Сидишь смотришь в исходники и думаешь, или автор такой гений, что ты не можешь постичь его творение (понятно, что изначально считаешь автора умней, я же его исходники читаю, а не он мои), или я такой гений, что во всех исходниках мне говнокод мерещится.


  1. nikitasius
    08.05.2018 14:00

    Можно и комментарии для разрядки оставлять:


    Заголовок спойлера

    image


  1. MrDaedra
    10.05.2018 09:53

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

    Всё-таки «Сворачивание комментариев в Visual Studio Code».