«No pain, no gain», как гласит древняя восточная мудрость. И даже если мудрость не древняя и не восточная, лично для меня самый ценный жизненный опыт чаще всего был и самым болезненным. Недавний пост Дэвида Робинсона — аспиранта, занимающегося программированием в стенах Принстонского университета — посвященный код ревью, не только поднял важный вопрос повседневного быта каждого, кому волей (или неволей) приходится передавать свой опыт другим. Оригинальный текст был относительно «беззубым», однако, пост перестал быть томным после того, как в комментариях появился Джон Кармак.

Это история о плохом коде, который однажды написал ваш покорный слуга.

На одном из первых курсов университета я писал программу на Java, которая должна была читать файл весом в 6 MB в строку (этим файлом был геном бактерии в формате FASTA). Выглядел мой код следующим образом:

BufferedReader reader = new BufferedReader(new FileReader (file));
String line = null;
String text = "";

while( ( line = reader.readLine() ) != null ) {
    text = text + line;
}

Построение строки при помощи серии конкатенаций подобным образом крайне неэффективно — у меня, без преувеличения, уходило около 40 минут на чтение файла (с тех пор я узнал несколько способов получше). Самое главное — после чтения файла весь оставшийся алгоритм в программе отрабатывал секунд за 10. Два дня я так и работал: делал изменения в коде, запускал программу и успевал посмотреть целый эпизод LOST, прежде чем программа завершала выполнение. «Черт, на двенадцатой строчке ошибка! Опять все по-новой...»

После множества повторных запусков я наконец подумал «наверняка должен быть лучший способ сделать это». Я выяснил, что можно написать цикл на Perl, который сможет считать геном менее чем за одну секунду (при этом на Perl я умел программировать не лучше, чем на Java — просто повезло). Итак, я сел и написал скрипт на Perl, который читал файл, собирал его в одну строку и выводил ее. Затем я сделал так, что моя программа на Java вызывала скрипт на Perl через командную строку, захватывала вывод и сохраняла его в строку.

Если бы у меня сохранилась эта программа, то я бы напечатал ее исходный код и повесил в рамку на стену, чтобы почаще себе напоминать о том, что никогда и никого не буду ругать за написанный им «плохой» код.

Рассказать об этом случае из моей жизни меня вдохновил свежий комикс с XKCD про “качество кода”:

image

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

Проблема присутствует и в научных исследованиях. Есть много причин, по которым ученые публикуют свои статьи без прикладывания к ним кода (и они вполне объяснимы), но первую позицию в их списке обычно занимает смущение: «мой код слишком уродлив для того, чтобы отдавать его кому-то». Те, кто стремятся пристыдить других за код, в этом вопросе не слишком-то помогают!

Известный совет начинающим писателям гласит: «Каждый из нас держит в себе миллион плохих строк. Прежде, чем этот миллион выльется наружу, пытаться написать что-то хорошее бесполезно. Так идите и пишите!». Я вспомнил о нем, когда читал дискуссию, разгоревшуюся по поводу приведенного выше XKCD:

Когда вы, опытный программист, в следующий раз захотите пристыдить кого-нибудь за его код, попробуйте мысленно вернуться к собственному миллиону строк кода. Представьте, что кто-нибудь осудил вас так же, как и я себя выше. Продолжили бы вы просить о помощи? Осилили бы вы свою дорогу в миллион строк?

Комментарий Джона Кармака


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

Предоставленные сами себе, большинство людей демонстрирует непробиваемую способность игнорировать свои недостатки, и это вредит их профессиональному росту. Небольшой стыд часто становится позитивной мотивацией. Мне стыдно за огромное количество из того кода, что я написал за последний год. У меня в голове есть мысли насчет причин, почему все получилось так, как получилось, — некоторые из них представляют собой оправдания, но часть из них — это чистой воды «WTF я думал вообще, когда писал это?». И если вы не чувствуете небольшой вины за ваши последние работы, то, вполне возможно, вам будет полезно, если кто-то укажет вам на проблемы — в том плане, что этот человек сможет пробиться сквозь ваши «защитные механизмы».

