Pull to refresh

Comments 134

int main()
{
     int a,b;
     // Принять от пользователя два числа
     cin>>a;
     cin>>b;
     //Завести переменную для результата сложения
     double sum = a+b;
     // Вернуть результат сложения
     cout<<sum;
}


По-моему, это пример просто ужасных комментариев. Именно из-за такого кошмара я считаю, что комментарии — зло. Потому что он просто дублируют код, создают шум, не не вносят ничего нового. Комментарии должны пояснять непонятные моменты, трудные или спорные ситуации. А то, что "cout<<sum" — это «Вернуть результат сложения» я вижу и без комментария.
Хотели листинг чего-то посложнее? Автор прекрасно показал суть метода, чего же более?
Да, чтобы была тема для обсуждения.
Суть метода ТС заключается в том, что он пишет алгоритм по-русски, а потом тоже самое на языке программирования. Мне кажется что такой подход будет в основном шум и порождать, каким бы сложным не был листинг.
Если комментарии пишутся на том же уровне абстракции, что и конструкции языка программирования, то согласен с вами — это только мешающий шум. Я за такие бестолковые и отвлекающие комментарии всегда ругал своих начинающих разработчиков и заставлял переделывать. А вот если уровень абстракции комментариев выше, то комментарии становятся полезными.
За редким исключением комментарии должны быть предметного уровня. Например, оперировать понятиями «документ», «проводка», а не «цикл», «просканируем базу» и т.п.
Поддерживаю.
Это может в университетах так надо делать, когда курсач без этого не принимают.
Но это чаще всего для того, чтобы человек хотя бы понимал, о чем у него курсач, который ему кто-то написал.
А под общую «гребенку» попадают все.
Автор аж два раза сказал, что так делать именно так не стоит :) Для того и утрируют, чтобы в глаза бросилось.
В целом же, я за подобный подход — перед кодированием описать алгоритм в комментариях очень часто бывает полезным.
Два раза? Вижу только один: «Комментарии вида // инициализируем счетчик бесят больше чем их отсутствие»
И то, нигде не вижу надписи, что код в примере — плохой.

Неужели вы алгоритм не можете сложить в голове и его необходимо обязательно записать перед кодированием?
Не любой алгоритм можно сразу сложить в голове. Помогает псевдокод.
Первый раз было сказано, что пример сильно утрирован, перед самим примером.
Я то и алгоритм сложить могу, и даже держать его в голове энное время, пока не закодирую, но вот никто не даст гарантии, что в это время на меня не рискнут свалить какую-нибудь рабочую или домашнюю неожиданность, что я сам не отвлекусь, что не придётся реанимировать комп после внезапного скачка напряжения. Ну Вы поняли, да?
Если утрировать, сильно утрировать: «Зачем нам контроль версий? Мы всегда сами помним что и зачем было сделано даже другими людьми в прошлом веке на устаревшей технологии, неужто алгоритм не удержали в голове?». Как-то так…
Пример левый вообще.
Почему на вас «не рискнут свалить какую-нибудь рабочую или домашнюю неожиданность» когда вы пишете комментарии вместо кода?
Нет, возникло небольшое недопонимание, давайте тогда по шагам.
1) Допустим, алгоритм продумали, не записали, начали сразу кодить, как труЪ герой.
2) В процессе Вас отрывают на неопределённое количество времени. («Слууушай дорогой, а у меня есть новость, ты стал папой! Правда, здорово?» «Да, милая, вот сейчас, через часов 10, допишу код только...»)
3) Возвращаясь к недонаписанному коду, вспоминаете, что это была малознакомая, либо непростая область, например, графику мучали, или нужно было писать нечто согласованное с несколькими большими формулами-законами. Возможно сам алгоритм даже в голове занимал у Вас полотнище размером с футбольное поле, исписанное мелко-мелко да ещё и хлебными крошками.
4) Есть выбор: посмотреть на краткое описание алгоритма в комментариях, либо начинать заново продумывать алгоритм или архитектурные решения.

Ну да, разумеется, можно писать крутую и модную документацию, технические спецификации, но как часто они соответствуют правде?
1. Судя по примеру — описание в стиле комментариях будет такой же длины и сложности, как описание в коде.
2. Такие полотнища необходимо разбивать на мелкие участки и писать почучуть.
3. Часто описания подобных алгоритмов требуют рисунков, потому комментариями в коде всё-равно не обойтись и лучше использовать бумажку и ручку.
4. Вы вряд-ли сможете внятно описать сложный алгоритм в комментарии, или комментарий будет значительно длиннее самого кода.
1, 4) Не факт, иногда может хватить и предложения на метод, или отсылки на существующий документ.
2) Это вообще на первое место ставить, а ещё не забыть упомянуть прототипирование :) На самом деле, просто разный уровень макетирования, абстракции (И на всякий случай, я ни разу не говорил, что необходимо опускаться до коментариев вида «скадываем переменную А и пе...»).
3) Сдаюсь безоговорочно, листок+ручка решают, редко пишу без зарисовок.

