Как стать автором
Обновить

Лучшие практики написания комментариев к коду

Блог компании Mail.ru Group Программирование *Анализ и проектирование систем *Проектирование и рефакторинг *
Перевод
Tutorial
Автор оригинала: Ellen Spertus

Известный профессор МТИ Гарольд Абельсон сказал: «Программы нужно писать для того, чтобы их читали люди, и лишь случайно — чтобы их исполняли машины». Хотя он намеренно преуменьшил важность исполнения кода, однако подчёркивает, что у программ две важные аудитории. Компиляторы и интерпретаторы игнорируют комментарии и с одинаковой лёгкостью воспринимают все синтаксически корректные программы. У людей всё иначе. Одни программы нам воспринимать легче, чем другие, и мы ищем комментарии, которые помогут нам разобраться.

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

Как писал Питер Фогель:

  1. Написание и поддержка комментариев требует усилий.
  2. Ваш компилятор не смотрит на комментарии, поэтому невозможно определить их корректность.
  3. С другой стороны, вы гарантируете, что компьютер делает именно то, что предписывает ваш код.

Всё это так, но будет ошибкой ударяться в другую крайность и вообще не писать комментарии.

Первое правило: комментарии не должны дублировать код


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

if (x > 3) {
   …
} // if

Я слышал о преподавателях, которые требуют от студентов комментировать каждую строку кода. Для совсем новичков это может быть оправдано, однако такие комментарии как боковые колёсики на детском велосипеде, которые по мере роста надо снять.

Неинформативные комментарии вредны, потому что:

  • вносят визуальный беспорядок;
  • отнимают время на написание и чтение;
  • могут устареть.

Классический плохой пример:

i = i + 1;         // Add one to i

Комментарий не добавляет полезной информации и требует усилий по поддержке.

Требования комментировать каждую строку справедливо высмеяли на Reddit:

// create a for loop // <-- comment
for // start for loop
(   // round bracket
    // newline
int // type for declaration
i    // name for declaration
=   // assignment operator for declaration
0   // start value for i

Второе правило: хорошие комментарии не оправдывают непонятный код


Ещё один способ некорректного использования комментариев — предоставление информации, которая должна содержаться в коде. Например, когда кто-то назвал переменную одной буквой и добавил комментарий с объяснением:

private static Node getBestChildNode(Node node) {
    Node n; // best child node candidate
    for (Node node: node.getChildren()) {
        // update n if the current state is better
        if (n == null || utility(node) > utility(n)) {
            n = node;
        }
    }
    return n;
}

Комментарий был бы не нужен, если дать переменной правильное название:

private static Node getBestChildNode(Node node) {
    Node bestNode;
    for (Node currentNode: node.getChildren()) {
        if (bestNode == null || utility(currentNode) > utility(bestNode)) {
            bestNode = currentNode;
        }
    }
    return bestNode;
}

Как написали Керниган и Плогер в книге "The Elements of Programming Style": «Не комментируйте плохой код, а переписывайте его».

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


Самый известный комментарий в исходном коде Unix звучит так: «Вряд ли вы это поймёте». Его вставили перед запутанным кодом переключения контекста. Дэннис Ричи позднее объяснил, что это был не наглый вызов, а высказывание в духе «На экзамене такого не будет». Но похоже, что он сам и его соавтор Кен Томпсон сами не поняли свой код, и позднее переписали его. Всё это напоминает о законе Кернигана:

Отладка вдвое труднее первоначального написания кода. Поэтому если вы пишете код как можно умнее, то вы по определению не настолько умны, чтобы его отладить.

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

Четвёртое правило: комментарии должны исключать путаницу, а не вносить её


Ни одно обсуждение плохих комментариев нельзя считать полным без этой истории из «Hackers: Heroes of the Computer Revolution» Стивена Леви:

[Питер Самсон] особенно усложнял ситуацию тем, что отказывался добавлять в свой исходный код комментарии с пояснением, что он делает в каждом конкретном случае. Одна из распространённых программ, написанных Самсоном, состояла из сотен инструкций на ассемблере с единственным комментарием после инструкции под номером 1750. Комментарий был такой: RIPJSB, и люди ломали головы над тем, что это означает, пока кто-то не догадался, что в 1750-м году умер Бах, и что Самсон написал аббревиатуру фразы “Rest In Peace Johann Sebastian Bach”.

Хотя я ценю хороший хак, но это не пример для подражания. Если ваш комментарий вносит путаницу, а не устраняет, то удалите его.

Пятое правило: объясняйте в комментариях не идиоматический код


Лучше комментировать код, который кто-нибудь может счесть ненужным или избыточным, вроде этого кода из App Inventor (источника всех моих положительных примеров):

final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
    return null;
}