Я был бы счастлив, если бы кто-нибудь «зарылся» во весь тот код, что я написал для Oculus Mobile SDK. Уверен, что по большей части этим читателем рано или поздно стану я сам, и по большей части буду только кивать головой и соглашаться с написанным; однако, я уверен, что смогу вынести из этого что-то полезное, и это благотворно повлияет на мою дальнейшую работу.

>> Вы в Oculus делаете код ревью для каждого коммита?

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

>> Ваш комментарий к статье выглядит так, будто макака прокатилась по клавиатуре, а вы потом только прошлись для виду автокорректом… ну как, прозвучало не слишком уж полезно, правда? Думаю, что вы путаете излишнюю жесткость с серьезной критикой. Заметили, что моя последняя фраза не такая обидная, и в то же время принесла толку больше, чем первая?

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

>> Делали ли вы ревью кода, написанного другими разработчиками в id в прошлом?

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

Пусть Джон и признается, что отчасти не сторонится в жизни строгих комментариев, ему далеко до Линуса Торвальдса, щедро пересыпающего свои письма личными оскорблениями, а выступления — фразами в духе «Меня не интересуете вы, я беспокоюсь о технологии и ядре — вот что для меня действительно важно» и утверждениями, что «никто не услышит вас, если вы собираетесь быть мягким».