На самом деле, сейчас спор уже ни о чём :) Банально — у каждого свои привычки.
Самодокументируемый код? Да хоть плюньте в меня, адепты этого красивого мифа, а я лучше перестрахуюсь с риском схватить всего лишь косой взгляд «вот же тупой прогер был, всё закомментил», зато прямо в коде будут подсказки по алгоритмам или принципам, а в системе контроля версий будут все даты, персоны, ссылки на доки и причины изменений.

Как правило для основной массы «произведений», чуть что сложнее X=Y+2 или древнее полугода — начинается территория ужасов. Причём есть даже примеры из весьма солидных контор, когда в энтерпрайз коде, пол года назад сданном в продакшен и не раз уже проданном, замечали явный бред.
> 2. Такие полотнища необходимо разбивать на мелкие участки и писать почучуть.

По сути это и предлагается! Потому что вспомнить всю простыню после «довольно неожиданного» « — Слууушай дорогой, а у меня есть новость, ты стал папой! Правда, здорово?» намного сложнее, если вообще возможно, чем вспоминать кусок, да и тот, уже немного подсказанный тобою же в комментариях.
Поддерживаю.
Как пишет Макконел — «Если код нуждается в комментариях — значит это плохой код» (как то так)
Комментировать полезно методы, классы, большие сущности. Весь же остальной код в идеале должен быть «самодокументируемым». Лишь совсем уж не очевидные строчки можно обрамить поясняющим комментом.
Написал тоже что и вы ниже теме же словами :)
> Комментировать полезно методы, классы, большие сущности.
Именно поэтому и написал в скобках о необходимости!
«класс -> метод -> код внутри метода (если необходимо).»

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

Вот с этим я категорически не согласен. Надо учится написанию качественного кода, который не нуждается в комментариях.
Написали вы небольшой модуль! В нем вам все понятно и логично, но все будет понятно и логично до тех пор пока код не попадет в руки других людей, которые захотят его изменить или даже просто воспользоваться. Очевидные для вас вещи могут быть далеко не очевидны другим. Даже комментарии к функции: что она делает, что принимает, что возвращает, требуют умения краткого и четкого изложения сути. При этом сам код может быть вполне самодокументированным!
Я уже несколько лет не работаю в одиночку. Код который я пишу, тут же подхватывают другие разработчики, и наоборот. И если кто то пишет код который через месяц/два/10 лет он сам или кто то другой не сможет прочесть то надо делать две вещи:
-избавиться от такого кода
-избавиться от такого программиста

Насчет комментариев к функции. Самое сильное «искусство» это придумать такое название методу, чтобы не пришлось писать коммент к нему. Ибо в коде чаще будет встречаться вызов этого метода, и если программисту пришлось лезть в код этой функции чтобы понять что она делает это минус.
Я уже несколько лет не работаю в одиночку. Код который я пишу, тут же подхватывают другие разработчики, и наоборот.

Аналогичная ситуация и у меня, но только не несколько лет, а уже второй десяток лет.

И если кто то пишет код который через месяц/два/10 лет он сам или кто то другой не сможет прочесть...

И я, и мои разработчики прочтут и разберутся в ЛЮБОМ коде нашего проекта. Разобраться-то разберутся, только вопрос «За какое время?». Согласитесь, одно дело а) разобраться за 15 минут и совсем другое — б) потратить на тот же самый код пару дней. И то, и другое я запросто могу обеспечить своим коллегам (и они мне), если буду а) писать качественные комментарии или б) не писать их или, что чаще всего гораздо хуже, писать некачественные комментарии.

По своему опыту скажу: много комментариев — плохо, нет комментариев — тоже плохо. Без комментариев может обойтись только тривиальная программа вроде студенческой лабы. Когда проект в сотни тысяч строк кода, ведется более десятка лет и постоянно модифицируется, то без комментариев будет ОЧЕНЬ И ОЧЕНЬ хреново. Поэтому я крайне отрицательно отношусь к идее кода без комментариев. И своих новых разработчиков всегда постоянно натаскивал, учил писать комментарии правильно.
Поддерживаю. Качественные комментарии внутри методов никому не мешают, но при этом значительно ускоряют дальнейшую работу с кодом.
Надо учиться читать код, а не заниматься ерундой с комментариями. При всей моей нелюбви к Макконелу про комментарии он правильно написал.
Как-то Вы категорично слишком. Неужели и код кодека/архиватора будет без комментариев писать? Или хитрую оптимизацию проводить без указания что и зачем сделано?
UFO landed and left these words here
Вы только листинг и название статьи прочитали перед тем как писать комментарий?
В книге Роберта Мартина «Чистый код. Создание, анализ и рефакторинг» один из разделов посвящен правильному комментированию кода. В топике автора ничего нового я для себя не открыл — очевидные вещи.
тут нужны следующие комментарии неочевидных моментов, на мой взгляд:
1. что такое cin и почему он нигде не объявлен? можно предположить что это std::cin, однако, соответсвующий заголовок не включен, так что код просто не скомпилируется
2. в данном случае может быть не для всех очевидно, что оператор >> означает не битовый сдвиг, а чтение из потока
3. почему результат сложения двух переменных типа int сохраняется в переменную типа double
4. неочевидно, почему функция объявлена как возвращающая int, но ничего не возвращает
понятно, что опытному программисту все это кажется неочевидным, но новичку нет
Можно скопировать в комменты всю книгу «C++ для чайников»
1. Поправил.
2. Я думаю что в теме про комментарии это не суть важно, однако если кому будет непонятно, то вполне возможно он сможет воспользоваться поиском.
3. Поправил.
4. Поправил.
У МакКонела еще написано, что хорошо бы чтобы код был самодокументируемым, так как код пишется для человека, который будет его читать, а потом для машины.

