No comments

в 7:45, , рубрики: Блог компании Маклауд, код, коменты, Программирование, Совершенный код, чистота кода

No comments - 1

«Комментарии должны составлять 5% от общего количества баллов», — заявил мой коллега-преподаватель.

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

«Я хочу, чтобы студенты изначально перенимали хорошие привычки. Вы ведь согласны, что добавление комментариев улучшает качество кода?», — спросил меня коллега, немного расстроенный моей негативной реакцией.

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

Подождите, что за ересь? Комментарии никому не мешают. Или всё-таки мешают?

Есть две причины, по которым я считаю комментарии антипаттерном:

  1. Они неизбежно устаревают. Разработчики забывают обновлять комментарии при рефакторинге кода и создании новых функций. Когда такое происходит, комментарии становятся первопричиной того, чему должны были препятствовать, а именно запутанности. Особенно справедливо это для крупных компаний, в которых множество людей активно изменяет общую кодовую базу. Представьте состояние новичка, который не может разобраться, почему дом имеет комментарий, называющий его «пальмой» (Palm Tree).
  2. Программисты (в том числе и я) пишут избыточные или плохие комментарии. Я замечал это в каждой из компаний, где я работал, и этим грешат многие превосходные программисты. В моей команде в Google было правило, что каждому определению буфера протокола должен предшествовать комментарий. Поэтому у нас была куча примеров кода, который выглядел примерно так:

// Represents a Dog.
message Dog {
    // The id of the dog.
    string id = 0;
    // The name of the dog.
    string name = 1;
    // The breed of the dog.
    string breed = 2;
}

Избыточные комментарии — это шум, способный сделать файлы в два раза длиннее, чем они должны быть.

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

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

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

# Seller is eligible to be paid under the following conditions:
# 1. It's past 2020/5/1 when we got legal approval to make payouts
# 2. It’s Nov/Dec since those are the only months eligible
# 3. User is not from list of countries that are banned
today = date.today()
if today > date(2020, 1, 1) and (today.month == 11 or today.month == 12) and user.country not in ['Narnia', 'Odan', 'Maldonia']:
    # This function does the actual payout by calling Stripe
    # It saves the response asynchronously.
    payoutHandler()

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

  1. Условия выплаты. Без комментария в начале читателю самому бы пришлось разбираться в парсинге кратких подусловий в условном операторе, чтобы понять, должен ли выполняться платёж.
  2. Почему использованы конкретные константы (2020/5/1, 11, 12 и [‘Narnia’, ‘Odan’, ‘Maldonia’]) и что они обозначают.
  3. Что делает метод payoutHandler().

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

PAYOUT_APPROVAL_DATE = date(2020, 5, 1)
BANNED_COUNTRIES = ['Narnia', 'Odan', 'Maldonia']
NOVEMBER, DECEMBER = 11, 12
ELIGIBLE_MONTHS = [NOVEMBER, DECEMBER]
today = date.today()
is_past_approval_date = today > PAYOUT_APPROVAL_DATE
is_eligible_month = today.month in ELIGIBLE_MONTHS
is_user_from_banned_country = user.country in BANNED_COUNTRIES
if is_past_approval_date and is_eligible_month and not is_user_from_banned_country:
 stripe_payout_resp = callStripeToPayout(user)
 saveResponseAsync(stripe_payout_resp)

Обратите внимание, что информация, которая раньше передавалась в комментариях, теперь передаётся при помощи временных переменных (is_past_approval_date, is_eligible_month, is_user_from_banned_country), констант (BANNED_COUNTRIES) и глаголов в качестве имён функций.

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

То есть комментарии никогда не нужно использовать? Какое-то слишком строгое требование.

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

# This code removes the invalid control characters because the 
# AS400 processor cannot handle them

назовите свою функцию

def remove_AS400_incompatible_control_chars():

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

# Prevents a rare but severe race condition which happens when...

# Closing this write transaction before making the RPC to prevent stale locks

Возможно, вам стоит изучить свою кодовую базу на предмет возможности замены комментариев в ней на самодокументируемый код.


Маклауд предлагает высокопроизводительные серверы для любых задач — до 128 vCPU, 512 ГБ RAM.
Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Автор: Mikhail

Источник


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


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js