Не пишите комментарии к коду!

    Вступление


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

    Перед началом еще хочу сказать, что примеры буду приводить с использованием Java, а небольшой отрывок кода (с маленьким дополнением) взят из проекта описанного тут.

    Для понимания проблемы обратимся к Вики, а после перейдем к примерам:

    Коммента́рии — пояснения к исходному тексту программы, находящиеся непосредственно внутри комментируемого кода.


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



    public static void main(String[] args) throws IOException {
        // "ua.in.link.rest.server" - name of package with classes for Jersey server
        ResourceConfig rc = new PackagesResourceConfig("ua.in.link.rest.server");
        // creating httpServer for url "http://localhost:8080"
        HttpServer httpServer = GrizzlyServerFactory.createHttpServer("http://localhost:8080", rc);    
        InetSocketAddress socketAddres = httpServer.getAddress();    
        doSomethisWithSocket(socketAddres);        // waiting for Enter before stoping the server
        System.in.read();
        httpServer.stop();
    }
    


    Константы



    Давайте поглядим на данный пример. Начнем с таких строк:
        // "ua.in.link.rest.server" - name of package with classes for Jersey server
        ResourceConfig rc = new PackagesResourceConfig("ua.in.link.rest.server");
    

    Для человека, который не работал с локальным сервером Jersey, может быть действительно неочевидно, что за строка передается в конструкторе («ua.in.link.rest.server»). И автор, наверняка, хотел сделать данную часть более понятной. Однако, теперь, если по каким-либо причинам имя пакета в конструкторе будет изменено существует вероятность того, что комментарий останется старый, а, как известно, устаревший комментарий хуже отсутствующего. Более того, как уже говорил ранее, желание вставить комментарий в код свидетельствует (почти всегда) об проблемах с кодом. В данном примере думаю понятно, что проблемой является «захардкоденная» строка пакета(«ua.in.link.rest.server»). И если ее вынести в отдельную сущность, мы будем вынуждены именовать ее, для связки ее с данным кодом. Например, мы вынесли ее как константу:

    private static final String JERSEY_CLASSES_PACKAGE_NAME = "ua.in.link.rest.server";
     
    public static void main(String[] args) throws IOException {
        ResourceConfig rc = new PackagesResourceConfig(JERSEY_CLASSES_PACKAGE_NAME);
        // creating httpServer for url "http://localhost:8080"
        HttpServer httpServer = GrizzlyServerFactory.createHttpServer("http://localhost:8080", rc);    
        InetSocketAddress socketAddres = httpServer.getAddress();    
        doSomethisWithSocket(socketAddres);    
        // waiting for Enter before stoping the server
        System.in.read();
        httpServer.stop();
    }
    


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

    Разделяй и властвуй



    Идем далее… Обратим внимание на вот эти строки:

        // creating httpServer for url "http://localhost:8080"
        HttpServer httpServer = GrizzlyServerFactory.createHttpServer("http://localhost:8080", rc);    
        InetSocketAddress socketAddres = httpServer.getAddress();    
        doSomethisWithSocket(socketAddres);
    


    И тут комментарий наносит непоправимую пользу=). Вроде и так понятно, что делаю строки, комментарий дописан, так как метод в данном примере решает более чем одну задачу и нужно разграничить код, очень часто это делают комментариями, как тут. Что мы в итоге имеем. Допустим, что сервер стартует в каком-либо другом месте и из данного места старт сервера необходимо убрать. Нам нужно точно знать какой код отвечает за его старт. И вот проблема. Отвечает за старт только эта строка:

        HttpServer httpServer = GrizzlyServerFactory.createHttpServer("http://localhost:8080", rc);    
    


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

        HttpServer httpServer = GrizzlyServerFactory.createHttpServer("http://localhost:8080", rc);    
        InetSocketAddress socketAddres = httpServer.getAddress();    
        doSomethisWithSocket(socketAddres);
    


    Непонятно, какие строки необходимо убрать в случаи, если сервер запускается где-то на стороне. Более того, при модификации кода очень легко оставить строку:
        ResourceConfig rc = new PackagesResourceConfig(JERSEY_CLASSES_PACKAGE_NAME);
    

    Не заметив что она так же относится к блоку создания сервера.

    Давайте теперь отрефакторим данный код.

    private static final String JERSEY_CLASSES_PACKAGE_NAME = "ua.in.link.rest.server";
     
    private static final String SERVER_URL = "http://localhost:8080";
     
    public static void main(String[] args) throws IOException {    
        HttpServer httpServer = startServer();    
        
        InetSocketAddress socketAddres = httpServer.getAddress();    
        prepareSocket(socketAddres); 
        
        // waiting for Enter before stoping the server
        System.in.read();
        httpServer.stop();
    }
     
    private static HttpServer startServer() {
        ResourceConfig rc = new PackagesResourceConfig(JERSEY_CLASSES_PACKAGE_NAME);
        return GrizzlyServerFactory.createHttpServer(SERVER_URL, rc);    
    }
     
    private static void prepareSocket(InetSocketAddress socketAddres){
        doSomethisWithSocket(socketAddres);       
    }
    


    Теперь очевидно, что операции с Socket не касаются факта запуска сервера, иначе они бы выполнялись в методе старта сервера, как-то так:

    private static HttpServer startServer() {
        ResourceConfig rc = new PackagesResourceConfig(JERSEY_CLASSES_PACKAGE_NAME);
        HttpServer httpServer = GrizzlyServerFactory.createHttpServer(SERVER_URL, rc);    
        InetSocketAddress socketAddres = httpServer.getAddress();    
        prepareSocket(socketAddres); 
        return httpServer;
    }
    


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

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

    private static final String JERSEY_CLASSES_PACKAGE_NAME = "ua.in.link.rest.server";
     
    private static final String SERVER_URL = "http://localhost:8080";
    
    private static final String PRESS_ENTER__TO_STOP_STRING = "Press Enter to stop server";
     
    public static void main(String[] args) throws IOException {    
        HttpServer httpServer = startServer();    
        
        InetSocketAddress socketAddres = httpServer.getAddress();    
        prepareSocket(socketAddres); 
        
        userStopsServer(httpServer);
    }
     
    private static HttpServer startServer() {
        ResourceConfig rc = new PackagesResourceConfig(JERSEY_CLASSES_PACKAGE_NAME);
        return GrizzlyServerFactory.createHttpServer(SERVER_URL, rc);    
    }
     
    private static void prepareSocket(InetSocketAddress socketAddres){
        doSomethisWithSocket(socketAddres);       
    }
     
    private static void userStopsServer(HttpServer httpServer){
        System.out.println(PRESS_ENTER__TO_STOP_STRING + httpServer.toString());
        System.in.read();
        httpServer.stop();
    }
    


    А где нужны комментарии?



    Очень удачно по поводу тестов сказано в Вики, которую я и процитирую:

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


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

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

    JavaDoc



    Множество проектов, уже на пред-релизном этапе, изобилуют стандартными комментариями вида:
    /**
    * Имя или краткое описание объекта
    * 
    * Развернутое описание
    * 
    * @имя_дескриптора значение
    * @return тип_данных
    */
    


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

    Вместо выводов



    Само собой комментарии — это весьма холиварная тема. Много, кто может полезть в открытые проекты, которыми я заведую и, указав на какой -то код, сказать — «без комментариев он не очевиден» и будет абсолютно прав. Однако, если у меня будет время заняться этой частью кода, я потрачу это время на рефакторинг а не на написание комментариев, и лишь будучи загнан в угол и не придумав как применить принцип KISS, покорно напишу комментарий, но не ранее. Так же хочется сказать, что о комментариях часто напоминают молодые программисты, которым на самом деле банально не хватает практики, что бы увидеть в том или ином коде всем известный паттерн, подход или незнание работы каких-либо библиотек. Но это не проблема (и точно не необходимость) комментариев, а просто отсутствие должного опыта.
    Метки:
    Поделиться публикацией
    Комментарии 325
    • –14
      Ещё чего.
      • +23
        Пост не читай — комментарий к посту пиши? Зато вы первый, ага.
        • –19
          Пост читал. Не согласен. Комментарии нужны почти везде, кроме геттеров, сеттеров и getItemByID.
          • +13
            Зачем они нужны? Аргументируйте, пожалуйста, свои высказывания.
            • +11
              После таких вот XP техник без комментариев я потрачу до 5 раз больше времени на разбор действий кода, чем с комментариями. До 10% функций кода рискуют быть непонятыми вследствие их костыльности или неочевидности.
              • +5
                И это позволяет быстро локализовтаь эти 10% костыльных и не очивидных мест в коде, которыми необходимо занятся в первую очередь. Там и коментарий можно поставить с пометкой // TODO…
                • –17
                  Комментарии todo не нужны, поскольку их специально практически никто не do.
                  • +22
                    Не надо говорить за всех, пожалуйста.
                    Я, например, вообще предпочитаю сначала написать общую структуру программы в виде комментариев todo, а потом уже реализовывать. Какие-то todo остаются «на потом», конечно.
                    • +1
                      Я тоже так раньше делал, вот только потом понял что таким образом очень плохо контролируется что уже реализовано, а что случайно осталось «на потом». Намного лучше писать костяк будущего кода сразу вызовами несуществующих пока функций — таким образом сохраняется принцип «сначала написать общую структуру» и никогда не забудется написать что-то важное (код просто не скомпилируется).
                      • +1
                        Вот хочется, чтобы он скопиллировался;)

                        Критичные TODO можно написать так:
                        #error TODO! implement this feature
                        


                        Менее критичные так:
                        #warning TODO! implement this feature
                        


                        А совсем «на потом» так:
                        // TODO! implement this feature
                        
                        • –1
                          Если то, что Вы отметили как "#error" должно препятствовать компиляции — то какой смысл такое писать? Не лучше ли сразу написать вызов будущего метода — и меньше писанины, и задел на будущее.

                          По поводу "#warning" — согласен, до этого вполне могут дойти руки, потому что «надо сделать чтобы проект собирался без ворнингов!» — этим руководствуются многие.

                          А "// TODO" — полностью бесполезная вещь — забудете и не сделаете никогда (ну разве что ваша IDE эти штуки умеет собирать и показывать в одном месте — но даже в этом случае вряд ли до них дойдут руки).
                          • +1
                            >>Если то, что Вы отметили как "#error" должно препятствовать компиляции — то какой смысл такое писать?
                            Это может быть субъективно, но сознание более свободно, когда описываешь программу, а не пишешь ее, если Вы меня понимаете:) Это как на доске сначала нарисовать, а потом уже начать делать.
                      • +4
                        В моей среде разработки TODO и FIXME подсвечиваются особым цветом.
                        Для того чтобы не помнить о всех TODO есть специальная владка где задания разделены на проект, текущий файл и скоп:

                        image
                      • 0
                        www.rau.su/observer/N07_96/7_14.HTM

                        TL;DR: Если вы вместо TODO занимались чем-то другим, есть немалая вероятность, что это что-то другое оказалось важнее.
                        • 0
                          В проектах, которые я видел, метка todo являлась чем-то вроде overengineering-а. Так что что-то другое само собой оказывалось намного важнее.
                    • +18
                      Лучше называть методы нормально и код писать понятно, а тотальное комментирование приводит к наплевательскому отношению к их написанию.
                      В итоге получаем уродцев с автогенерированными комментариями типа

                      //Builds the Ext
                      public void BuildExt()

                      и так постоянно
                      Зато блин покрытие комментариями 100%, только это блин мусор. А натыкаясь на мусор перестаёшь видеть действительно стоящие комментарии.
                      • +10
                        Лучший комментарий — это тест.
                        • –1
                          Function InitClient(someArguments, &error=Null) {
                          //Логика работы: 1. Старт сокета, 2. соединение, 3. хендшейк
                          //Входящие параметры: тратата
                          //Возврат: Объект типа ClientConnection; Null в случае какой-то ошибки, error содержит описание ошибки
                          // 1. Старт сокета
                          Code Code Code
                          // 2. Соединение
                          Code Code Code
                          // 3. Хендшейк
                          Code Code Code
                          } //Конец InitClient

                          В таком случае я могу понять логику в 1 строке, пропуская весь код функции. Если всё грамотно сделано, то сокращает анализ кода
                          • +9
                            Сколько строчек кода в функции? Можно отрефакторить и вынести код в три метода с понятными названиями.
                            • +1
                              Иногда рефакторить вредно — когда операция идет на неявно связанных объектах единожды в программе, но при этом используется весьма много параметров, у вас получится еще большая каша.
                              А иногда просто функция сложная и состоит из этапов. Удобно вам иметь одну функцию, которая делает что надо и разбита по пунктам, или лучше иметь InitClient(Arg){return InitClient_Step3(InitClient_Step2(InitClient_Step1(Arg)))}
                              • +3
                                Мне второй вариант нравится больше, но разумеется не в таком виде.

                                Connection InitClient(args) {
                                    var socket = CreateSocket(args);
                                    var connection = CreateConnection(socket);
                                    connection.StartHandshake();
                                }


                                Хотя целесообразность наличия такого метода с именно такой функциональностью под вопросом, но для этого нужно контекст знать.
                                • +4
                                  А если вам надо ещё и ошибки обрабатывать? Ваш код превратится в nested hell. Такие случаи лучше разбивать на отдельные фунции и связывать через одну цепочку вызовов с Either. На Scala это будет как-то так
                                  def startServer(): Either[String, Server] = {
                                    for {
                                      conf <- loadConfig().right
                                      sever <- startServer(conf).right
                                      _ <- addListeners(server).right
                                      _ <- addHooks(server).right
                                      _ <- logServerSetup(server).right
                                      _ <- verifyServer(server).right
                                  } yield server
                                  


                                  А каждая из функций будет что-то типа
                                    def startServer(conf: ServerConfig) = {
                                     try {
                                        val server = new Server(conf)
                                        server.start()
                                        Right(server)
                                    } catch {
                                      case e: ServerException => Left("Failed to start server " + e)
                                    }
                                  


                                  При таком подходе чётко видно какие функции в каком порядке выполняются, каждая функция отвечает за одну задачу и ошибки удобно обрабатывать. Исполнение остановится на первой встреченной ошибке и вернёт сообщение об этом.
                                  • +5
                                    [off]«Какой кошмар ваш Scala»[/off]
                                    Именно по этой причине я и ввожу переменную по ссылке &error — для возврата ошибки
                                    • –1
                                      Э… то есть если сервер не стартовал, то приложение ругается в код, но продолжает доблестно работать?
                                      • 0
                                        Нет, если сервер не стартовал, то функции addListeners, addHooks и т.п. не запускаются вообще, а вызывающему возвращается ошибка в виде Left(error). Вызывающий уже обработает это, в соответствии с бизнес-логикой.

                                        Преимущество в том, что нормальный процесс весь в одном месте, а обработка ошибок вся в одном, но другом, месте. Примерно того же можно добиться бросая некрасивые исключения отовсюду и только ловя их в одном месте. Но это просто некрасиво.
                                    • +1
                                      Почему бы такие функции не вынести в объект?
                                      • +2
                                        Скажем так, в куче языков просто объект с функциями — весьма нетривиально и\или весьма нестандартно. Этим вы внесете еще большую путаницу. Ну а необходимость выделять под одноразовую «не-reusable» задачу класс — это известный холивар. Я сторонник не городить ООП там, где можно и проще обойтись функциональным программированием.

                                        В добавок, 99% моей текущей деятельности на PoSH, в котором весьма геморройно выглядят любые введения ООП от имени пользователя
                                        • 0
                                          Ну согласитесь, если набор функция оперирует множеством переменных, на 2-3 экрана, ее нужно разбить на методы. Потом оказывается, что эти функции будут работать каждая с 3+ переменными. Безусловно удобнее будет выделить подобное в класс, или переменные вынести в существующий класс.
                                          Это все, если конечно пишешь в ООП стиле, не процедурном
                                          • 0
                                            Полностью согласен, если язык предусматривает введение классов.
                                            Если же это скриптовый язык типа PoSH, то сама операция создания класса и его объекта вызовет лютый баттхерт, а коллеги не смогут прочитать код, так как введение класса в языке, который в большинстве своем используется для маленьих простых програм — очень редкое и невиданное явление
                              • +14
                                Видимо, вы никогда не разбирались в больших проектах. Встретить комментарий — большая радость, уменьшает количество работы и времени для добавления фичи ил правки бага.
                                • +1
                                  Мы говорим о комментировании кода. Нет никакой разницы большой проект или маленький, это уже вопрос проектирования.

                                  Ну а вообще, я только лишь хотел аргументированное мнение от Lamaster, он уже второй комментарий делает пустые заявления.
                                  • +10
                                    Оо да. На моём веку было много случаев, когда именно в больших проектах комментарии не соответствовали действительности. Потому что код изменился, а комментарий остался.

                                    Так что есть комментарий или нет — а в код смотреть надо. Особенно в больших и старых проектах.
                                    • +3
                                      Помню в большом проекте долго разбирался с куском кода, и увидел комментарий, уже обрадовался, как прочитал что там было написано: /* Refactoring this shit */
                                    • +1
                                      Ваше утверждение ничуть не потиворечит созержанию поста. Автор предлагает решение взамен комментариев, которое работает даже лучше них. Понятное дело, что если никто не трудился над понятностью и чистотой кода, то встретить хотя бы комментарий — это просто счастье. Вопрос в том, как писать код сейчас, чтобы при его поддержке не приходилось так же «радоваться».
                                  • 0
                                    Ну вот видите, прочитали пост и после этого написали комментарий по делу. Более того, я с вами даже в чем-то согласен. Сам стараюсь писать предельно понятный код(очевидные имена переменных, методов и классов, лаконичные методы, выполняющие одну задачу), но при этом стараюсь еще и дополнять код комментариями. Тем более, что пишу на C# и XML комментарии помогают при использовании методов из других классов.
                              • +4
                                Всеми руками за! Сам работаю с проектом (livestreet), для примера есть файлы, где на 110 строк только 20 строк кода. Поэтому работа начинается с удаления комментариев — тогда становится возможным читать код, а не комментарий что $sCurrentAction это переменная, которая хранит текущий экшн, и принимает строковые значения.
                                • +4
                                  Ну в публичных CMS это оправдано, тут уровень понимания пользователя может весьма варьироваться.
                                  • +2
                                    в публичных CMS есть документация. Не нужно запихивать её в файлы с кодом (пример комментария выше — реален).

                                    Серьёзно, я в первый раз столкнулся с Livestreet и обилие комментариев только мешает разбираться с кодом. Тем более большинство комментариев просто копирует название функций/переменных.
                                    • +7
                                      Не знаю как livestreet, но многие решения генерируют техническую документацию именно из комментариев к коду.

                                      Некоторые IDE могут сворачивать комментарии.
                                      • –2
                                        >>многие решения генерируют техническую документацию именно из комментариев к коду.
                                        И это очень плохо. В результате получается документация, которая «как бы есть».

                                        Свернуть комментарии — идея хорошая — но это доп действия ручками. к тому же всё равно остайтся как минимум забитая строка, на том месте. Это всё читаемость не улучшает.

                                        В результате, читать такой код, всё равно что читать книгу, где через каждую строчку серым шрифтом идёт пересказ выше сказанного.
                                        • 0
                                          >>многие решения генерируют техническую документацию именно из комментариев к коду.
                                          И это очень плохо. В результате получается документация, которая «как бы есть».


                                          С какого перепугу «как бы есть»? Если разработчик ленивый и не документировал как следует код — это его проблемы и проблемы его квалификации. Если уж смог написать прототип метода, потрать еще 2-3 минуты и напиши к нему коментарий, из которого сгенерируется документация. Эти коменарии и есть по сути написание документации.
                                          Плохой разработчик и код напишет, который «как бы есть».

                                          Вот вам пару примеров «как бы есть», AFNetworking, Facebook iOS SDK. Да вооще любая зрелая и уважающая себя open source библиотека для iOS подробно документирует в коде все свои API, чего уже говорить про код самой Apple.

                                          И понятие «читаемости» у вас какое-то специфическое, даже «забитая строка» ее ухудшает…
                                          • –6
                                            Обьясняю
                                            /**
                                            * Абстрактный класс экшена.
                                            *
                                            * От этого класса наследуются все экшены в движке.
                                            * Предоставляет базовые метода для работы с параметрами и шаблоном при запросе страницы в браузере.
                                            *
                                            * @package engine
                                            * since 1.0
                                            */
                                            abstract class Action extends LsObject {
                                            /**
                                            * Список зарегистрированных евентов
                                            *
                                            * var array
                                            */
                                            protected $aRegisterEvent=array();
                                            /**
                                            * Список параметров из URL
                                            * /action/event/param0/param1/../paramN/
                                            *
                                            * var array
                                            */
                                            protected $aParams=array();
                                            /**
                                            * Список совпадений по регулярному выражению для евента
                                            *
                                            * var array
                                            */
                                            protected $aParamsEventMatch=array('event'=>array(),'params'=>array());
                                            /**
                                            * Объект ядра
                                            *
                                            * var Engine|null
                                            */
                                            protected $oEngine=null;
                                            /**
                                            * Шаблон экшена
                                            * see SetTemplate
                                            * see SetTemplateAction
                                            *
                                            * var string|null
                                            */
                                            protected $sActionTemplate=null;
                                            /**
                                            * Дефолтный евент
                                            * see SetDefaultEvent
                                            *
                                            * var string|null
                                            */
                                            protected $sDefaultEvent=null;
                                            /**
                                            * Текущий евент
                                            *
                                            * var string|null
                                            */
                                            protected $sCurrentEvent=null;
                                            /**
                                            * Имя текущий евента
                                            * Позволяет именовать экшены на основе регулярных выражений
                                            *
                                            * var string|null
                                            */
                                            protected $sCurrentEventName=null;
                                            /**
                                            * Текущий экшен
                                            *
                                            * var null|string
                                            */
                                            protected $sCurrentAction=null;

                                            /**
                                            * Конструктор
                                            *
                                            * param Engine $oEngine Объект ядра
                                            * param string $sAction Название экшена
                                            */
                                            • +9
                                              Ну это явно написано под автокомплит любимой IDE разработчика или под генерирование документации, как я и говорил.

                                              Используйте IDE вроде PHPStorm и вы по-другому будете смотреть на такие комментарии(аннотации).
                                              • +3
                                                Поддерживаю. Раз. Два.

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

                                                Любой более-менее продвинутый текстовый редактор (sublime text 2, например), имеет кучу средств навигации по коду «в обход» этих коментариев.

                                                Могу только придумать одну ситуацию, когда это тяжело читать — в текстовом редакторе типа Notepad'а, без какой-либо подсветки синтаксиса, и когда код, по какой-то необъяснимой причине, нужно читать от корки до корки, как страницы в книге, как роман. Тогда да, ваши аргументы уместны.
                                              • 0
                                                Бедный хабрапользователи от икоты поди уже отчаялись. В следующий раз форматируйте код перед размещением в комментариях.
                                              • 0
                                                Эти библиотеки (AFNetworking, FB SDK) скорее комментируют свой API чтобы собрать из этого appledoc'и.
                                              • +5
                                                Свернуть комментарии — идея хорошая — но это доп действия ручками.
                                                Зачастую в IDE есть и автоматическое сворачивание регионов определённого типа.
                                      • +2
                                        Полностью согласен, лучше уделить время понятному коду.

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

                                        Так же насчет doc комментирования, его очень хорошо использовать в классах, которые по определению реюзабельны, эти комментарии подхватывают многие IDE и выдают понятный пользователю автокомплит.
                                        • +6
                                          Создавайте отдельную функцию на каждую неявную формулу/регулярное выражение. Это значительно улучшит понимание кода.

                                          Согласитесь, checkMail($mail) читается гараздо лучше, чем
                                          preg_match('/^([0-9a-zA-Z]([-.w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-w]*[0-9a-zA-Z].)+[a-zA-Z]{2,9})$/si', $subject, $regs)
                                          • +3
                                            Ну тут можно функцию то не городить. А сохранить сам регехп в переменную с именем checkMailRegExp и уже его проверить. А вообще регехп бы статической константой вынести глобально. Чтоб в проекте не было 10 разных валидаций. Я больше люблю разруливать такие вещи говорящими переменными нежели функциями. Если нужна будет какая то более сложная обработка то уже функция отдельная, опять же лучше в каком то паке утилов завести что консистентность проверок поддержать.
                                            • +1
                                              Можно и так — суть в том что можно обойтись без комментария.

                                              Единственная проблема в вашем решении в том, что если регекспа станет не хватать, то прийдётся во всём коде переделывать на функцию.
                                              • +2
                                                Да, и не так уж это и сложно. Я пришёл к выводу что бритва Оккама работает очень хорошо. Делать надо минимум. Если вы точно знаете что такая более сложная чем регехп обработка будет, то можно сразу функцию заводить. В противном случае нет. Не так уж и долго найти все ссылки на константу и во всех местах на функцию заменить, совсем не сложно. Зато не будет ненужных уровней абстракции. За последние пару лет разработки я понял что всего на перёд всё равно не предусмотришь, а в 10-15 местах заменить одно на другое не проблема, особенно когда ide рефакторинг хорошо поддерживает.
                                            • +2
                                              Это проблему решает лишь отчасти. Тут, имхо, нужен комментарий, указывающий как проверяется адрес почты и почему именно так. И если «как» кому-то может показаться избыточным (типа, ты что не впитал навык чтения PCRE с молоком матери?), то «почему так» тут явно напрашивается.
                                          • +6
                                            Вообще придерживаюсь принципа: комментируй как это сделано, а не что с.делано.
                                            Ещё недавно видел вот такую штуку и мне прям понравилось:
                                            if (equation > 0) { doSmth(); } else if (equation < 0) { doSmthElse(); } else { // комментарий о том что случай с равенством нулю не забыт, // обработка не требуется. }
                                            Сразу понятно что и как.

                                            //fallthrough всегда пишу когда применяю.
                                            Иногда вместо обновления приватной переменной изнутри класса дёргаю внешний сеттер, тогда тоже пишу коммент что сеттер дёрнут намеренно. Или геттер с ленивой инициализацией. Этидва случая конечно попахивают, но иногда для простоты и балланса между горой ненужного кода и простотой применяю.
                                            Т.е. если код может быть прочтён двояко, и может быть заподозрена ошибка то пишем коммент.

                                            А вообще с постом согласен, тупы хоменнтариев дублирующих написанное быть не должно.
                                            • 0
                                              Подождите, вы пишите код, которым описываете, как вы это сделали. А потом описываете в комментарии как это сделали?

                                              Серьезно, имя функции, переменных, класса, анотации — неужто этого не достаточно? Нет, было время, мне нравилось писать хитросделанные фунции и формулы, которые не с первого получаса поймёшь — но блин, мы же продукт делаем, а не заковыристостью кода хвастаемся!
                                              • 0
                                                Подождите, вы пишите код, которым описываете, как вы это сделали

                                                не понял мысли.
                                                Я пишу коммент если можно допустить небольшую некрасивость, но с одним комментом понятную, нежели городить новый уровень абстракции.

                                                Блин, тег code херню какую то делает. source надо использовать

                                                if (equation > 0) {
                                                	doSmth();
                                                } else if (equation < 0) {
                                                	doSmthElse();
                                                } else {
                                                	// комментарий о том что случай с равенством нулю не забыт,
                                                	// обработка не требуется.
                                                }
                                                • 0
                                                  >>Вообще придерживаюсь принципа: комментируй как это сделано, а не что с.делано.

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

                                                  К тому же очень часто такой комент должен звучать как
                                                  //Тут надо вроде ещё проверку сделать, но этот случай маловероятен, PM сказал забить.
                                                  • +1
                                                    //Тут надо вроде ещё проверку сделать, но этот случай маловероятен, PM сказал забить.
                                                    Вот такой зло как раз. У нас, слава всем богам, есть время разработчиков когда они выполняют поддержание кода и инструментов в порядке, и не отчитываются за это время ни перед кем. В такое время это и делается. А мой вариант показывает что не забыли это обработать. Он не маловероятен, он вполне вероятен, только действие не требуется. И не сразу это очевидно. Когда придумывал, думал что понадобится действие. Написал последний елс. Потом попробовал внести в один из ифов также равенство, тоже не круто. Вот и выделил отдельно. И всегда понятно будет почему так, и при чтении руки ни у кого не зачешутся поправить.
                                                    • –2
                                                      Ок, давайте рассмотрим

                                                      b = $('.someDiv');
                                                      if (b.html() == "")
                                                      b.html(«Привет»);

                                                      *тут код продолжается*
                                                      — Ваш вариант:
                                                      b = $('.someDiv');
                                                      if (b.html() == "")
                                                      b.html(«Привет»);
                                                      else {
                                                      /*тут ничего делать не надо, просто так конструкцию написал*/
                                                      }

                                                      *тут код продолжается*

                                                      Может быть лучше просто не писать конструкции, если их не нужно использовать?
                                                      Если же код неочевиден — то очевидно нужно его изменить.
                                                      • +5
                                                        Да пишите, кто же против то. Вам же код поддерживать. Я говорил о случае когда мы по некому условию разбиваем всё доступное пространство входных данный на некоторые большие области и их специфично обрабатываем. Классической ошибкой в таких штуках является потерять границы. И часто при дебаге и чтении кода на таких местах заостряется внимание. Тут просто сразу дана подсказка что это не ошибочно забыто а сознательно не обработано. Мне это помогает. И, если вы не заметили, не рекомендую всегда так писать. Но в некоторых местах такая штука бывает полезна. Мы код пишем чтоб писать его и поддерживать.
                                                        • –5
                                                          >>Мы код пишем чтоб писать его и поддерживать.
                                                          А мы — чтоб он работал :)

                                                          Если без шуток — каждый комментарий — это напоминание о том, что код попахивает (например — каждая область if содержит по сотне строк). И тут есть два пути:
                                                          1) оставить комментарий
                                                          2) исправить код

                                                          Естественно это всё не про анотации.
                                                          • +1
                                                            Вовсе не каждый. Как минимум комментарии нужны, чтобы объяснять почему выбран конкретный вариант в рамках предметной области. Скажем «используем ньютоновскую механику, релятивистскими эффектами можно пренебречь — это эмулятор морского корабля, а не космического :)» или «проверяем валидность мыла „интуитивно“, извращенцы, знающие RFC наизусть — не наша ЦА»
                                                            • 0
                                                              Вам не кажется, что в код стоит лезть с некой определённой целью? Скажем — определить откуда растут ноги у ошибки, провести рефакторинг и так далее. Т.е., грубо говоря «какую формулы мы выбрали» — должна рассказывать спецификация к проекту (юзер стори, сценарии поведения пользователя и так далее). А код — должен просто это реализовывать. Так зачем спецификацию запихивать в код?
                                                              • 0
                                                                Ошибка может быть из-за того, что релятивистские эффекты не учитываем или учитываем их криво. Вот чтобы разобраться в «или» нужна документация к коду.

                                                                И далеко не все проекты достаются с отдельной документацией, даже если она когда-то была. Зачем плодить сущности сверх необходимого, если можно документировать код прямо в коде комментариями?
                                                                • 0
                                                                  Потому что это:
                                                                  1) Экранирует принципы реализации от не-программистов (например от физиков и математиков, маркетологов и так далее)

                                                                  2) Мешает разбераться в коде (честно — я ту формулу не с первого раза пойму, даже если будет приписано что это за формула. Так что просто так копаться точно не буду)

                                                                  3) комментарий не изменяется вместе с кодом. Точнее должен — но часто о нём забывают. В результате Вы офигиваете от того, что релятивистские эффекты не учитываются на скоростях близких к С, потом офигиваете от того, что они таки учитываются (вопреки комментарию).
                                              • +3
                                                Жесть какая-то. Тогда надо к каждому IF писать ELSE с комментарием «не, я не забыл про этот случай — просто ничего не надо делать». Ну чтобы уже наверняка! А то мало ли кто заподозрит…
                                                • +8
                                                  Кому-то жесть, а кому-то… Согласен, что нужна «золотая середина».

                                                  Лично я не вижу ничего плохого прописать явно какую-то пустую или тупиковую ветку алгоритма с комментарием "//do nothing", чтобы потом вспомнить, что там действительно «nothing to do». Естественно, делать так повсеместно не призываю:)

                                                  Одно время я параноил и расставлял return без параметров в функциях, которые не должны ничего возвращать. Тем самым я подчеркивал, что функция действительно дописана, а я не просто отвлекся от кода и забыл дописать:). Сейчас от этого отошел, но это и есть — поиск «золотой середины»:)
                                                  • –2
                                                    В упор не понимаю зачем сама ветка ELSE существует. Самый нормальный способ — добавить юнит тест наподобие ifEquationIsZeroDoNothingBecause… Но если так и прет дописать комментарий, то можно сделать его перед первым IF. Сама ветка ELSE вообще ни к селу ни к городу. По поводу вашего return без параметров — вы просто набрались опыта и поняли, что это бесполезная практика. А другие разработчики, которые с вами работали, одобряли эту практику?
                                                    • +7
                                                      Я не понимаю, почему тесты так упорно противопоставляются комментариям в коде. Одно другому не мешает!

                                                      Что касается «избыточной ветки ELSE».

                                                      Case1. Программист дочитал до этого ELSE и подумал (как Вы, например) «нафига здесь эта пустую ничего не означающая ветка?» — это мысль на доли секунды, такой риторический вопрос, ответ на который дан в комментарии; код читается дальше с мимолетным ощущением собственной крутости «а я и так все понял бы, без этой тупиковой ветки!»:)

                                                      Case2. Программист в поисках ошибки добирается до IF и не видит обработки ветки ELSE. Задумывается, начинает смотреть, а что означает эта другая отсутствующая ветка с точки зрения входных данных, даже находит заботливо подготовленный старшим товарищем unit-тест, запустив который, убеждается, что зря параноил. 5 минут тоже не так много в масштабе вселенной, но… против долей секунды в Case1 — неприлично много.

                                                      Имхо,
                                                      тесты отвечают на вопрос «оно все еще работает?», а комментарии отвечают на вопрос «почему оно работает?».

                                                      Это лишь мое скромное мнение, сформированное за 20 лет программирования:)
                                                      • 0
                                                        Вы так увлеклись выдумыванием странных кейсов, что забыли про мой основной вопрос: «Зачем ветка ELSE, если комментарий можно поставить перед первым или последним IF?».

                                                        Почему оно работает вам должны говорить имена классов, переменных, методов и комментарии в том случае, когда вы не в силах выразить сложность задумки простым и понятным кодом.
                                                        • +1
                                                          Николай,
                                                          я не призываю в каждом случае фанатично ставить пустые ветки ELSE:)
                                                          На самом деле, наличие такой ветки больше вписываются в Ваше мировоззрение — все-таки «else {}» — это код, который «говорит сам за себя»;)
                                                          Я говорю лишь то, что не вижу ничего зазорного в том, чтобы использовать такую конструкцию, если по смыслу окружения могут закрасться сомнения — вот и все!

                                                          p.s. Я реально не вижу смысла в продолжении этой ветки дискуссии, чтобы не превращать обсуждение в балаган, что настойчиво пытаются сделать два товарища далее по тексту:). Предмета для спора просто нет:)
                                                          • 0
                                                            На самом деле действительно вставка ветки else выглядит несколько сомнительным приемом. Его хотя бы нужно было тоже закомментировать с фразой типа «вдруг когда нибудь придется обрабатывать и ноль». Информативность в плане того, что обработка ноля не баг, а фича не уменьшается, но эффективность кода может понизиться в некоторых трансляторах.
                                                  • +3
                                                    Не так. В коде из примера любой новый программист вначале будет считать, что он обнаружил ошибку («да тут же не обрабатывается случай, когда equation == 0 !»). Именно для этого и написан комментарий.
                                                    • +3
                                                      «Programs must be written for people to read, and only incidentally for machines to execute», воистину :)
                                                • 0
                                                  А во, ещё практика. Иногда я в коде закладки делаю своеобразные, // guid
                                                  И в отдельном файле что помечено какими гуидами. Удобно задумать например какой то рефакторинг, держать его в голове пару недель и расставлять в коде такие метки с местами которым стоит уделить внимание. Потом банальным поиском по проекту элементарно находится. Гуит у меня в ide одним хоткеем ставится.
                                                  Пришёл к выводу что это лучше чем всякие системы закладок на код. Потому что команда у нас работает с разными ide + элементарн работать с такими метками даже в блокноте, никогда не рассинхронизируются. В общем счастье одно.
                                                  • +2
                                                    На мой взгляд, комментарии как намерения обязательно должны присутствовать, в коде или в документации. Если их нет, то ошибочный код будет неотличим. Затем, идею прочитать легче в тексте, чем разбирать в не очень приспособленном для этого языке. Пример идеи: поставить перед текстом "#", если это hex-строка и реализация; что прочитать легче?
                                                    var color = $("#color").val().toUpperCase(), cL = color.length;
                                                    for(var i in cL)
                                                        if(cL[i] < '0' && cL[i] > 'F') //найден не hex-символ
                                                            break;
                                                    document.body.style.backgroundColor = (color.charAt[0] !='#' && i < cL ?'':'#') + color;
                                                    
                                                    • 0
                                                      Имхо в идеале- вынести в отдельный метод с соответствующим названием. А уже этот метод нормально прокомментировать.
                                                      Но суть в том что комментарии придётся читать только если нужно выяснить как он там работает, а не просто в момент когда встречаешь его вызов.
                                                      Т.е. что-то типа «PrepareColorValue»(название можно придумать и получше чем у меня), а что там внутри нужно будет смотреть только когда надо действительно разобраться что там такое
                                                      • +1
                                                        Вот видите, какую вы ужастную реализацию сделали, что её и понять то с первого раза сложно.
                                                        Вынесите код в функции, избавтесь от неочевидных конструкций типа color.charAt[0] !='#' && i < cL ?'':'#' и комментарии станут не нужны.

                                                        Самая большая проблема коментов в том, что после изменения кода — комментарии автоматически не меняются
                                                        • +5
                                                          if(cL[i] < '0' && cL[i] > 'F') //найден не hex-символ

                                                          Какой смешной код. Между '0' и 'F' ещё много чего находится.
                                                          • 0
                                                            Это и есть иллюстрация того, что идея описывается цельнее, чем код, который имеет допуски, которые в данном случае работают — нужно лишь отличать hex-коды от слов, в которых не встречается ни тех 7 знаков, ни многих других (если подробнее, то наличие ошибочного знака с тем же успехом не даст результата, что и отсутствие "#").
                                                          • +2
                                                            Правильное решение — вынести проверку в отдельный метод: скажем,
                                                            CharIsHexSymbol(c) {
                                                              return c > '0' && c < 'F';
                                                            }
                                                            

                                                            Код сам себя успешно комментирует, и это допустимо почти в любой ситуации. Ну все примеры, которые народ приводил, все поголовно используют комментарии там, где можно использовать инкапсуляцию.
                                                            Согласен, что иногда комментариев не избежать, но уж, имхо, точно не в случае с пустым ELSE. Тудухи — в тудухи, если вы на своих проектах забиваете на тудухи, то это проблема не тудух, а ваших проектов.
                                                            • 0
                                                              Хоть и плюсанул ваш коммент, но, имхо, тут всё же необходим комментарий, объясняющий почему столь странная (по крайней мере для ASCII-based кодировок) проверка выбрана. Зачастую комментарии служат лишь средством записи контракта (это понятие несколько шире чем сигнатура обычно). В данном случае либо в комментарии а-ля *doc напрашивается описание для функции типа «Argument MUST not to match to PCRE /[:-@]/» или «надеюсь, не найдется идиота, который в поле для ввода шестнадцатиричного числа будет набирать некоторые знаки препинания и прочей типографики» (типичный случай, почему у меня в коде присутсвуют комментарии на двух языках :( )для самой проверки. Во втором случае функцию можно было бы называть CharIsNeralytHexDigit, но опять же для понимания того, что значит «nearly» нужно будет в код заглядывать, а название CharIsBetween0AndF выглядит совсем тупо — типичный случай, когда код лучше инкапсуляции.

                                                              Или ещё пример, когда комментарии крайне желательны: Реализуем функцию сортировки. С точки зрения вызывающего кода всё равно как мы её реализуем, потому именуем её тупо sort(array) — что делает функция определено. Решаем реализовать её пузырьковым методом — как нам донести это для читателей кода без комментариев? Переименовать именно в «пузырьковую сортировку»? Так могут возникнуть мысли, что в использовании именно её есть некий сакральный смысл, что мы ограничены, скажем, в памяти, а не в процессоре. Оставить всё как есть? Так можем допустить ошибку в реализации и читающему код не будет понятно баг это или фича, а то он просто не опознает в ней именно пузырьковую.
                                                              • 0
                                                                Вы абсолютно правы, собственно, именно это и имел в виду Макконнелл, говоря про комментирование намерений. Но в данном топике народ старательно путает намерения и реализацию.

                                                                Что касается сортировки… Мне лично кажется, что если в ситуации допустимо использование нескольких сортировок, лучше воспользоваться каким-то паттерном, наподобие композита. Читающему код будет понятно, что в каждом конкретном вызове композитного сортировщика выполняется какая-то сортировка, а какая именно — будет отлично видно в названии класса-сортировщика.
                                                                В случае если мы вдруг при живом квиксорте решили воспользоваться пузырьком, конечно, комментарий следует написать, но именно как описание некоего магического знания: «Здесь мы проседаем по памяти». Потому как в противном случае (вместо названия писать суть в комментарии) придется писать комментарий на каждый вызов этой сортировки.
                                                          • +19
                                                            Канонический ответ: зависит от кода и области применения. Вот сейчас как раз читаю код коллеги — реализация некого анализа на основе normalized cross-correlation на CUDA. Даже с учетом того, что я знаю идею и формулы, сложно было бы уследить за извивами мысли без комментариев.

                                                            Если работаете с каким-либо мат.аппаратом, то лучше перебдеть.
                                                            • –1
                                                              Проблема черезмерного комментирования и написания все-в-одном методов очень свойственна, почему то, именно Инженерам, т.е. тем кто больше работает с мат. аппаратом а не реализацией. И часто такой код трудно поддерживать без рефакторинга, даже если он и неплохо документирован.
                                                              • +4
                                                                Ну декомпозицией кода в таких решениях, можно и навредить, я уже представляю класс из 300 методов или 300 классов по одному методу, как больше нравится.
                                                                • 0
                                                                  Ну, как говорится, сделай все максимально просто но не проще чем это возможно. Само собой я не говорю о тех вариантах где это навредит.
                                                                  • +3
                                                                    А мне когда то пришлось работать с функцией на 2500 строк. Поверте, лучше 300 отдельных методов.

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

                                                                      Нужно грамотно выдержать баланс между декомпозицией, реюзабельными методами и комментариями, но это уже дело немалого опыта.
                                                                      • +1
                                                                        Если код одноразовый, то грамотный компилятор соберет все «одноразовые» методы в одну функцию. Даже без явного inline.
                                                                        • 0
                                                                          выносить, скажем так, «одноразовый» код в отдельные методы так же не лучшая практика.


                                                                          Вы зря считаете что код выносится в методы только для уменьшения энтропии code duplication. Это лишь одна сторона, и я бы не сказал что главная. Большинство кода (по крайней мере в моей работе) — одноразовый. Но я неустанно бью код на мелкие методы (порой по 2-3 строчки) для поддержания некого layering'а в рамках класса. Методы уровнем повыше вызывают методы уровнем пониже. А мешать вызовы высокоуровневых методов с какой нибудь низкоуровневой арифметикой (хоть и относящейся к ответственности сего класса) — не комильфо. Мозг очень медленно при чтении таких методов меняет уровень абстракции. Приходится перечитывать по несколько раз. Лучше чтобы один метод имел один уровень.

                                                                  • +11
                                                                    Особенно полезны комментарии к математике в шейдерах или граф\физ движках: там ради оптимизации в пару тактов может так формула измениться, что саппортер глаза сломает, пока поймет по коду. Один только dot(a,a) вместо pow(length(a),2) чего стоит, и это далеко не сложный пример.
                                                                    • +6
                                                                      Аналогичная ситуация по коду на assember-е и некоторым скриптам на bash-e. Такой недокументированный код мы между собой называем write-only:)
                                                                      • +2
                                                                        Хмм, иногда целые языки программирования называют write-only… ;)
                                                                        • 0
                                                                          Но если вы сами работаете с ассемблером — то не проще ли научиться такой код читать? Хотя комментарии вроде «здесь мы используем флаг Carry, полученный 6 команд назад» вполне могут пригодиться: слишком большой риск, что при редактировании кто-нибудь его испортит.
                                                                          • +4
                                                                            Да что уж тут! Давайте запишем в корпоративных стандартах, что в команде программистов должны быть только гении, да чтоб еще и мысли друг друга могли читать через время и расстояние. И действительно, о чем мы тут спорим?:)

                                                                            С комментариями, опять же по моей практике и по моему скромному мнению, значительно больше шансов, что никто ничего не испортит:)
                                                                            • 0
                                                                              Недавно на Хабре был опрос. 16% сказали, что они могут быстро разобраться в любом чужом коде. Может быть, существование write-only языков, всё-таки, несколько преувеличено?

                                                                              А чтобы с комментариями никто ничего не испортил, тут уж точно надо уметь читать мысли — причём из будущего. Чтобы понять, что придёт в голову будущему редактору, что для него будет очевидным, а что — тоже очевидным, но при этом неправильным?
                                                                              Разве что комментарий типа «у этого блока вход такой-то, выход такой-то, меняет то-то, делает то-то, других побочных эффектов не имеет. Write-only, хотите изменить поведение — переписывайте заново». Если программа разбита на подобные блоки, то шансы, что её не испортят, слегка повышаются.
                                                                              • +2
                                                                                А чтобы с комментариями никто ничего не испортил, тут уж точно надо уметь читать мысли — причём из будущего. Чтобы понять, что придёт в голову будущему редактору, что для него будет очевидным, а что — тоже очевидным, но при этом неправильным?

                                                                                Решается путем чтения своих мыслей при написании кода :)
                                                                                • +1
                                                                                  Так мысли-то говорят, что вновь пришедшие программисты будут умнее нас — так что то, что очевидно мне, будет тем более очевидно и им. Зачем тогда комментарии?
                                                                                  • 0
                                                                                    Умнее-то они может и будут, но вот контекст совпадать совсем необязательно будет. Наверное, основная задача комментариев — это именно передача контекста. Что мы придумали видно и так в коде, но вот почему мы придумали именно так и что имели в виду на самом деле (чтобы читатель кода точно знал «это не баг, это фича») нужно документировать.
                                                                                    • 0
                                                                                      Тогда 80% комментариев к проекту должны жить вне кода, в большом документе сопровождения. Где перечисляются не классы с интерфейсами, а общие концепции и их взаимосвязи. Возможно, с указанием их отражения в архитектуре. Ведь это и есть контекст проекта. Только… кто ж его писать и поддерживать-то будет?
                                                                                      • 0
                                                                                        Вот комментарии и должны минимизировать необходимость такой документации :)
                                                                                        • 0
                                                                                          Я думаю, что наоборот :) Контекст — штука глобальная. Даже такие мелкие решения, как «захватывать/освобождать массивы каждый раз или повторно их использовать», не очень понятно, где описывать — их влияние может распространяться на несколько файлов. А в глобальном контексте местечко для описания найдётся сразу.
                                                                                          • 0
                                                                                            Извините, упустил слово «общие». А если контекст локальный? Вот выбрал я «пузырек» для сортировки — где не самое лучшее место как в самой реализации сортировки описать почему я его выбрал? Может я просто других методов не знаю, может минимизировал свои усилия, а может минимизировал потребление памяти.
                                                                        • +1
                                                                          За pow(length(a),2) — выгонять из проекта, пока не исправится. Выглядит оно заметно сложнее, чем dot(a,a), а выполняется в 10 раз дольше. Любой, кто работает с компьютерной геометрией, увидит и поймёт скаляный квадрат вектора, вообще не затрачивая усилий — это же идиома!
                                                                          А более сложный пример можете привести? Если можно, без комментариев :)
                                                                          • +3
                                                                            Никто в здравом уме и не пишет возведение в степень для квадрата, но ведь и руки не отвалятся если рядом с чем-то вроде dot(a,a) писать // length(a)^2, а лучше кончную цель вычисления или формулу.
                                                                            Вот простой пример с dot:
                                                                            n.z = sqrt(saturate(1.0f - dot(n.xy,n.xy)));

                                                                            Шейдерист по профилю с первого взгляда узнает восстановление третей компоненты tangent-space normal, но часто бывает, что код надо надо саппортить программисту более широкого профиля и простейший комментарий с формулой тут был пригодился.

                                                                            А вот пример показательного шейдерного кода без комментариев (© unigine):
                                                                            
                                                                            float4 q2 = q0 * (2.0f / dot(q0,q0));
                                                                            q0 *= scale;
                                                                            			
                                                                            float4 qq0 = q0 * q2 * 0.5f;
                                                                            float3 q0x = q0.xxx * q2.yzw;
                                                                            float3 q0y = q0.yyz * q2.zww;
                                                                            float3 q1x = q1.xxx * q2.wzy;
                                                                            float3 q1y = q1.yyy * q2.zwx;
                                                                            float3 q1z = q1.zzz * q2.yxw;
                                                                            float3 q1w = q1.www * q2.xyz;
                                                                            			
                                                                            float4 row_0 = float4(qq0.w + qq0.x - qq0.y - qq0.z,q0x.x - q0y.z,q0x.y + q0y.y,q1w.x + q1x.x - q1y.x + q1z.x);
                                                                            float4 row_1 = float4(q0x.x + q0y.z,qq0.w + qq0.y - qq0.x - qq0.z,q0y.x - q0x.z,q1w.y + q1x.y + q1y.y - q1z.y);
                                                                            float4 row_2 = float4(q0x.y - q0y.y,q0x.z + q0y.x,qq0.w + qq0.z - qq0.x - qq0.y,q1w.z - q1x.z + q1y.z + q1z.z);
                                                                            
                                                                            • 0
                                                                              Весело у вас :)
                                                                              Сначала, увидев .yzw, я подумал, что речь идёт о тензорах 4^3 (потом понял, что ошибся). Потом ещё надо было догадаться, что умножение покоординатное. В итоге получилось что-то вроде возведения в квадрат матрицы поворота на малый угол со сдвигом. Хотя, наверное, у этой формулы есть более строгий физический или геометрический смысл.
                                                                              • 0
                                                                                Конечно же я вырвал кусок кода из контекста, чтобы эффект был заметнее. =) На самом деле по имени файла, дефайнам и пр. видно, что это скиннинг с Dual Quaternions, q0 и q1 это кватернионы соседних двух костей, а row_* формируют результирующую Modelview матрицу для вертексов. Но, ей Богу, если будет подозрение на ошибку в этом месте, то головная боль обеспечена.
                                                                                P.S. К чести автора кода (тов. frustum из Unigine), он отлажен и работает идеально. Но все же пример показателен.
                                                                                • 0
                                                                                  Не похоже, чтобы q0 и q1 были независимы (что такое «соседние кости», я не знаю). q1 попадает только в столбец сдвига, а q0 явно отвечает за поворот… вычисляется матрица для чего-то вроде (q0*v+q1)*Inverse(q0). В первый раз такое вижу. Когда писал сам, то использовал q0*v*Inverse(q0)+VShift. Надо будет посмотреть, в чём преимущество ввода вектора сдвига под скобку. А то вдруг кватернионы снова понадобятся (в своём проекте я отказался от них лет семь назад, в пользу матриц).
                                                                              • +1
                                                                                А вообще, это интересный пример. Здесь самым полезным комментарием (после глобального — «преобразуем кватернионы в матрицу») будет как раз «что сделано», а не «как сделано» — явно расписанные формулы перед вычислением row_0, row_1, row_2. Тогда читатель сможет, во-первых, убедиться, что формулы соответствуют теории (а если не соответствуют — внести нужные изменения), а во-вторых — проследить, где какой член этой формулы вычисляется, и правильно ли он достаётся.
                                                                                • 0
                                                                                  В принципе, явно расписывать формулы не обязательно в подобных случаях, если они широко известны в узких кругах — достаточно ссылки (желательно и библиографической, и URI) на места, где их можно найти.
                                                                        • +9
                                                                          Процитирую Макконнелла:

                                                                          «Вопрос о том, стоит ли комментировать код, вполне обоснован. При плохом выполнении комментирование является пустой тратой времени и иногда причиняет вред. При грамотном применении комментирование полезно.
                                                                          Основная часть критически важной информации о программе должна содержаться в исходном коде. На протяжении жизни программы актуальности исходного кода уделяется больше внимания, чем актуальности любого другого ресурса, поэтому важную информацию полезно интегрировать в код.
                                                                          Хороший код сам является самой лучшей документацией. Если код настолько плох, что требует объемных комментариев, попытайтесь сначала улучшить его.
                                                                          Комментарии должны сообщать о коде что-то такое, чего он не может сообщить сам — на уровне резюме или уровне цели.
                                                                          Некоторые стили комментирования заставляют выполнять много нудной канцелярской работы. Используйте стиль, который было бы легко поддерживать»
                                                                          • +4
                                                                            Это всё хорошо, пока вы пользуетесь чем-то вроде блокнота или vi. В нормальных IDE комментарии вроде JavaDoc помогают избежать подглядывания в код вызываемых методов, а в случае с пхп и phpDoc и вовсе единственный способ дать IDE знать, какой тип у параметров и возвращаемых значений.
                                                                            • 0
                                                                              Если, конечно, вести речь о аннотациях перед телом метода|класса.
                                                                            • 0
                                                                              www.gunsmoker.ru/2010/07/blog-post_31.html
                                                                              Весьма похожая статья бородатых годов. Вы, случаем, не ею вдохновлялись?
                                                                              • 0
                                                                                Благодарю за ссылку. Ранее не поподалась на глаза =(
                                                                              • +8
                                                                                Допустим ситуация — кусок кода или какое-то хитросплетение методов и асинхронных колбеков, и вроде даже код написан с соблюдением всех правил, но очень тяжело понять. Или вы видите какой-то кусок кода, который на первый взгляд не нужен, но есть подозрение, что тут какой-то побочный эффект. И не нужно говорить «код говно», «код говно» это очень даже реальный случай, который нужно нередко поддерживать или рефакторить, но для начала нужно понять что хотел сделать автор.

                                                                                Так вот в такой ситуации, неужели не возникнет мысли «Автор, блин, мудила, не мог пару строк коментариев написать что ли! Без ста грамм не разобраться!»

                                                                                Коментарии нужны, хорошие коментарии нужны, не пишите больше статей с таким заголовком :)

                                                                                Ну а документация исходного кода — отдельная история.
                                                                                Пример iOS документация, сделанная с помощью коментариев в .h файлах и headerdoc. Ведь именно эта документация отображается в Xcode и на сайте iOS Developer. Или аналог headerdoc'а — appledoc. Яркие примеры проектов с такой документацией — AFNetworking и Facebook iOS SDK.

                                                                                Даже если вы пишите код для внутреннего проекта, рано или поздно в команду прийдут новые разработчики. Вы конечно можете сказать «иди читай код, он у нас говорящий», а можете снабдить все API подробной документацией (с помощью коментариев), как это принято в мире open source, да и не только.
                                                                                • +3
                                                                                  Код говорящий? — пусть новичок читает.
                                                                                  Код говорящий, новичок не умеет читать? — не умеющий читать тот язык, на котором пришел работать, не нужен проекту.
                                                                                  Код не говорящий? Переписываем код, потому что он говно.
                                                                                  Код не говорящий, но его переписать понятнее нельзя (потому как хитрая оправданная оптимизация, например) — тогда и начинаем думать о комментировании.

                                                                                  Выше цитата из Макконела где-то о том же.
                                                                                • +14
                                                                                  Автор поста, видимо, никогда не участвовал в больших проектах или не развивал один проект на протяжении длительного времени (пробовали возвращаться к своему коду через 10 лет? Не возникало вопроса «какой дурак это написал?»?)

                                                                                  Глубоко убежден, что комментарии необходимы. Особенно необходимы при написании интерфейсов (классов, библиотек). Огромный плюс, если комментарии стандартизированы, например, в формате doxygen.
                                                                                  • –4
                                                                                    >Не возникало вопроса «какой дурак это написал?»?)

                                                                                    Я думаю у любого программиста всегда возникает такой вопрос по поводу своего кода :), вне зависимости от комментариев, если у него есть профессиональный рост.

                                                                                    >Глубоко убежден, что комментарии необходимы. Особенно необходимы при написании интерфейсов (классов, библиотек). Огромный плюс, если комментарии стандартизированы, например, в формате doxygen.

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

                                                                                    Лично я не могу придумать такой пример где комментарий нельзя заменить на более грамотный код. (без крайностей конечно, для исключений нужно и действовать исключительно)
                                                                                    • +16
                                                                                      Практически любая оптимизация, когда проектное решение отличается от того, что 99% программистам приходит в голову сразу, требует документирования. Именно в комментарии нужно ответить на вопрос потомков: а почему он сделал так через задницу, а не просто и понятно в лоб? Предвосхитите этот вопрос и не портите себе карму в будущем:))
                                                                                      • –5
                                                                                        Может быть проще и правильнее предвосхитить этот вопрос тестом? Если вы знаете о какой-то ситуации, из-за которой код написат так как написан, то воспроизведите ее в тестах. Это не даст вашим «потомкам» на скорую руку поправить «якобы баг» в вашем творении. А если вы такую ситуацию не можете воспроизвести, то может быть и не стоит так код писать. Исключительно редко на моей практике попадались такие ситуации, в основном из-за дефектов во внешнем коде. Вот тогда комментарий с линкой на проблему очень даже полезен.
                                                                                        • +2
                                                                                          Я за тесты, также как и за комментарии! Надеюсь, Вы не считаете, что одно другому мешает?:)
                                                                                          • +2
                                                                                            А если вы такую ситуацию не можете воспроизвести, то может быть и не стоит так код писать.

                                                                                            Тесты прежде всего фиксируют поведение, но они не объясняют почему оно такое.
                                                                                            • +2
                                                                                              Это смотря как вы пишете тесты. Многие используют структуру тестов, которая полностью описывает как раз суть сценария, объясняя ПОЧЕМУ код должен себя так вести. Но естественно не описывают КАК это сделано в коде, то есть его структуру.
                                                                                              • 0
                                                                                                Для меня поведение кода — это его входы и выходы (включая побочные эффекты). А вот, например, сложности (как по «тактам», так и по памяти) в поведение не входит — это свойства поведения, но не его суть. Именования и тесты раскрывают суть, но не раскрывают свойства. В общем случае. Бывают, конечно, исключения типа «необходимо, чтобы на конкретной программно-аппаратной платформе время исполнения не превышало N микросекунд», но мы же не об этом говорим?
                                                                                        • +1
                                                                                          Но, насколько я понял, в данном топике обсуждаются именно комментарии к коду, а не аннотации, которые несомненно полезны.


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

                                                                                          А примеры могут быть.
                                                                                          Допустим приходится общаться с сервером, а у его архитектуры есть какая-то необычная особенность, вот есть и все, в силу каких-то архитектурных решений она там давно поселилась и никуда деваться не собирается.

                                                                                          Из-за этой особенности в коде клиента, приходится делать какой-то вызов, который трудно понять, как правильно и красиво ты его не реализуй.
                                                                                          Простой коментарий вроде «особенности архитектуры сервера, см. вики, страница такая-то» съэкономит массу времени и нервов.
                                                                                      • +1
                                                                                        Странно, что никто ещё не вспомнил про книгу «Чистый код». Про коментарии там написано достаточно подробно.
                                                                                        • 0
                                                                                          Ок, согласен код должен быть понятным, это просто без вариантов, но по моему в данном конкретном случае листинг увеличился раза в 3, эт норм?
                                                                                          • +9
                                                                                            Посмотрел петпрожект автора на гитхабе. Быдлокодер еще тот, еще других взялся учить.
                                                                                            • +3
                                                                                              Не согласен, он высказал проблему, которая совсем не однозначна, зато очевидна. Или давайте код всех кто за и против сравнивать.
                                                                                              • +4
                                                                                                Простите, а для того, чтобы поднять проблему и подтолкнуть к её обсуждению в комментариях — обязательно иметь 150 идеальных проектов на Гитхабе? По-моему, каждый имеет право инициировать дискуссию.
                                                                                              • +4
                                                                                                Я даже не представляю, как работал бы со многими Open Source проектам, если бы авторы не комментировали свой код.

                                                                                                Совет автора топика, по крайней мере, выглядит довольно странным.
                                                                                                • +1
                                                                                                  Может вы смешиваете, комментирование API и комментирование кода. Для многих open source проектов документация API (а не кода внутри) гораздо важнее самого кода, потому что это то, что они «продают» для конечного потребителя и оно должно выглядеть отлично. В принципе как и документация к сложному продукту. Вопрос же о комментариях внутри кода.
                                                                                                • –1
                                                                                                  Выносить поголовно единожды используемые переменные в константы… Зачем?
                                                                                                  Только засорять код. Они ведь нигде не используются, кроме как внутри метода. Если нужно получить доступ к быстрому их изменению, то достаточно объявить их в начале метода.
                                                                                                  • +5
                                                                                                    Константы следует выносить на видное место хотя бы ради того, чтобы подчеркнуть, что какая-то цифирь оказалась захардкожена в программу! А в комментарии необходимо указать, почему выбрано именно такое значение, какие значения возможны еще и как программа будет работать при установке этих других значений. Поверьте, это существенно облегчит жизнь Вашим последователям.
                                                                                                    • 0
                                                                                                      Справедливо.
                                                                                                      Однако в данном конкретном случае, разве это не очевидно?
                                                                                                      Вот, к примеру, я работаю над Meridian. Там все константы API для VK вынесены в отдельный класс, потому что другие значения там просто неприемлемы. А тут — обычный каркас, показанный скорее для разработчика, что не желает копаться в документации.
                                                                                                      Хотя, может я и не прав.
                                                                                                      • +2
                                                                                                        >> Однако в данном конкретном случае, разве это не очевидно?
                                                                                                        Предметом обсуждения, имхо, является не данный конкретный случай, все-таки, а общий подход.

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

                                                                                                        Также и «в данном конкретном случае». Если не задумываешься об этом на маленьких проектах, то в большие никто не пустит:)
                                                                                                  • +6
                                                                                                    Хвала Роберту Мартину и его книге «The Clean Coder: A Code of Conduct for Professional Programmers», втолковавшей мне, что комментарии должны содержать намерения кода. С тех пор, как я стал применять это простое правило, вникать в свои же собественные листинги стало куда проще.
                                                                                                  • +3
                                                                                                    На мой взгляд необходимость в комментариях серьезно зависит от языка и сути программы.
                                                                                                    Неоткомментированная логика на ассемблере и неоткомментированный UI на С# — все-таки разные вещи.
                                                                                                    • +2
                                                                                                      Старенький пост в тему: habrahabr.ru/post/97320/
                                                                                                      • 0
                                                                                                        Был простой понятный метод с комментариями, а вы развели на ровном месте кучу методов и констант, не решающих по сути ни одну из проблем с комментариями. Что касается устаревания — название константы, комментирующее её назначение, может устареть точно так же, как и комментарий. Что касается читаемости — грамотно прокомментированный код читается как книга, как техническая статья. Просто читаются комментарии и примерно обозреваются структурные конструкции в фоне. В то время, как код без комментариев вынуждает читать именно код, вникать во все подробности тогда, когда это может быть не нужно. А неоправданное разбиение кода на функции увеличивает время понимания кода тогда, когда ты реально хочешь разобраться до тонкостей, как работает код, привнося искусственные сущности, захламляя ими оперативную память мозга.

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

                                                                                                        • +2
                                                                                                          Почему не надо?
                                                                                                          Перечитайте еще раз на цитату Макконела orionll

                                                                                                          Константы, в отличие от комментариев — это код. Со всеми вытекающими. Это значит, что коду больше внимания. Это значит, что имя константы устаревает гораздо реже. Лично я вообще не помню, чтобы они устаревали, т.к. IDE прекрасно справляются по переименованию константы. Комментарии не компилируются. И не переименовываются во всех местах с помощью каких-то технических средств.

                                                                                                          Да и самое главное — язык программирования — это в первую очередь язык. Ваша задача — выразить замысел требований на языке программирования.
                                                                                                          Если код читается плохо, надо учиться что-то с кодом делать, чтобы он читался лучше. Код для программиста должен стать родным языком. Ни ЮМЛ, ни комментарии. С чего вдруг программисты когда-то решили, что комментарии так нужны? Похоже, что это были либо программисты, для которых язык программирования не родной, либо уже такой язык программирования, не позволяющий кратко/емко выражать мысли. Приходится мысли дублировать на естественном языке, разжевывая, что делает код, или даже цель/намерение кода.
                                                                                                          • +2
                                                                                                            Комментарии нужны хотя бы чтобы выразить замысел требований на естественном языке. Иначе человек, читающий код, не может быть уверен, что код их реализует.
                                                                                                            • –2
                                                                                                              Код надо (в идеале) писать так, чтобы он выражал требования. А не реализацию. И правильно писали, что вместо комментариев эти требования прекрасно выражаются еще и тестами, если кодом не удается.

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

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

                                                                                                              Всё это конечно спорно и требует чувства баланса. Языки программирования к сожалению не идеальны. Или я таких не знаю. Сила выражения мыслей на языке программирования зависит от языка, очевидно. Например, на Си, где нет эксепшинов, даже маленькое действие в методе превратится в много проверок и выходов. Но в С#, на котором сейчас работаю, действительно можно неплохо выразить мысль, без никаких дополнительных комментариев.
                                                                                                              • +2
                                                                                                                Во-первых, именно в идеале. Никто от ошибок не застрахован. Во-вторых, рука должна тянуться написать комментарий прежде всего, когда чувствуешь неочевидность данного подхода и/или возможные проблемы. В таких ситуациях комментарии должны быть аргументом принятого технического решения, передавать не только «что» и «как», но и «почему именно это и именно так».