Комментарии стоит писать к методам, классам и их API, а не описывать пятистастрочнуюю лапшу в методе main.
А еще, вроде, у МакКонела написано, что комментировать надо не то что делает код, а то для чего это делается. Потому как, что делает код и так будет ясно.
Еще я думаю, что преподаватель просто не знает/не помнит языка, на котором написана лаба и ему надо что-то типа псевдокода, чтобы видеть, что там не ахинея написана. Отсюда и требование такое.

В нормальной разработке, когда все участники знают язык профессионально, комментарии по структуре не нужны, а нужны, как выше указаны причины того или иного решения, ну и документация API для использования компонентов. Вы можете проследить это в продуктах c открытым кодом типа JDK, Spring'а, или того же JQuery (там правда документация API пишется отдельно).
Порою там и преподаватель, знающий язык профессионально, не разберется без комментариев!
Так надо учить детишек программировать нормально, а не спрашивать «где комментарии?». А то потом такие комментаторщики приходят писать за деньги, а потом другие удивляются «почему после института никуда не устроится junior разработчиком даже».
Сейчас почти в каждой школе есть компьютерный класс, где детишки учатся «программировать».
Я со своим классом ходил в специальный учебный комбинат, где нас действительно учили. А сейчас в моей школе информатику преподает библиотекарь!
А после такого переучивать сложно, если вообще возможно. Толковый студент после слов преподавателя о его неумении писать код пойдет читать и учиться, а не обижаться на «старого пердуна» и после окончания вуза, как вы правильно подметили, удивляться «почему после института никуда не устроится junior разработчиком даже».
Не знаю, думаю что в школе, не специализированной, не зачем преподавать программирование.

Для этого есть курсы/кружки, далее техникум (политехник), первые курсы бакалавриата, т.е. там куда человек пошел осознанно.
Школа неспециализированная, но отбирали очень интересно: сначала делили класс на две группы — кто силен в областях математики, физики и тех, кто силен в других областях. Потом в первой полугруппе проводили опрос — кто хочет заниматься по усиленной программе (расписывая все прелести и невзгоды, учитывая необходимость учиться и весь июнь). Итого это были 12 человек которым интересно учиться программировать. Именно учиться, а не зубрить, чтобы отмазаться. При этом программа у малой группы была такой же как и у остальных, но плюсом шло полтора года программирования + выпускная работа (информатика была 10-11 класс). И никто не верещал, что «мы не хотим весь июнь по будням пять часов в день сидеть учиться». Сидели и учились.
Вообще, на мой взгляд, вопрос «Когда надо начинать учить программированию?» заслуживает отдельной, очевидно холиварной, статьи.
Как показывает мой личный опыт, лучше всего комментарии удаются если писать их, отвечая не на вопрос «что тут происходит» а на вопрос «зачем это тут происходит». Соответственно, если ответ на вопрос «зачем?» очевиден по коду — комментарий не ставится. Если есть сомнения — не ставятся. Пример, по моему мнению, плохого комментария:

//  Проверяем что элемент не установлен
if( STATE_NOT_SET == item->state() )
{
  //  Устанавливаем начальное состояние
  item->setState( STATE_INITIAL );
}


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

//  Элемент может быть не установлен если к нему еще никто не обращался.
//  В таком случае считаем что это новый элемент и у него начальное состояние. 
if( STATE_NOT_SET == item->state() )
{
  item->setState( STATE_INITIAL );
}

Код в вашем примере должен говорить сам за себя, имхо в данном случае вам нужен метод с именем которое будет более говорящим чем конструкция STATE_NOT_SET == item->state(), например это может быть isNewElem()
Это как бы пример. Он написан из головы за десять секунд. Тратить полчаса на поиски идеального образца я не буду, но если вы готовы — можете поделиться :).
Я как бы о том, что заменой конструкции на что-то подобное item->isNewElem() вы избавляетесь от необходимости оставлять такого рода комментарий. И в большинстве случаев это будет применимо и к другим примерам.
А я бы всю эту конструкцию целиком вынес в отдельный метод
void initItemState(Item& item)
{
    if( STATE_NOT_SET == item.state() )
    {
        item.setState( STATE_INITIAL );
    }
}


