Как правильно комментировать код
Перейти к содержимому

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

Пять правил использования комментариев в коде

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

Реклама

Правило 1. Пишите комментарии на высоком уровне абстракции

Рассмотрим такой пример кода на C++:

Основная его проблема — нарушение инкапсуляции. Пользователю класса Registrator не интересно то, каким образом будет храниться информация. А если в будущем m_persons станет множеством std::set или просто поменяются имена переменных? В конечном итоге автор класса вообще перейдет на хранение записей в базе данных и комментарий в текущей формулировке потеряет всякий смысл.

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

Лучше было бы дать такое описание функции-члену registerPerson() :

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

Реклама

Правило 2. Не пишите избыточные комментарии

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

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

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

Правило 3. Не устраняйте недостатки кода с помощью комментариев

Предположим, что перед нами код ужасного качества. Кто-то может попытаться выправить ситуацию с помощью комментариев. Тогда те, кто в будущем будут работать с этим кодом, вероятно, смогут с ним разобраться, но зачем тратить время таким образом? Рассмотрим пример плохого кода:

Догадаться о том, что делает этот код, не так уж сложно. Видно, что он находит какое-то минимальное значение. Но сказать точно, что это за значение, уже будет непросто. Можно было бы подробно задокументировать эту функцию, однако гораздо эффективнее дать понятные имена переменным и функциям:

Мы лишь переименовали переменные и функции, но код уже стал гораздо лучше. Теперь можно однозначно утверждать, что функция findMinimumAreaFigure() находит в переданном ей векторе фигуру с наименьшей площадью.

Но и это решение не является наилучшим. Удобнее и правильнее будет воспользоваться стандартной STL-функцией std::min_element() :

Правило 4. Следите за актуальностью комментариев

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

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

Рассмотрим пример. Предположим, что у нас есть безопасный для работы в многопоточной среде класс:

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

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

Пример может выглядеть надуманным, но такая ситуация вполне реальна. Возможно, что кто-то из вас даже в нее попадал.

Правило 5. Пишите комментарии только для функций и классов

Что можно сделать с очень длинной функцией, чтобы упростить работу с ней? Один из вариантов — добавить комментарии в каждый ее блок, чтобы логически выделить структуру. Например:

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

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

Заключение

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

Комментарии в C

Комментарий — это последовательность символов, которая начинается с косой черты и звездочки (/*). Компилятор воспринимает комментарий как один пробельный символ, в остальных случаях он игнорируется. Комментарии могут включать любое сочетание символов из представимого набора символов, который включает символы новой строки, но не включает разделитель конца комментария (*/). Комментарии могут занимать несколько строк, но не могут быть вложенными.

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

Комментарии используются для документирования кода. В следующем примере компилятор принимает комментарий:

Комментарии в коде могут находиться в той же строке, что и оператор:

Перед функциями или программными модулями можно вставлять блоки комментариев с описаниями.

Поскольку комментарии не могут содержать вложенные комментарии, то следующий пример вызовет ошибку:

Причина ошибки в том, что компилятор распознает первое сочетание символов, */ , расположенное после слов Open file , как конец комментария. Он пытается обработать оставшийся текст, а обнаружив символы */ за пределами комментария, выдает сообщение об ошибке.

Хотя с помощью комментариев можно скрывать часть кода для тестирования, для этого есть полезная альтернатива: директивы препроцессора #if и #endif и условная компиляция. Дополнительные сведения см. в статье Preprocessor Directives (Директивы препроцессора) в справочника по препроцессору.

Блок, относящийся только к системам Microsoft