Без комментария кто-нибудь может «упростить» код или счесть его таинственным, но необходимым заклинанием. Сэкономьте время и нервы будущих читателей и напишите, для чего нужен этот код. Необходимо оценивать, нуждается ли код в объяснении. Когда я изучал Kotlin, я столкнулся в руководстве по Android с подобным кодом:

if (b == true)

Я удивился, почему бы не заменить его просто на if (b), как сделал бы это на Java. В результате небольшого исследования я выяснил, что допускающие пустое значение булевы переменные явным образом сравниваются с true, чтобы избежать уродливой проверки на null:

if (b != null && b)

Я рекомендую не добавлять комментарии к распространённым идиомам, если только вы не пишете руководство для новичков.

Шестое правило: добавляйте ссылки на исходный код, который вы скопировали.


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

  • какую задачу вы решали;
  • кто предоставил код;
  • почему это решение рекомендовано;
  • что думали об этом комментаторы;
  • работает ли это ещё;
  • как его можно улучшить.

Посмотрите на такой комментарий:

/** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */

Если перейти по ссылке, то вы обнаружите, что:

  • Автора кода зовут Tomáš Procházka, он входит в топ-3% на Stack Overflow.
  • Один из комментаторов предложил улучшение, уже внесённое в репозиторий.
  • Другой комментатор предложил способ избежать пограничного случая.

А теперь сравните с этим комментарием (слегка изменён, чтобы защитить виноватых):

// Magical formula taken from a stackoverflow post, reputedly related to
// human vision perception.
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);

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

Некоторые программисты могут не захотеть указывать, что они не сами написали код, но повторное использование кода может быть разумным шагом, экономящим время и дающим вам преимущество в виде большего количества проверяющих. Конечно, никогда не вставляйте код, который не понимаете. Люди копируют со StackOverflow много кода, который попадает под лицензирование Creative Commons, требующее указания авторства. Для этого достаточно указать ссылку на первоисточник.

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

// Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html
// for a great reference and examples.

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


Конечно, не все ссылки ведут на Stack Overflow.

// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");

Ссылки на стандарты и другую документацию помогут читателям понять проблему, которую решает ваш код. Хотя эта информация может храниться в проектной документации, однако удачно размещённый комментарий станет своевременным указателем. В приведённом примере ссылка подсказывает, что RFC 4180 обновили на RFC 7111, это полезная информация.

Восьмое правило: исправляя баги, добавляйте комментарии


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

 // NOTE: At least in Firefox 2, if the user drags outside of the browser window,
  // mouse-move (and even mouse-down) events will not be received until
  // the user drags back inside the window. A workaround for this issue
  // exists in the implementation for onMouseLeave().
  @Override
  public void onMouseMove(Widget sender, int x, int y) { .. }

Комментарий не только помогает понять код в конкретных методах, но и определить, нужен ли ещё этот код и как его тестировать. Также комментарий может ссылаться на систему отслеживания ошибок:

// Use the name as the title if the properties did not include one (issue #1425)

Конечно, можно с помощью git blame найти коммит, в котором была добавлена или изменена строка. Однако пояснения к коммитам обычно краткие, и самые важные изменения (например, исправление бага №1425) могут не содержаться в последнем коммите (который, скажем, переместил метод из одного файла в другой).

Девятое правило: помечайте комментариями незаконченные реализации


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

// TODO(hal): We are making the decimal separator be a period, 
// regardless of the locale of the phone. We need to think about 
// how to allow comma as decimal separator, which will require 
// updating number parsing and other places that transform numbers 
// to strings, such as FormatAsDecimal

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

Заключение


Комментарии не оправдывают и не улучшают плохой код. Они дополняют хороший код, предоставляя другой тип информации. Как писал Джефф Этвуд, один из сооснователей Stack Overflow: «Код говорит вам «как», а комментарии говорят «почему»». Следование описанным правилам сэкономит время и нервы вам и вашей команде.
Теги: лучшие практикикомментирование коданикто не читает теги
Хабы: Блог компании Mail.ru Group Программирование Анализ и проектирование систем Проектирование и рефакторинг
Всего голосов 34: ↑31 и ↓3 +28
Комментарии 6
Комментарии Комментарии 6

Похожие публикации

Лучшие публикации за сутки

Информация

Дата основания
Местоположение
Россия
Сайт
team.mail.ru
Численность
5 001–10 000 человек
Дата регистрации
Представитель
Павел Круглов

Блог на Хабре