И пусть в меня кинет камень тот, кто без комментариев не понимает что делает ф-ия initItemState()
Отличный пример неудачного названия. Надо заглядывать в код, чтобы понять не затрётся ли установленное состояние. А вот был бы в вызывающей функции текст:
// устанавливаем состояние my_item в начальное значение, если оно ещё не установлено
initItemState(my_item);

или:
initItemStateIfStateNotSet(my_item);

или вообще:
// устанавливаем состояние my_item в начальное значение, если оно ещё не установлено
initItemStateIfStateNotSet(my_item);

Как по мне так третий вариант понятнее всего.
это не неудачное название, это неудачный пример, в котором действительно нужны комментарии, но совершенно другого плана — надо ответить на вопрос «почему вообще возникла необходимость в таком методе?»
см комментарий ниже
Чем читать такой объём кода и комментариев лучше всё-таки просто написать
if( STATE_NOT_SET == item->state() )
{
item->setState( STATE_INITIAL );
}

Не надо делать простые вещи сложными.
Более отвратительного примера не найти. Начальное состояние должно в конструкторе объекта устанавливаться и если этого не происходит, то тогда действительно нужно писать комментарий, но другого рода — почему же вы не инициализируете состояние объекта в конструкторе, а за вас это должен сделать клиент. Наверное, у вас были веские причины…
Защита от дурного клиента, который переопределит мой конструктор и забудет установить состояние?
А почему вы считаете, что этот самый «дурной клиент» не забудет вызвать аж целый метод для инициализации?
Метод для инициализации вызову я в основном методе своего родительского класса.
Но вы же говорите о человеке, который наследуется от вашего класса. Почему вы так уверены, что он не переопределит ваш метод, в котором все так же забудет вызвать метод инициализации? Если я что-то не так понял, поправьте.
Если он переопределит мои конструктор и метод, то мой метод исключения не выдаст из-за того, что состояние не установлено, а со своим конструктором и методом он сам разберётся (и вообще непонятно, зачем он наследовался :) ).
Тогда я не понимаю в чем проблема, если клиент (кстати действительно, как писали ниже, это некорректное название) выкидывает исключение при неустановленном состоянии, то он его и выкинет если в конструкторе по какой либо причине это самое состояние не было инициализировано. Разве этого недостаточно, чтобы защититься от случайной ошибки? Любой клиент поймет, что что-то не так и будет искать ошибку.
Ситуация 1: Клиент берёт мою библиотеку, наследуется, переопределяет конструктор и метод, но забывает проинициализировать состояние и проверить его в своём методе- исключение выбрасывает его метод

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

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

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

Мне тоже больше по душе и в конструкторе я его проинициализирую. Но если нет уверенности, что это сделает каждый, кто будет использовать мой класс, то лучше, подстраховаться. Пользователям нельзя доверять :)
А каким образом вообще клиент может переопределить мой конструктор? (клиент — это тот, кто использует мой класс)
class Item
{
    Item() : _state(STATE_INITIAL){}
}

class Foo
{
    void UsingItemFunction()
    {
        Item item;
        //клиент использует item
    }
}
class MyItem
{
  function _constructor() {
    $this->_state = STATE_INITIAL;
  }
}

class ClientItem extends MyItem
{
  function _construct($state) {
    $this->_stat = $state; // опечатка КЛИЕНТА
  }
} 
А в третьей строчке моя :)
В смысле, вы хотите сказать, что компилятор не ругнется на такую опечатку? Даже варнинг не выдаст?
Ну тогда я даже не знаю что вам посоветовать, в с++ такое не скомпилируется. Если компилятор ПХП такое пропускает, то либо пишите внимательней, либо переходите на строго типизированные языки. Но мне кажется варнинг выпадет в любом случае, иначе вы бы с ума сошли от такого компилятора ))
Кстати да, php должен выдать notice «Undefined property». Но тут в другом проблема, в php если в дочернем классе переопределен конструктор и не вызван напрямую parent::__construct, то конструктор наследуемого класса не вызовется. Это если я не ошибаюсь конечно.
Варнинг, фатальная ошибка, исключение, а то и вообще ничего не будет (в зависимости от настроек и контекста) только при попытке использовать $this->_state в «правой» части выражений, например при исполнении (то есть когда реально передастся управление) в return $item->getState(); Вернее со свойством объекта фатальную ошибку мы всегда получим, а вот с простыми переменными можем узнать, когда сайт взломают Яндекс проиндексирует :)

