Комментировать или не комментировать?

в 6:12, , рубрики: комментарии, Программирование, разработка, Совершенный код, метки: ,

Комментировать или не комментировать?По-настоящему хороший комментарий — тот,
без которого вам удалось обойтись.
© Дядюшка Боб

В последнее время меня стали очень утомлять оживлённые дебаты о том, нужно ли комментировать код. Как правило, по одну сторону баррикад — самоуверенные джуниоры, имеющие непререкаемую позицию вида «А как же его не комментировать, ведь без комментариев непонятно будет!». По другую — умудрённые опытом сеньоры. Они понимают, что если возможно обойтись без комментариев, то «Лучше бы, чёрт возьми, так и сделать!». Наверное, у многих жажда комментировать идёт со студенческой скамьи, когда товарищи преподаватели заставляли комментировать каждую строчку, «чтобы студент лучше разобрался». В реальном проекте не должно быть кучи комментариев, которые только и делают, что засоряют код. Впрочем, я не агитирую вообще не писать комментарии, но если вам удалось написать такой код, который не требует пояснений, то расценивайте это, как свою маленькую победу. Сразу хотелось бы сослаться на нескольких очень умных книжек, на основе которых формировалось моя позиция. Я люблю и уважаю авторов этих работ, полностью разделяя их мнение.


Итак, что же меня так раздражает в комментариях? Приведу несколько основных тезисов:

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

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

Давайте обсудим некоторые типичные сценарии, в которых можно сказать что-нибудь определённое про надобность комментария. Примеры кода я привожу на C#, но для данной темы это не принципиально.

Когда без комментариев можно обойтись

Комментарии, которые повторяют код

Давайте взглянем на код:

// Этот метод отвечает за подсчёт суммы элементов массива
public int CalcSumOfElement(int[] elements) // Метод принимает на вход массив элементов
{
  int result = 0; // Заводим специальную переменную под результат
  int n = elements.Length; // Узнаём длину массива, т.е. количество элементов
  for (int i = 0; i < n; i++) // Запускаем цикл по всем элементам
    result += elements[i]; // Пребавляем к результату очередной элемент
  return result; // Возвращаем результат
}

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

Комментарии, которые поясняют синтаксис

Ну, а вот такой пример:

public class Item
{
  private int value; // Это приватное поле, извне оно не доступно

  // Это конструктор
  public Item(int twoValue)
  {
    value = twoValue >> 1; // Два знака больше означают побитовый сдвиг вправо
    // таким образом мы делим число на два
  }
}

Если это лабораторная работа первокурсника, то всё нормально. А вот если это продакшн код, и ваши программисты нуждаются в таких комментариях, то у меня для вас плохие новости. Наверное, эта статья не для вас.

Комментарии, которые поясняют стандартные классы

HashSet<int> set; // Это структура данных, которая называется Хеш-Сет
// Она представляет собой множество элементов
// Мы очень быстро можем узнать, есть ли элемент в этом множестве или нет
// Подробнее про хеш-таблицы можно почитать в википедии: http://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0

Если программист действительно не знает назначение какого-то стандартного класса или метода, то он всегда может погуглить / почитать документацию / спросить у товарища. А большинство нормальных программистов скорее всего и так всё знает. Поэтому польза таких комментариев ну очень сомнительна.

Комментарии, которые компенсируют плохие наименования

// Устанавливаем соединение с сервером
// public void DoIt()

Я согласен, что далеко не всегда удаётся придумать хорошее название для класса/метода/свойства/переменной. А если проект сдавать вчера, то времени на придумывание красивого названия просто нет. А давайте возьмём какое-нибудь произвольное название, а в комментарии объясним то, что происходит. Это же намного проще и быстрее! Или же всё-таки вы найдёте минутку-другую на придумывание понятного названия?

Комментарии, которые объясняют абзац

Часто приходится слышать подобные заявления: «Не, ну этот метод занимает 300 строк, он очень много всего делает. Без комментариев в нём не разобраться. Сейчас я напишу перед каждыми 10-строчками о том, что в них делается». Если действительно дела обстоят так, то, возможно, что-то вы делаете не так. Возможно стоит разбить большой 300-строчный метод на несколько маленьких методов. И каждому маленькому методу дать понятное название — тогда и комментарии будут не нужны.

Комментарии, которые поясняют константы

public int GetSeconds(int hours)
{
  return hours * 3600; // 3600 - это количество секунд, образующих час
}

Ну, в таком варианте, наличие комментария — это более адекватный вариант, чем просто магическое число, которое закралось в код и непонятно что обозначает. Но ещё лучше бы было сделать именованную константу, из названия которой всё было бы понятно. Например, так:

private const int SecondsInHour = 3600;
public int GetSeconds(int hours)
{
  return hours * SecondsInHour;
}

Комментарии, которые не относятся к программированию

Мне очень нравится байка из «Совершенного кода» про то, как один программист всю ночь пытался расшифровать вот такой комментарий.

MOV AX, 723h ; R. I. P. L. V. В. 

