Так много может пойти не так с комментариями.

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

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

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

Лучший комментарий - это отсутствие комментариев

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

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

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

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

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

Различные типы комментариев

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

Документация

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

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

Вот пример простого цикла for, который не нуждается в комментариях, если все сделано правильно, потому что он не дает много дополнительной информации, если мы перепишем/рефакторингом:

public List<String> processItems(List<String> items) {
    List<String> processedItems = new ArrayList<>();

    for (String item : items) {
        // Filter items
        if (item.startsWith("_") == false) {
            continue;
        }

        // Transform and add to list
        item = item.toUpperCase()
        processedItems.add();

        // Limit to 5 items
        if (processedItems.size() >= 5) {
            break;
        } 
    }

    return processedItems;
}

Лучше подумать о рефакторинге нашего кода в несколько методов с понятными именами:

public List<String> processItems(List<String> items) {
    List<String> processedItems = new ArrayList<>();
    for (String item : items) {
        if (shouldBeFiltered(item)) {
            continue;
        }
        processedItems.add(transform(item));
        if (limitReached(processedItems, 5) {
            break;
        } 
    }
    return processedItems;
}

Это лучше, но мы могли бы сделать еще больше, чтобы сделать его более читабельным. Переписывая исходный код с помощью Java Stream API, он становится еще более понятным:

public List<String> processItems(List<String> items) {
    return items.stream()
                .filter(item -> item.startsWith("_"))
                .map(String::toUpperCase)
                .limit(5)
                .collect(Collectors.toList());
}

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

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

Вот пример из Apache Commons Lang3:

/**
 * <p>Checks if a CharSequence is not empty ("") and not null.</p>
 *
 * <pre>
 * StringUtils.isNotEmpty(null)      = false
 * StringUtils.isNotEmpty("")        = false
 * StringUtils.isNotEmpty(" ")       = true
 * StringUtils.isNotEmpty("bob")     = true
 * StringUtils.isNotEmpty("  bob  ") = true
 * </pre>
 *
 * @param cs  the CharSequence to check, may be null
 * @return {@code true} if the CharSequence is not empty and not null
 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
     */
public static boolean isNotEmpty(CharSequence cs) {
    ...
}

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

Уточнение/описание

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

// Bad: Sets the value of size to 32
// Good: Underlying data pipeline only supports size 32
int size = 32;

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

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

// BAD:
// Regex for customer names 
Pattern nameRegex = Pattern.compile("([A-Za-z]+)\\s{1}([A-Z]\\.\\s{1})?([A-Za-z]+)");
// BETTER:
// Regex for validating customer full names (e.g. "Benjamin L. Weidig", "Ben Weidig")
Pattern nameRegex = Pattern.compile(
    "([A-Za-z]+)" +          // Firstname (mandatory)
    "\\s{1}" +               // Whitespace (mandatory, 1)
    "([A-Z]{1}\\.\\s{1})?" + // Initial with dot and space (optional)
    "([A-Za-z]+)"            // Lastname (mandatory)
);

Требования

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

Вывод

Хорошая привычка комментировать имеет много свойств:

  • Намерение, а не действие Мы видим код перед собой, нам не нужен комментарий, повторяющий его. Вместо этого нам нужно знать, зачем этот код. Выразите намерение вашего кода. Уровень детализации зависит от сложности кода, но, возможно, упрощение кода является лучшей долгосрочной стратегией, чем написание большого количества поясняющих комментариев.
  • Неверный английский Неправильный синтаксис, опечатки и неправильная грамматика могут привести к тому, что комментарий может быть неправильно понят, и лишить его первоначальной цели. Если английский (или любой другой язык, на котором ваша команда предпочитает документировать) не является вашим родным языком, сделайте одолжение другим и используйте средство проверки орфографии. Особенно не носители языка будут вам за это благодарны.
  • Точные и лаконичные
    Комментарии не должны перевешивать строки кода, если они не используются для документирования. Трудно найти и прочитать код, если вы видите только комментарии. Комментарии должны быть дополнением к коду, а не его заменой. Их видят люди, читающие код, а не руководство без кода.
  • Знайте свою аудиторию
    Необходимость комментариев для документации или пояснений сильно различается для разных целевых аудиторий нашего исходного кода. Внутренний код может нуждаться в большем пояснении, чем в документации, но в сторонней библиотеке гораздо больше документации, чем в нашем собственном коде. Прокомментируйте свой код для нужного получателя и носителя, скрин, а не отдельное руководство.