Собственно поэтому в PHP (да и в других слаботипизированных динамических языках, афаик) лишняя, на взгляд сишников или джаверов, проверка на тип или значение аргументов в функциях (особенно в реализациях публичных API) быдлокодом не считается, насколько я могу судить :) — в лучшем случае перестраховкой («да эту функцию никто кроме тебя никогда не вызовет, да и IDE если что подскажет» — а потом вызывают, или я код набиваю в блокноте в vim). Да и автоматическое тестирование более актуально, т. к. тестирует не только логику, но и синтаксис.
Я не совсем понимаю что вы сейчас обсуждаете. Этот код был написан «из головы» за десять секунд. Он писался как «код к которому нужен комментарий». Это может быть что угодно, включая работу в внешней библиотекой заказчика.
Обсуждения имеют свойство уходить в сторону :)
Но моя мысль была такой, что реализация ф-ий в очень редких случаях требует комментариев. Комментировать нужно только прототипы ф-ий, описывая что делает ф-ия. Ну и модули/классы, описывая за что отвечает класс/модуль.
Но моя мысль была такой, что реализация ф-ий в очень редких случаях требует комментариев


«Требует» для чего? Чтобы скомпилировалось? Чтобы скомпилировалось комментарии не нужны. Чтобы любой понять мог? Гуру поймет любой код за минимальное время. Человек с медицинским синдромом дауна не поймет любой код за бесконечное время. Чтобы «сферический разработчик в вакууме» быстро разобрался? Это слишком сильно зависит от разработчика.

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

Вообщем я свое мнение как ИМХО высказал — как-то его аргументировать мне не интересно, это результат моих наблюдений за последние пятнадцать лет, из них десять как разработчика и пять как руководителя отдела разработки. Какие-либо обоснования тут потребуют слишком сложных выкладок из психологии, менеджмента и теории нейросетей — я не очень люблю обсуждать «философские» темы.
Ну далеко не во всех языках отделяется прототип (декларация) от реализации. Правда в некоторых есть соглашения, по которым комментарий к функции в целом (включая типы передаваемых параметров, возвращаемых значений, выбрасываемых исключений и т. п. — и в целях документирования, и в целях помощи IDE и статическим анализаторам) описываются перед функций, а комментарии к реализации уже в теле.
«Питер Гудлиф — Ремесло программиста. Практика написания хорошего кода»
В этой книге хорошо на эту тему написано.
Не читал. Спасибо за совет! На досуге освою.
У нас препод по С требовал удалять комменты, когда сдаешь домашки. При том я обычно делал домашку в начале семестра, а сдавать можно лишь в конце. И ты сидишь в конце семестра и стираешь свои «гениальные» комментарии :)
Код должен быть сам по себе комментарием
Наивно так полагать, когда реализуется что-нибудь достаточно сложное. Например, какие-то специальные вычисления. Лучше в комментариях написать номера страницы книги на которых представлено описание этих формул.
А если у меня будет другая книга, или новое издание, где формула описывается на других страницах? Или кто-то захочет использовать другую формулу для вычислений?
В таком случае лучше формулу писать в комментариях. Или если она носит чье-то имя — указывать название.
В таком случае, нужно правильно назвать метод в котором реализованы вычисления, и покрыть их тестами. Если это часть публичного Api, нужно написать doc comment для автоматической генерации документации. Вероятность того, что кто-то будет менять код реализующий вычисления из книги, при условии что тесты будут зелеными близка к 0.
… и потратив время на все вышеперечисленное полениться за 1 минуту написать комментарий, поясняющий что происходит внутри метода.
Коментарии не пишутся, не потому что лень, а потому что они не нужны никому. Don't repeat yourself.
Если комментарии дублируют код — значит это плохие комментарии. В более-менее нетривиальном коде всегда найдется, что написать по существую
Там, где не нужны никому, — там, может быть, и не пишутся.
Я вот сейчас представил гипотетическую ситуацию, что я заставил своих разработчиков удалить все комментарии из нашего проекта. Я больше чем уверен, что результатом будет то, что они начнут вести «двойную бухгалтерию» — один код для показа мне (я являюсь сборщиком проекта и одновременно его библиотекарем), а другой — для своей повседневной практической работы. Да и еще и обидятся на меня — зачем, мол, начальник, палки в колеса нам суешь?
Я ещё соглашусь — писать название в комментарии перед методом. А ещё лучше — описать класс.
И вообще слабо верю, что нельзя в метод заключить описание действия.

