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

30 мая 2010 г. | | |

Все мы не раз слышали, что код нужно комментировать, чтобы в нём потом можно было разобраться. Неопытные программисты часто возражают : "Это мой код, и я знаю, что он делает, и не забуду даже через полгода, что значит переменная k в выражении empS += k*arr[i] + bon[i]!" И при этом совершенно не учитывается, что кроме них, этот код могут править другие программисты - те бедолаги, которым придется сопровождать этот код. Но, опять же, комментарии, написанные, лишь бы написать, чтоб не цеплялись, - это еще хуже, чем отсутствие комментариев.

При плохом выполнении комментирование является пустой тратой времени и иногда причиняет вред.
С.Макконнелл

Например, в следующем коде комментарии совершенно бесполезны, потому что совершенно ничего не говорят:

int k = getKoeff(m); /*инициализируем переменную k значением, возвращаемым методом getKoeff */
double empS = 0.0; //инициализируем переменную empS нулем
for(int i=0; i<getWNub(m); i++)
{
empS +=k*arr[i] + bon[i]; //вычисляем сумму в цикле
}

Раз уж зашел разговор о полезности комментариев, то давайте определим цели - для чего вообще нужны комментарии в коде? Комментарии должны давать представление о том, что делает данный код, должны помогать читать его, так? На мой взгляд, самый лучший комментарий к коду - сам код.
Хороший код сам является самой лучшей документацией. Если код настолько плох, что требует объемных комментариев, попытайтесь сначала улучшить его.
С.Макконнелл
Я не призываю отказаться от комментариев в коде, я призываю к написанию ясного кода, который легко понять и модифицировать даже по прошествии длительного периода времени.
Что в моем понимании "ясный код"? Это, конечно же, самодокументирующийся код. Например, предыдущий кусок кода можно переписать так:

int koefficient = getSalaryKoefficient(monthNumber);
double employeeSalary = 0.0;
int workingDaysInCurrentMonth = getWorkingDaysNumber(monthNumber);
for(int dayNubmer=0; dayNumber<workingDaysInCurrentMonth; dayNubmer++)
{
employeeSalary +=koefficient*workingHours[dayNubmer] + dayBonus[dayNubmer];
}

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

for(element = 0; element<elementCount; element++)
{
/*Для деления на 2 используется операция сдвига вправо. Это сокращает время выполнения цикла на 75% */
elementList[element] = elementList[element] >>1;
}

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

//Цвет фона по умолчанию - белый
itemBgColor = Color.FromAGB(255,255,255);

Этот код лучше будет даже переписать следующим образом:

const Color DEFAULT_BG_COLOR = Color.FromAGB(255,255,255);
...
itemBgColor = DEFAULT_BG_COLOR;

Кроме того, следует комментировать использование недокументированных возможностей или исправление обнаруженных ошибок - ведь в следующих версиях системы этих возможностей может и не быть, а ошибки могут быть исправлены :)
Полезным может оказаться документирование ограничений, если они не заданы константами с говорящими именами, а используются в коде как есть - в виде чисел. Но с таким настоятельно советую бороться :)
В своей практике кроме всего выше перечисленного я предпочитаю давать краткое описание методу перед началом его кодирования, при этом использую очень замечательную возможность документирования кода в Visual Studio. Это выглядит так:

/// <summary>
/// Возвращает следующий по номеру ваучер по отношению к номеру текущего ваучера
/// </summary>
/// <returns>VoucherItem</returns>
public VoucherItem GetNextVoucherItem()
{
return VoucherRepository.GetNextVoucher(this.VoucherNumber);
}

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

0 коммент.:

Отправить комментарий