Комментарии (50)


  1. StrangerInRed
    29.04.2015 13:08
    +5

    С радостью бы что-нибудь поревьюил в свободное время. Это и опыт для себя и взгляд со стороны. Чем круты opensource проекты — можно научится чему нибудь, или помочь кому нибудь, найдя баг.


    1. EngineerSpock
      29.04.2015 16:56
      +1

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


    1. lany
      29.04.2015 17:51

      С радостью бы что-нибудь поревьюил в свободное время

      Так к чему это «бы»? Что-то мешает? :-)


      1. StrangerInRed
        29.04.2015 19:22

        Не, ну я лажу по исходникам на гитхабе, когда есть время. Но так чтобы кто-то просил посмотреть, обычно никто не просит :)



    1. Myshov
      29.04.2015 19:31

      У neovim'а есть пункт, связанный с ревью кода.


  1. boolivar
    29.04.2015 13:23
    +19

    А меня прям бесит когда мой код ревьюжат те, чей код недалеко ушел от говнокода. И критика вида: че-та методов многовато и где джавадоки??


    1. mapron
      29.04.2015 23:51
      +5

      Меня как-то ревьюил опытный коллега, который у нас не работает уже. После этого я к ревью не обращался.
      -Много двойных пробельных строк;
      -Не отбиты пробелами вызовы функций;
      -Не все методы с Doxygen комменнтами;
      -Названия классов видите ли надо с литеры C начинать, а то вроде как непонятно где класс а где метод (у меня подсветка кода, мне все понятно).

      Я спросил его «ну а архитектура-то как?» он «ну я хз, я не понял как оно работает. вроде норм.»


      1. ncix
        30.04.2015 00:17
        +1

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


      1. MacIn
        30.04.2015 02:03
        +2

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


      1. fetis26
        03.05.2015 15:18
        +1

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


        1. mapron
          04.05.2015 21:16
          +2

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


  1. VokaMut
    29.04.2015 13:33
    +2

    Через год-два после того, как я начал учить язык php я понял, что хочется посмотреть как пишут другие. И я полез на киберфорум и стал помогать новичкам решать их проблемы, мысленно критиковал код и наматывал на ус.


    1. valergrad
      29.04.2015 16:53
      +11

      Я знал, я знал! Что критикой занимаются те, кто сами ничего не знают :)


  1. n0ne
    29.04.2015 13:59
    +17

    Знаете, иногда уже фиг с той красотой кода, понять бы, что это такое я написал год назад…


    1. StrangerInRed
      29.04.2015 14:01
      +12

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


      1. n0ne
        29.04.2015 17:36
        +19

        ОК, пойду почитаю, что за комментарии такие.


        1. Muxto
          29.04.2015 17:42
          +12

          Кажется, Макконнелл о чем-то таком упоминал…
          Вечно эти академические теоретики что-то выдумают.


      1. burjui
        01.05.2015 17:41
        +1

        Прежде, чем задаться целью писать комментарии, советую прочитать «Чистый код» Роберта Мартина (aka Uncle Bob).


    1. zloddey
      29.04.2015 14:29
      +8

      Тут вот такая загогулина получается, что код обычно делается «красивым» не для того, чтобы от взгляда на него получать эстетическое наслаждение, а чтобы его было проще читать и понимать. Возможно, само слово «красивый» наводит на ложные ассоциации? Попробуйте подставить вместо него слово «читаемый» — и тогда сразу же появится смысл.


      1. n0ne
        29.04.2015 15:59
        +8

        Видите ли, когда я открываю конспект по «вышке» от первого курса, а это 93й год, то я впадаю в ступор от того, какой я тогда был умный, если понимал всё это.
        Бывает откроешь свой файл, ну вот все переменные понятно называются, методы, классы, всё понятно, но «угадал все буквы, но не смог назвать слово»: ничего не понятно, что, куда, откуда и почему… пока не проследишь, что откуда берётся, пока примерно не восстановишь ход своих _тех_ мыслей, не всегда бывает легко разобраться даже в собственном коде.


        1. Flammar
          29.04.2015 18:53

          Чаще бывает нужно восстановить ход не всех _тех_ мыслей, а только их части. Тогда «красота» кода, в смысле разбиения на блоки, хорошо помогает.


          1. khim
            29.04.2015 20:55

            У меня нет в мыслях «разбиения на блоки», уж извините. Я вот сейчас регулярно комментирую изменения, которые в носятся в один модуль созданный мною 4 года назад. Понять тот ужас, который там сейчас имеется я могу с большим трудом, но я ведь всегда могу взять свою оригинальную версию с функциями длиной по 200 строк (не преувеличение… их там, правда, не так много) и поиграться с ней. Ну а потом, уже зная что и где нужно менять я могу и придумать как завернуть всё в ту версию, которая там сейчас используется (на это обычно уходит несколько больше времени, чем на первичное решение проблемы, но так как решение я уже знаю, то это не так страшно).

            Зато «красиво»: убрана дубликация кода (как будто эти 100 строк копипаста могли кого-то убить), есть куча комментариев и тестов и т.д. и т.п. Ну и? Кому и зачем всё это было нужно? До сих пор не знаю…


            1. MacIn
              30.04.2015 02:05

              Чтобы понять мог другой человек.


            1. justaguest
              30.04.2015 07:22
              +1

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


              1. khim
                30.04.2015 08:03

                Мимо. Там были две идентичные функции для работы с двумя архитектурами. То, что в них могут быть идентичные ошибки и что в большинстве случаев их нужно править одновременно — как бы самоочевидно. Зато каждая из них была достаточно проста и было понятно что в них происходит. Сейчас же та же логика размазана по двум десяткам функций и для того, чтобы всё это не разъехалось пришлось написать не один десяток тестов. Где, понятно, тоже могут быть ошибки. Притом что за четыре года ни одной ошибки, которая могла бы проявиться на практике, в исходном коде не было найдено, а в «улучшенном» кода такие ошибки были — не могу сказать, что я прям в восторге от проделанной работы.

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


  1. oberon87
    29.04.2015 15:56
    +2

    Все подобные красивые и правильные рассуждения страдают от недостатка метрик и формальных определений. И это помимо всяких метрик сложности по памяти, по времени исполнения и т.д.

    Куча разных критериев, удобство сопровождения, понятность для коллег по code review. Что такое читаемость, что такое наглядность, что такое выразительность? Какие-то субъективные критерии, которые легли на девственно чистый участок коры головного мозга авторитетного автора, пока он работал на первой быдлокодерской работе. Как всегда недостаточно весомые критерии для публичных рассуждений.

    Кто-то пытается выехать на актуальных трендах, типа, stream вместо foreach, как раньше выезжали на foreach вместо while. Кто-то считает строки. Кто-то ветвления считает. Кто-то просто выдумывает красивые и звонкие мемы и аллегории, как на картинке.

    В итоге все превращается в выяснение истины методом голосования.


    1. nuald
      29.04.2015 17:15
      +4

      К сожалению, даже метрики и формальные определения не всегда помогают. Вот, например, один из самых больных для обсуждения требование к стилю — длина строк не должна превышать 80 символов. Несмотря на то, что есть логические предпочтения для этого, абсолютное большинство голосуют против этого: «мы же не в каменном веке терминалов!!!» А то, что:

      • вообще-то с терминалами до сих приходиться работать (SSH в AWS/другие облака),
      • code review для длинных строк кода очень тяжело делать (потому что в основном это side-by-side comparison),
      • некоторые разработчики предпочитают другие layout-ы на экранах — например, иметь консоль с логами от watcher-а (gradle watch, grunt etc) или в целом просто tail -f логами рядом с редактором кода

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

      P.S. Хотел бы отметить один момент с layout-ами — многие возражают, что сейчас у всех много (2+) мониторов на работе. Тем не менее, современная практика разработки программного обеспечения (не уверен насчет России) включает в себя WFH (Work From Home), и дома у большинства нет лишних мониторов. WFH становится более и более популярным потому что это снижает риск эпидемий на работе (болеешь, можешь сидеть дома и работать, тем самым не теряя зарплату) и современные технологии практически исключили требования иметь всех под боком в любой момент времени.


      1. lany
        29.04.2015 17:54
        +1

        Про 80 символов — сильно зависит от языка. В той же Java бывают имена классов по 30 символов. Если ограничивать по 80 в таких условиях (учитывая ещё отступы по 4 пробела), код начинает выглядеть откровенно уродливо. На перле 80 символов — вполне адекватно.


        1. nuald
          29.04.2015 18:25
          +2

          Естественно, не зря современный стандарт — 80/120 (и ситуация намного хуже для конфигураций, где, например, в том-же JSON-е из-за отсутствия многострочных литералов приходится иногда писать очень длинные строки). Я больше ссылался на разработчиков, которые имея возможность писать короткие строки, тем не менее пишут код длиной до 2800 символов в строке (реальный пример, я сам не мог долго поверить своим глазам и все попытки убедить, что так делать не надо, уперлись в каменную стену фанатичности: «я — snowflake, что хочу то ворочу, и никто мне не указ»).


          1. ingumsky
            30.04.2015 02:24
            +3

            2800 в одной строке?! А чем автор кода мотивировал своё решение? У него вместо монитора бегущая строка?


        1. ncix
          30.04.2015 00:19
          +3

          КстатиИменаСущностейПоСтопицотСимволов — это тоже плохой стиль, я считаю.


          1. MacIn
            30.04.2015 02:07
            +4

            Лучше, чем КИСПСС().


            1. grossws
              30.04.2015 02:51
              +2

              Кроме, пожалуй, случаев устоявшихся аббревиатур в предметной области.

              Какой-нибудь SVMTrainData/SvmTrainData выглядит лучше, чем SupportVectorMachineTrainData.


          1. skvot
            30.04.2015 12:19
            +1

            А как же говорящие имена, самодокументирующийся код и т.д.?


            1. ncix
              30.04.2015 14:20

              Лаконичность никто не отменял. Краткость — сестра таланта.


    1. fetis26
      03.05.2015 15:26

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


      1. khim
        03.05.2015 18:15

        То есть если Вася умеет реализовывать сложные математические алгоритмы, но не умеет обрабатывать сложные структуры данных, а Петя успешно обрабатывает сложные форматы данных, но у него плохо с математикой, то в коде не должно быть ни сложных структур данных, ни сложной математики? Ну и куда вы зайдёте с таким «идеалом»?


        1. fetis26
          03.05.2015 20:00

          Речь о code style. А не о методологиях решения проблем.


      1. oberon87
        03.05.2015 20:44

        А в попугаях это сколько?


        1. fetis26
          03.05.2015 22:35

          38 попугаев, конечно же.


  1. ScratchBoom
    29.04.2015 16:31
    +2

    Так вот всё время твердит, что java тормозит.


  1. JIghtuse
    29.04.2015 17:58
    +1

    Пусть Джон и признается, что отчасти не сторонится в жизни строгих комментариев, ему далеко до Линуса Торвальдса

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


  1. dyadyaSerezha
    29.04.2015 20:05
    -22

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

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


    1. dyadyaSerezha
      30.04.2015 19:33
      -4

      Забавно, что ни один из минусующих не возразил: «нет, вот конкретно у нас была такая крутая девушка-программист». То есть, минусуют за сам факт, потому он неприятен? Ну заминусуйте еще за факт, что 99% научных открытий (проверить легко по статистике Нобелевских лауреатов) совершается мужчинами и что 99% детей рожается женщинами. Ну про 99%, это я политкорректно написал. В-)


      1. saluev
        01.05.2015 10:22
        +6

        Ну я даже не знаю, погуглите Мариссу Мейер там, или Аду Лавлейс для начала. А минусуют вас за то, что вы сексизм разводите на ровном месте.


  1. justaguest
    29.04.2015 21:17
    +3

    Мой первый — и длительный — серьезный опыт в программировании выглядел похожим образом, разве что ждать приходилось не сорок минут. У меня была программа на С++, написанная в С стиле, с использованием void указателей вместо темлейтов (что я аргументировал, фактом наличия таких указателей в функциях стандартной библиотеки С, а темплейты слишком ужасно выглядят).
    Чтобы найти только одну ошибку, которую я бы мог обнаружить, если бы умел правильно писать код, мне приходилось готовый бинарник переложить в определенную директорию, переключиться на терминал, подключенный к устройству, откуда командой «tftp -gr file $IP» скачать файл, затем не забыть дать ему исполняемые права, затем переместить в другую директорию на замену старого приложения, затем убить старое приложение, затем подождать некоторое время, пока его перезапустит демон, затем на ПК в клиентской части приложения сделать еще несколько пассов, и получить сегфолт. Затем проделать часть манипуляций, связанных с запуском gdbserver, и подключением к нему, снова воспроизвести сегфолт, и, наконец, заняться изучением причин.
    Но чаще всего сегфолта не возникало, а просто что-то работало неправильно, и все нудные манипуляции приходилось повторять полдня, чтобы только найти одну проблему.

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


    1. burjui
      01.05.2015 17:48
      +1

      Haskell нужно изучить ещё и ради функциональщины. Недавно с удивлением обнаружил, что коллега не знаком с функциональным программированием. Парадигма не является «серебряной пулей», но очень мощна, особенно в обработке коллекций.


  1. ivlis
    30.04.2015 05:04

    В науке это нормальное дело. У меня была программа на python, которая запускала программу на C++, которая читала вывод из Maple и потом передавала данные назад, а программа на python строила график. Даже если бы я к статье приложил этот код, не думаю чтобы он кому-то помог :)


  1. Mixim333
    30.04.2015 16:37

    Мне кажется, что автор абсолютно прав, а вот это: «Каждый из нас держит в себе миллион плохих строк. Прежде, чем этот миллион выльется наружу, пытаться написать что-то хорошее бесполезно. Так идите и пишите!» вообще бесспорно. Для меня, написание кода аналогично написанию стихов поэтом и лично мне дает огромное, если хотите, вдохновение, когда код, на который ты потратил свое время не только решает быстро сложную задачу, но и легко читается даже через год.