И да, своей фразой я не отрицаю необходимость комментариев.
UFO landed and left these words here
Всегда пользовался правилом писать комментарии ко всем классам и методам (включая приватные), а так же к блокам кода внутри метода, которые поясняют, что собственно происходит. Идея о том, что хороший код не нуждается в комментариях плохо работает при реализации алгоритмических задач. Как бы хорошо не назывались переменные и методы короткая фраза, написанная человеческим языком проясняет то, что делает код намного лучше. Не говоря уж о том, что код никогда не может объяснить, зачем он это делает. В этом плане очень ценны комментарии типа «оптимизируем структуру для уменьшения используемой памяти».
Как результат, коллеги считают мой код весьма простым и понятном, за счет чего вполне легко получалось отдавать поддержку своих модулей другим людям.
>Идея о том, что хороший код не нуждается в комментариях плохо работает при реализации алгоритмических задач
Это правда. Но алгоритмические задачи составляют очень маленький процент всего процесса программирования. Здесь проблема в том, что сложно понять алгоритм из кода из-за недостаточного уровня абстракции. Поэтому лучше полностью описать алгоритм отдельным комментарием, или дать ссылку на источник, если это известный алгоритм. А если человек разобрался с алгоритмом, то ему уже не нужны будут комментарии типа «оптимизируем структуру для уменьшения используемой памяти».
Опять споры о том с какой стороны разбивать яйцо.
Не скажите! Разобьете вы яйцо с одной стороны или с другой — разница несущественна. Разница по времени разбирательства в кодах с хорошими и плохими комментариями, по моим практическим наблюдениям на реальном проекте, может достигать двух порядков! А это, согласитесь, уже весьма и весьма существенно.
А вообще без комментариев? :)
Где-то между «плохо откомментированным» и «правильно откоментированным» вариантами, зависит от хитро*опости писавшего.
То есть лучше вообще без комментариев, чем с плохими, но лучше с хорошими, чем вообще без них. Так я и думал, осталось узнать какие комментарии у меня :)
Это плохо, но всё же лучше, чем когда комментарии есть, но они отвратительные.

Комментариями можно запутать, забить внимание, увести в ложную сторону («Ой, код я переписал, а комментарии от старого кода остались!»), заставить разгадывать головоломки и т.д. В итоге времени может понадобится даже больше, чем если бы комментариев вообще не было.
Я считаю, что комментарии должны быть только к методам, классам, модулям и т.п., но никак не к строкам кода.

Если имеется метод, внутри которого без комментариев не разобраться — его нужно рефакторить.
Абсолютная правда. И если реализация функции не влазит на экран, значит что-то тут не то, надо разбивать на дополнительные ф-ии. И намного важнее называть ф-ии, переменные и классы осмысленными именами, которые четко их описывают.
Если, конечно, речь идет про ООП…
Есть хорошо названный метод с единственной ответственностью на 200 строк. Так ли уж необходимо разбивать его на 20 по 10 строк с невнятными именами засоряющими нэймспейс, плюс писать простыню из 20 вызовов (сорри, эти 20 вызовов нужно разбить ещё на 2 по 10 строк с ещё более невнятными именами)?
Покажите этот метод. Никогда не видел «метод с единственной ответственностью на 200 строк», хочу посмотреть.
Реализация какой-нибудь восьмиэтажной математической формулы со знаками суммы, интегралов и т. п., например криптографической или решение задачи из учебника по дискретной математике. Какого-то смысла у отдельных частей нет (или до кодера его не довели), смысл есть у параметров и у результата «Вычисление хэша строки по алгоритму VolCh2048» или «Ответ задачи №247».
Извините, не встречал.
Если 8-ми этажная формула с интеграмали, то интеграл очевидно отдельная ф-ия. Если вычисление хэша, то скорее всего его можно разбить на подфункции. Это проще для восприятия, не требует комментариев, способствует повторному использованию кода. В целом я не вижу смысла спорить об этом, ни одна программа с хорошей архитектурой не имеет ф-ий на 200 строк. И я утверждаю, что ф-ии в 200 строк — плохая архитектура. Не соглашаетесь — наступайте дальше на грабли, и чаще пользуйтесь ctrl-c ctrl-v, я не буду настаивать. Думаю, что свое мнение я донес, можете еще обдумать если хотите, а не хотите — пишите как раньше.
Интеграл библиотечная функция.

Разбить можно, но нужно ли? Я же не о том, что писать формулу в 200 строк не разбивая на части и вычисляя по 10 раз какую-нибудь (a+b). Но мне кажется вариант
с = a + b;
d = a - b;

return c*d-c/d;


читабельней чем
с = sum(a, b);
d = sub(a, b);

return sub(mul(c, d), div(c, d));


даже если подобную ахинию продолжить ещё на 200 строк. А в этом примере копипаста я избежал без выделения в функции.
Ну вы начинаете утрировать. Кто ж будет писать ф-ии sum, sub, которые делают сложение/вычитание.
Если вы хотите дальше обсуждать эту тему, давайте это делать на реальных примерах, найдите ф-ию на 200 строк и я вам покажу как её разбить на ф-ии, чтоб это было более читабельно. Даже статью напишу специально для вас. Судя по количеству минусующих мои комментарии, такая статья будет полезна многим.
Если мне карму совсем не сольют, конечно. Дети какие-то, ей богу. Не согласны с точкой зрения — сразу минус в карму.
Разбить функцию в 200 строк на отдельные функции по 10-20 строк — это не проблема. Вопрос в другом — а всегда ли это надо? И всегда ли это удобно для сопровождения?

Расскажу на примере собственного опыта. Искать проблемы в последовательно выполняемом коде объемом N тысяч строк, разбитом на 50-60 процедур/функций/методов, гораздо тяжелее, чем если процедур будет всего 5-6. Вместо последовательного скольжения взглядом сверху-вниз приходится постоянно скакать вниз-вверх согласно дереву вызовов. Поэтому в таких случаях лучше плюнуть на всякие там правила и рекомендации и написать процедуру объемом несколько сот строк кода подряд. Что мы и делали.