А несколько месяцев спустя он встретился с автором этого кода и узнал, что комментарий расшифровывается следующим образом: «Rest in peace, Ludwig van Beethoven», т.к. 723 — это шестандцатитичное представление года смерти Бетховена.
Увы, некоторые программисты считают программный код своеобразным форумом, в котором можно общаться. Некоторые пытаются проявить своё остроумие (чуть ли не анекдоты рассказывают), другие пытаются нам что-то рассказать о себе (типа «Сейчас уже три часа ночи, но я всё равно пишу этот класс, ведь я так люблю программировать»). Не нужно так делать, для общения есть сотни других способов. Если комментарий вставлен в код, то он должен нести в себе что-то полезное для проекта.

Комментарии, которые содержат мысли

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

public void Main()
{
  // Ну, это очень полезный метод.
  // Он выполняет основную логику этого класса.
  // Сначала я хотел назвать его Run.
  // Но потом подумал, Run переводится «бежать».
  // А этот метод никуда не бежит, он очень медленный.
  // Я думал об этом, пока мыл посуду.
  // И когда я её домыл, я вернулся к компьютеру и переименовал метод в Main.
  // Ведь это главный метод данного класса, пусть он называется Main.
}

Комментарии, которые содержат примеры использования

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

// Sum(1, 2) == 3
// Sum(2, 1) == 3
// Sum(2, 2) == 4
public int Sum(int a, int b)

А я так считаю — для каждой задачи должен быть свой инструмент. Для этой задачи люди давно придумали удобный инструмент, он называется Unit-тесты. Очень толковая штука. Нужны ли на самом деле Unit-тесты или нет — также дискуссионная тема. Но если в проекте всё-таки возникла потребность описать для метода примеры возвращаемых результатов, то почему бы просто не сделать соответствующий Unit-тест?

Комментарии, которые содержат историю написания

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

// 11.06.13: Исправил багу в методе. Раньше он работал так-то так-то, а теперь работает иначе.
// 12.06.13: Ой, та бага — была не бага. Вернул всё обратно.

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

Комментарии, которые содержат код

Эти комментарии меня особенно печалят. Читаешь, скажем, код какого-нибудь хорошего класса. И тут:

// int number = GetNumber()
// int number = 4;
// int number = 5;
int number = 4;
// double number = 4.5;
// decimal number = 4.5;
// string number = "Это число";

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

Комментарии, которые непонятны

bool flagA = true;
bool flagB = false;
bool flagC = true;
if (Condition(flagA, flagB, flagC))
  Foo();
// else флаг равен true, выключение сервера

В подобных случаях никогда нельзя догадаться что хотел сказать автор. Какой флаг равен true? Он всегда равен true в else-ветке или тут нужно дописать код, в котором нужно присвоить флагу значение true. А что за сервер, почему он выключается? Он выключится сам или нам нужно самим его выключить?
От подобных комментариев вреда больше, чем пользы. Сведений он в себе по факту не несёт, а вместо этого только смущает читателя. Не смущайте читателя вашего кода! Или не пишите ничего вовсе, или потратьте время на написание доходчивого сообщения, которое всем будет понятно.

Комментарии, которые содержат ну очень много текста

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

Комментарии, которые врут

// Произведение двух чисел
public int Sum(int a, int b)

Вы опять смущаете вашего читателя. Что тут происходит? Возможно, метод когда-то считал произведение, а потом его переделали в сумму, комментарий стал устаревшим. А может наоборот: комментарий обновили, а про название метода забыли. А может метод с самого начала считал сумму, а программист ошибся при комментировании. А метод может быть на самом деле очень сложный, придётся потратить много времени, чтобы разобраться, какая из черепашек обманывает.

Когда можно и прокомментировать

Комментарии, которые повышают уровень абстракции

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

Комментарии, которые объясняют необъяснимое

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

Комментарии, которые TODO

Вопрос опять-таки дискуссионный. Одни скажут, что есть IssueTacker, давайте все задачи хранить там. Другие скажут, что зачем нам создавать много мелких Issue, когда можно просто расставить комментарии специального вида, которые будут обращать внимание разработчиков на то, что тут надо бы дописать функционал. Благо, современные IDE умеют находить все TODO-комментарии и выдавать их большим красивым списком, так что не нужно бояться потерять подобные инструкции на будущее. Нужно сразу договориться в команде о том, какая методология будет использоваться. Многие программисты считают TODO-комментарии очень удобными, ничего особо криминального в их использовании нет.

Комментарии, которые обращают внимание

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

Комментарии, которые документируют

Многие генерируют документацию на основе комментариев специального вида (такой подход используется во многих языках). Есть и другие инструменты по созданию документации без комментариев, но в силу разных обстоятельств в некоторых проектах принципиально использовать именно комментарии для документирования, тут уж никуда не деться. Но тут речь идёт скорее о публичном API, а не о private-методе во внутреннем проекте. В команде должна быть договорённость о том, когда и где будет использоваться подобный подход к документации. Ваше время очень ценно, не следует его тратить на создание такой документации, которая никогда никем не будет использоваться.

Комментарии, которые содержат юридическую информацию

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

Резюме

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

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

Автор: DreamWalker

Источник

Поделиться

* - обязательные к заполнению поля