[Из песочницы] Как писать хорошие комментарии к коду: «зачем», а не «как»

Привет, Хабр! Представляю вашему вниманию перевод статьи «Writing good comments: the why, not the how» автора Jack Franklin.

image

Комментирование кода в программистской среде нередко считается пустой тратой времени или неким сигналом о том, что код можно и улучшить. Вот цитата из файла CONTRIBUTING.md, который я нашёл на Гитхабе (и таких примеров очень, очень много):

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


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

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


Итак, положим, вы свежеиспечённый студент, только начавший этот курс. Что вы будете делать? Комментировать код, конечно же!

// задаём значение из переменной окружения bar
const inputValue = process.ENV.bar

// а теперь умножим на 2
const newValue = inputValue * 2

// теперь передадим значение функции square
const finalValue = square(newValue)

// эта функция возводит число в квадрат и возвращает результат
const square = (x) => x * x


Люди, говорящие, что комментарии — это плохо, на самом деле думают о таких вот комментариях. И они при этом совершенно правы! Комментарии вроде тех, что выше, отвечающие в программировании на вопрос «как?», совершенно бесполезны. Все эти комментарии не привнесли в код ничего, что нельзя понять из него самого.

Отвечайте на вопрос «зачем?»


Проблема с комментариями выше заключается в том, что они объясняют, как. Поясняют шаги, которые мы делаем в коде. Такие комментарии крайне редко оказываются полезными; код сам по себе куда лучше рассказывает о нужном порядке действий. В конце концов, строки кода — лишь инструкции, объясняющие компьютеру, как выполнить задачу.

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

Как-то раз работал я в процессинговой компании. У нас каждый день выполнялся огромный SQL-запрос, выбиравший платежи для выплаты. Запрос был хорошо оптимизированным — нам нужно было, чтобы он работал весьма быстро — и притом крайне сложным: приходилось учитывать множество пограничных случаев. Мы очень старались, чтобы он был настолько ясным, насколько вообще возможно. Впрочем, этот запрос никогда не смог бы полноценно быть интуитивно понятным и лёгким для восприятия. Он просто содержал слишком много кода с кучей условий и логикой, понять которую можно было лишь в контексте нашей компании и того, как она работала.

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

// Сейчас key может быть передана как свойство. Это потенциальный источник проблем, 
// если key при этом отдельно явно объявлена (например, 
// или
). Тут следовало бы исключать key, переданную со свойствами, // но пока что мы используем jsxDEV во всех случаях, кроме //
, потому что на данный момент невозможно понять, // объявлена ли явно key неопределённой или нет. if (maybeKey !== undefined) { key = '' + maybeKey }


(И вот ссылка на него на Гитхабе).

Обратите внимание на сам код, о котором речь:

if (maybeKey !== undefined) {
  key = '' + maybeKey
}


Не так сложно понять, что он делает. Если значение maybeKey не неопределено, мы присваиваем переменной key переведённое в строку значение maybeKey. Пометка: это небольшой JavaScript-трюк — '' + maybeKey переведёт содержимое maybeKey в строку.

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

Если хотите посмотреть на какой-нибудь комментарий, который я оставлял в написанном мной коде, то вот один из них (TypeScript/Closure Compiler). Это хороший пример того типа комментариев, которые я считаю очень ценными.

Любой код в итоге можно понять. В конце концов, код — не что иное, как инструкции, объясняющие компьютеру порядок действий. Код может сбивать с толку, но он не может лгать; если времени достаточно, любой разработчик может пошагово разобрать код и понять, что тот делает. Куда уж сложнее иногда понять, зачем он это делает. Так что оставьте своим коллегам (или будущему-себе-через-шесть-месяцев) немного контекста о том, почему и для чего ваш код делает то, что он делает. Будет гораздо лучше.

© Habrahabr.ru