Как говорится, из всякого правила есть исключения. Жизнь — она гораздо богаче учебников.
Вы здесь уже затрагиваете вопросы проектирования ПО. Пожалуй, вы знаете что есть объектно-ориентированная декомпозиция, структурная декомпозиция и другие. В целом не столь важно каким способом именно вы разделяете сложную структуру на более мелкие части, но вы всегда можете это сделать неудачно (или вообще не сделать) и получить функции в 200 строк или файлы по «N тысяч строк». Если у вас так получается, то стоит посмотреть с более высокого уровня абстракции на проблему и там уже разделять её на части. Вряд ли я одним комментарием смогу вам рассказать на тему по которой куча книг написано. И если у вас что-то не получается, то не факт, что «жизнь богаче учебников», возможно конкретно вы не можете справиться с этой сложностью — может не хватает знаний, опыта или талантов.
возможно конкретно вы не можете справиться с этой сложностью...
Такое ощущение, что вы вообще не читали мой пример. Где вы увидели, что у нас были проблемы с декомпозицией на коротенькие функции?
Мы СОЗНАТЕЛЬНО сделали антидекомпозицию, чтобы избежать негативный эффект, о котором я рассказал. Т.е. пошли даже дальше, чем вы можете себе представить, опираясь на чьи-то догмы. И цели своей достигли.
Я даже могу сказать, что было бы, если какой-нибудь начинающий программист, только что пришедший в нашу команду, опять бы разобрал тот код на 50-60 функций по 20 строк. Ребята за такое прибили бы его сразу. :)

В целом не столь важно каким способом именно вы разделяете сложную структуру на более мелкие части, но вы всегда можете это сделать неудачно (или вообще не сделать) и получить функции в 200 строк или файлы по «N тысяч строк».
С чего вы взяли, что мы сделали «неудачно», получив функции в несколько сотен строк? Наоборот, очень удачно, очень удобно и достигли желаемого нами эффекта — искать проблемы в том конкретном коде стало намного легче и удобнее. А вот какая конкретная польза была бы от вашей повторной декомпозиции в том конкретном случае — вы почему-то скромно умалчиваете, предпочитая отделываться лишь общими словами (проектирование, абстракции) да грязными, ничем необоснованными намеками («возможно конкретно вы не можете справиться с этой сложностью — может не хватает знаний, опыта или талантов»).
Если имеется метод, внутри которого без комментариев не разобраться — его нужно рефакторить.


А если в коде присутствует фикс к специфическому и малоизвестному багу операционки? Использование нетривиальных библиотек? Ветка кода для сложно corner case, который на первый взгляд непонятно когда происходит? Имплементация контринтуитивного требования заказчика? Сложная языковая конструкция? Во всех этих случаях тоже рефакторинг поможет?
Это частный случай, автор предлагает комментить каждую строку.
В смысле «автор»? Я как бы интересовался вашей позицией:
Я считаю, что комментарии должны быть только к методам, классам, модулям и т.п., но никак не к строкам кода


Если под «автором» вы имеет в виду автора поста, то я в упор не вижу в посте ни одного предложения комментить каждую строку. Уточните, где вы это увидели.
     // Принять от пользователя два числа
     // Завести переменную для результата сложения
     // Вернуть результат сложения


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

Комментарии в конечном коде должны использоваться исключительно для документирования.
Хмм… да, пожалуй вы правы, этот фрагмент я просмотрел. Тут, конечно, как-то совсем утрировано O_O.
Есть такое утверждение: пустая строка лучше любого комментария.
Ее смысл в том, что вставка пустой строки позволяет разбить код на смысловые куски, чем резко улучшает его понимание.
Согласен — очень эффективная штука для ориентации в коде. У нас активнейшим образом применяется. Более того — получила дальнейшее развитие. Где одна, а где 3 пустые строки — при скольжении взглядом по коду сразу бросается в глаза.
С TDD это, имхо, имеет мало общего. Вернее это дополняющие друг друга техники. Причём комментарии/псевдокод использую и в тестах, и в коде. Грубо говоря:
function calc($a, $b) {
  // возвращаем сумму параметров
  return $a + $b;
}

// проверяем, что calc складывает два числа
assertEqual(calc(2, 2) , 4)

Без комментариев не было бы ясно, например, то ли calc() складывает, то ли умножает, то ли в степень возводит.
Пример, конечно, натянутый, но, имхо, приём полезный, но, конечно, не исключающий нормальное именование методов.
Значете, можно называть ф-ию calc(), можно просто с(), а можно дать осмысленное имя add2Numbers(), например. Вы же пишете код для людей, а не для компьютера.
Осмысленные имена не панацея. Например,
$customers = array_merge(getAllCustomersFromSaintPetersbergInRussiaInLastYear(), getAllCustomersFromSaintPetersbergInRussiaInCurrentYear);