Компилятор Microsoft также поддерживает однострочные комментарии, перед которыми ставятся две косые черты ( // ). Если компиляция выполняется с параметром /Za (стандарт ANSI), то такие комментарии создают ошибки. Такие комментарии невозможно расширить до второй строки.

Комментарии, которые начинаются с двух косых черт ( // ), завершаются первым символом новой строки, перед которым не стоит escape-символ. В следующем примере символу новой строки предшествует обратная косая черта (\), создается escape-последовательность. Эта escape-последовательность заставляет компилятор обрабатывать следующую строку как часть предыдущей строки. Дополнительные сведения см. в статье Escape Sequences (Escape-последовательности).

Поэтому оператор i++; скрыт комментарием.

В Microsoft C расширения Microsoft по умолчанию включены. Отключить их можно при помощи параметра /Za.

Завершение блока, относящегося только к системам Майкрософт

Комментарии

Как мы знаем из главы Структура кода, комментарии могут быть однострочными, начинающимися с // , и многострочными: /* . */ .

Обычно мы их используем, чтобы описать, как и почему работает код.

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

Плохие комментарии

Новички склонны использовать комментарии, чтобы объяснять, «что делает код». Например, так:

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

Про это есть хорошее правило: «Если код настолько запутанный, что требует комментариев, то, может быть, его стоит переделать?»

Рецепт: выносите код в функции

Иногда выгодно заменить часть кода функцией, например, в таком случае:

Лучший вариант – использовать отдельную функцию isPrime :

Теперь код легче понять. Функция сама становится комментарием. Такой код называется самодокументированным.

Рецепт: создавайте функции

И если мы имеем такой длинный кусок кода:

То будет лучше отрефакторить его с использованием функций:

Здесь комментарии тоже не нужны: функции сами говорят, что делают (если вы понимаете английский язык). И ещё, структура кода лучше, когда он разделён на части. Понятно, что делает каждая функция, что она принимает и что возвращает.

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

Хорошие комментарии

Итак, обычно «объясняющие» комментарии – это плохо. Но тогда какой комментарий считается хорошим?

Описывайте архитектуру Сделайте высокоуровневый обзор компонентов, того, как они взаимодействуют, каков поток управления в различных ситуациях… Если вкратце – обзор кода с высоты птичьего полёта. Существует специальный язык UML для создания диаграмм, разъясняющих архитектуру кода. Его определённо стоит изучить. Документируйте параметры и использование функций Есть специальный синтаксис JSDoc для документирования функций: использование, параметры, возвращаемое значение.

Подобные комментарии позволяют нам понимать назначение функции и правильно её использовать без необходимости заглядывать в код.

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

Также существуют инструменты, например, JSDoc 3, которые умеют генерировать HTML-документацию из комментариев. Получить больше информации о JSDoc вы можете здесь: https://jsdoc.app/>.

Почему задача решена именно таким способом?

Важно то, что написано. Но то, что не написано, может быть даже более важным, чтобы понимать происходящее. Почему задача решена именно этим способом? Код не даёт ответа.

Если есть несколько способов решить задачу, то почему вы выбрали именно этот? Особенно если ваш способ – не самый очевидный.

Без подобных комментариев возможна следующая ситуация:

  1. Вы (или ваш коллега) открываете написанный некоторое время назад код и видите, что в нём есть, что улучшить.
  2. Вы думаете: «Каким глупым я раньше был и насколько умнее стал сейчас», и переписываете его на «более правильный и оптимальный» вариант.
  3. …Желание переписать код – это хорошо. Но в процессе вы понимаете, что «оптимальное» решение на самом деле не такое уж и оптимальное. Вы даже смутно припоминаете, почему, так как в прошлый раз вы уже его пробовали. Вы возвращаетесь к правильному варианту, потратив время зря.

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

В коде есть какие-то тонкости? Где они используются?

Если в коде есть какие-то тонкости и неочевидные вещи, его определённо нужно комментировать.

Итого

Комментарии – важный признак хорошего разработчика, причём как их наличие, так и отсутствие.

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

Комментируйте:

  • Общую архитектуру, вид «с высоты птичьего полёта».
  • Использование функций.
  • Неочевидные решения, важные детали.

Избегайте комментариев:

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

Средства для генерации документации по коду, такие как JSDoc3, также используют комментарии: они их читают и генерируют HTML-документацию (или документацию в другом формате).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *