Скажи мне, что делает твой код, не говоря мне об этом.

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

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

На протяжении этих лет я сталкивался с разными типами комментариев, в основном на Java и TypeScript. Мой вывод на данный момент заключается в том, что независимо от языка, который вы используете, только конкретные случаи оправдывают использование комментариев. Вот что я узнал.

Примечание. Поскольку нижеследующее относится не только к одному языку программирования, я буду использовать более общий терминфункциявместо соответствующей специальной терминологии, например,methodдля Java и т. д.

Избыточные комментарии

Избыточные или шумовые комментарии — это комментарии, которые, ну… являются излишними. У них нет цели. Они не добавляют ценности. Они только добавляют строки и загромождают ваш код. Через некоторое время они превращаются в блоки шума, которые ваши глаза учатся механически игнорировать, пока вы читаете код. Вот пример:

public class Person {
    /** The first name. */
    private String firstName;
    
    /** The last name. */
    private String lastName;
    
    /**
     * Returns the full name of the person.
     */
    public String getFullName() {
        return firstName + ' ' + lastName;
    }
}

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

Почему эти переменные или функции нуждаются в комментариях? Ответ: нет!

Почему им не нужны комментарии? Ответ в том, что у них есть имена собственные! Имена, которые ясно сообщают о своей цели. Имена собственные устраняют необходимость в комментариях к коду и упрощают его понимание.

Отвратительные комментарии

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

Давайте посмотрим на пример:

// Check if our hero can defeat the villain
if (hero.strength > villain.strength && 
    hero.energy > 30 && !villain.bersekerMode) {
    // ...
}

Условие в операторе if- довольно сложное, и поэтому трудно сразу сказать, что оно проверяет. Даже после внимательного прочтения его намерения могут быть неясны. Был добавлен комментарий, чтобы объяснить, что делает код, в попытке компенсировать плохой дизайн.

Предыдущий фрагмент можно изменить на:

if (hero.canDefeat(villain)) {
    // ...
}

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

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

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

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

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

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

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

Устаревшие комментарии

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

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

Когда это имеет смысл?

Итак, когда имеет смысл использовать комментарии к коду?

1. При написании общедоступного API всегда предоставляйте хорошую документацию, объясняющую, как его использовать.

2. Когда вам нужно сообщить о намерениях, стоящих за решением, касающимся реализации, например, реализовать обходной путь из-за проблемы во внешних библиотеках. Небольшой пример из Angular:

public dropped(event: CdkDragDrop<Item[], Item[], Item>) {
    // VirtualScrolling and CdkDropList don’t work well together.
    // Workaround solution: set the correct previousIndex manually.
    event.previousIndex = event.previousContainer.data.findIndex(
        (item) => item.id === event.item.data.id
    );
   // ...
}

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

// TODO: Revert temporary changes (special handle of bugged type)
// when backend issue is resolved.
public onSelection(selected: SomeObjectWithType): void {
    if (selected.type === ObjectType.TypeWithBug)) {
        // handles buggy case separately
    } else {
        // original behavior
    }
}

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

// Don't run unless you got more than 10 GB of RAM free.
// Alternatively, decrease the value of N.
public void _testWithLargeN() {
    // ...
}

5. Что касается авторских прав и комментариев, которые иногда необходимо ставить в начале каждого исходного файла.

Заключение

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

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