не лучший пример для подражания, по-моему.
И вправду не лучший пример для подражания.
По хорошему у вас вместо ф-ий повторяющих код getAllCustomersFromSaintPetersbergInRussiaInLastYear и getAllCustomersFromSaintPetersbergInRussiaInCurrentYear
будет одна ф-ия наподобие
getCustomers($city, $year); // я на ПХП не программирую, извините если неправильный синтаксис

Я бы вас на работу не взял :)
Так в этих двух функциях и вызывается getAllCustomersByCityIdAndYear(Cities::SAINT_PETERSBURG_RUSSIA, year(now())-1) и getAllCustomersByCityIdAndYear(Cities::SAINT_PETERSBURG_RUSSIA, year(now)) в 20 разных местах кода :)
Не имеет смысла писать в имени ф-ии ByCityIdAndYear, если ф-ия принимает в качестве аргументов CityId и Year. Тут и дятлу понятно, что это ByCityIdAndYear.
Или по вашему еще нужно комментарий написать «ф-ия getAllCustomersByCityIdAndYear возвращает всех кастомеров по ID города и году, переданных ей в качестве аргументов»?

А также не имеет смысла писать отдельную ф-ию getAllCustomersFromSaintPetersbergInRussiaInLastYear(). Это ничем не лучше записи
getCustomers(Cities::SAINT_PETERSBURG_RUSSIA, year(now())-1)
Функция должна в себе содержать какую-то логику, а не лишь бы была.
Хорошо подумали? А прототип будет какой? getCustomers(int, int), да? И кто здесь кто?
Чего мне думать, я так пишу уже много лет, никто не жаловался. Прототип будет
getCustomers(int cityId, int year);
Правда там enum в качестве cityId, но раз хотите int, пусть будет по вашему.
И вот в коде написано getCustomers(2009, CID_MOSCOW). Вы никогда сразу не поймёте, что это неправильно.
Не вижу смысла обсуждать плохое зрение у программистов и скорость нахождения багов из-за этого.
Для того, чтобы это понять нам нужно заглянуть в её исходники. По названию мы даже не можем определить сколько параметров принимает функция — или смотрим код функции, или получаем fatal error (частично аналог compile error, но может возникнуть в том числе и на продакшене). Плюс наличие функций с именами getAllCustomersByCityIdAndYear, getAllCustomersByCityId, getAllCustomersByCountryId и т. п. — фактически соглашение об именовании во многих фреймворках и ORM.
А зачем в названии методов слово All?
А не помню уже откуда пошло. :)
Мартина и Макконнелла вспомнили, а вот Фаулера пока не упоминали, вроде, хотя в его книге «Рефакторинг. Улучшение существующего кода» есть отдельная небольшая глава, посвященная «плохому душку комментариев».

Насчет метода «сначала описать алгоритм естественным языком, а после писать код», — я с этим не согласен хотя бы по той причине, что описание алгоритма с помощью естественного языка слишком избыточно по сравнению с любой мало-мальско формальной схемой (если это действительно необходимо для понимания перед началом программирования). Кроме того, не очень ясен следующий момент: если после описания всего алгоритма с помощью ЯП большую часть комментариев (скорее всего, все) нужно будет удалить… то что хотел преподаватель от студента?:)
Имел ввиду Мартина Роберта, автора «Чистый код».
this.put(theGun).to(your.head).then(function(){
this.pull(theTrigger);
},this);

Очень часто забываю писать в комментарии, иногда забываю написать их в простейших вещах которые вроде бы смысла ну никак нет описывать.
Через пару месяцев тупо смотрю на тот(совершенно примитивный) кусок и думаю — ПОЧЕМУ, как я мог такое написать.
После исправления кода в 90% случаях выясняется( вспоминается ) что было сделано все правильно.

не пишите что, не пишите как — любой нормальный кодер разберется.
Главный вопрос — нафига именно так.
Я бы даже сказал так. Не можешь написать комментарий до написания кода — значит, этот комментарий лишний.
Я бы не был столь категоричен. Не всегда всё идет гладко, иногда приходится уже во время написания кода обходить те или иные «овраги» (помните — «гладко было на бумаге, да забыли про овраги»?) и описывать их в комментариях, которые становятся вовсе не излишними, хотя до написания кода мы про них никак догадаться не могли.
Применимо к веб-разработке, нормальное именование переменных и методов и хорошая архитектура, в большинстве случаев, избавляет от необходимости комментировать код. Если бывает такой код, к которому хочется написать комментарии в духе «сейчас я постараюсь объяснить, что же делает эта не читаемая колбаса», то, в идеале, надо менять сам код.
В моем институте, реальный случай.

Преподаватель увидел, что переменные именуются i1,i2,i3 и сказал, что это непорядок, вы, пожалуйста, дайте переменным длинные мнемонические имена.

На что студент переименовал переменные так:
int dlinnoe_mnemonicheskoe_imja_1, dlinnoe_mnemonicheskoe_imja_2, dlinnoe_mnemonicheskoe_imja_3;
Sign up to leave a comment.

Articles