Привет Хабр! Предлагаю вашему вниманию свободный перевод статьи «Good code is its own best documentation» от Amit Shekhar.

image

Хороший код, как хорошая шутка — не требует объяснений.

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

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

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

Хороший код похож на хорошо написанный учебник


  • Прост и понятен
  • Удобно разбит на главы, каждая из которых посвящена четко определенной теме

Плохой код похож на плохо написанный учебник


  • Все главы ссылаются друг на друга, и непонятно, о чем вообще идет речь
  • Снова и снова рассказывается об одном и том же, причем причин для этого нет
  • Автор упоминает несколько исключений из правил, при этом часто противоречит сам себе
  • Внезапно появляется вампир! Он искрится на солнце

Вот о чем важно не забывать, если хотите написать хороший код:


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

Проверка качества кода


Покажите ваш код другому программисту, который его еще не видел, и пусть он попробует объяснить, что выполняет каждый модуль, а вы внимательно слушайте.

Чем больше вам хочется перебить и объяснить по-своему, тем, скорее всего, хуже ваш код.

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

Признаки хорошего кода:


  • Он выглядит умным, но не заумным
  • Вы можете вернуться к написанию кода после выходных, и сразу приступить к работе без переосмысливания написанного
  • Алгоритмы оптимальны по скорости и по удобочитаемости
  • Классы, переменные и функции названы так, что не нужно напрягать мозг, чтобы понять, зачем они нужны
  • Каждый из ваших классов предназначен для одной, ясно выраженной цели, и отделен от других классов
  • Ваши методы короткие – в идеале короче 50 строк, и уж точно не больше 100
  • Методы предназначены для выполнения одной задачи
  • Названия методов однозначно определяют то, что они делают, и вам не нужно смотреть на код внутри этого метода
  • Если нужно вернуться и добавить/модифицировать какую-нибудь функцию, это не должно вызывать затруднений
  • Ваши try/catch блоки малы настолько, насколько это возможно
  • Unit-тесты пишутся легко и без особых усилий

Хороший код является модульным


Допустим, в вашем проекте есть три слоя — внутренний, средний и внешний.

Ваш внутренний слой не должен ничего знать о вашем среднем или внешнем слое. Ваш средний слой не должен ничего знать о вашем внешнем слое.

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

Подробнее об этом читайте в этой статье (Ссылка переводчика)

“Хороший код — наша лучшая документация” — Steve McConnell

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


  1. AstarothAst
    11.08.2017 11:19
    +6

    Статья состоящая из капитанства на 102%.


    1. i360u
      11.08.2017 11:34
      -1

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


      1. franzose
        11.08.2017 12:03
        +1

        Просто на эту тему уже столько всего говорено, а по факту все решается практикой. Больше практики, больше понимания того, как лучше, а как хуже. Даже мой комментарий вышел немного капитанским)


        1. velkonost Автор
          11.08.2017 13:39

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


    1. velkonost Автор
      11.08.2017 13:42
      -1

      Статья состоящая из капитанства на 102%.

      Именно так. Эти правила давно известны в кругах программистов.
      Я перевел и опубликовал эту статью по 2 причинам:

      1. Здесь собраны общие правила, понятные даже ребенку сравнения, предостережения по тому, как не переусердствовать. Оригинал показался мне самодостаточным и самым полным из тех, что попадались моему глазу.

      2. Данная статья нацелена на начинающих программистов, которые могут использовать ее как памятку в своих первых проектах.


    1. serg_p
      11.08.2017 22:51
      +1

      Согласен. Добавлю — Хорошая архитектура, а не хороший код. Для меня статья просто чушь, как то так.


  1. AlexZaharow
    11.08.2017 11:56
    +6

    Самодокументируемость кода — миф. Всегда нужно знать не что код делает, а зачем он это делает. Но сам код никогда вам об этом не расскажет.


    1. ShamanR
      11.08.2017 11:59
      +1

      Еще как расскажет — deleteItemFromBasket(id).
      Верхние слои в названиях содержат части бизнес-логики, нижние — части работы с обезличенными действиями.


      1. SirEdvin
        11.08.2017 12:26
        +6

        Ну отлично. А что за Basket? Почему из него надо удалять предметы? Это актуально, или согласно новыми требования уже такого делать нельзя, а этот код просто остался для совместимости, а на самом деле он не удаляет, а помечает удаленным?


        1. franzose
          11.08.2017 12:29

          Если бы товар помечался, как удаленный, то и метод бы назывался markAsDeleted или как-то так.


          1. SirEdvin
            11.08.2017 12:31

            А если вот сначала оно удалялось, а потом в середине проекта получилось так, что нужно было поменять логику на помечать как удаленный?
            Менять название метода везде? А потом выяснится, что у вас так же были еще интеграции, которые расчитывали на этот метод, и поэтому вам нужно, что бы название точно осталось.


            1. ShamanR
              11.08.2017 12:37

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


            1. i360u
              11.08.2017 12:37
              +1

              А доки как-то отвечают на все эти ваши "если"? Если вам во всех этих случаях требуется искать ответ в доках, разбираться почему старые названия методов не соответсвуют текущим реалиям — у вас полный бардак в проекте и все плохо спроектировано.


              1. SirEdvin
                11.08.2017 12:40
                +1

                Нижнеуровневые доки нет, а верхнеуровневые почти на все.


            1. franzose
              11.08.2017 12:39

              Менять название метода везде?

              На это есть средства рефакторинга.


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

              Возможно, необходимо изначально как-то предусмотреть это?


              1. SirEdvin
                11.08.2017 12:40
                +2

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


                1. igorch96
                  11.08.2017 15:12
                  -1

                  Да и в водопаде невозможно все предусмотреть, поэтому на смену ему пришел RUP.


        1. ShamanR
          11.08.2017 12:33
          +2

          >А что за Basket
          Поидее если идёт работа над каким-то проектом то бизнес-сущности все знают. Иначе в каждом методе в котором есть слово баскет нужно писать а что это за баскет такой.
          >Почему из него надо удалять предметы?
          Потому что нужно такое действие, удаление.
          >совместимость
          Если произошла рассинхронизация после рефакторингов и изменения логики, то точно так же могли забыть поменять и комментарий к коду. А вообще, ради совместимости вносить изменения в метод, чтобы он делал не то что он обязан делать это странно. Проще и правильнее создать новый метод, который назвать markDeleted или что-то в этом роде.
          Мой поинт в том что если скурпулёзно подходить к рефакторингу при изменениях, то всё будет понятно и без документации.


          1. SirEdvin
            11.08.2017 12:40

            Мой поинт в том что если скурпулёзно подходить к рефакторингу при изменениях, то всё будет понятно и без документации.

            Поидее если идёт работа над каким-то проектом то бизнес-сущности все знают. Иначе в каждом методе в котором есть слово баскет нужно писать а что это за баскет такой.

            А где будут описаны бизнес-сущности? В коде? И так же бизнес-условия?


            1. franzose
              11.08.2017 12:44
              +1

              Да.


              1. SirEdvin
                11.08.2017 12:45

                То есть вы вместо того, что бы собрать их в одной доке, предлагаете всем заинтересованным (среди которых не только программисты) искать их по разным файлам в коде?


                1. franzose
                  11.08.2017 12:54
                  +1

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


                  Плохому коду даже проектная документация, собранная в одном месте не поможет. Потому что вы в доках вы будете читать одно, а смотря на код вы будете видеть невесть что и думать, что же тут происходит-то?


                  1. Delmond
                    12.08.2017 09:23

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


                    1. franzose
                      12.08.2017 14:46

                      Внутренний проект компании и open source библиотека — это всё-таки разные вещи.


            1. ShamanR
              11.08.2017 12:45
              +2

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


        1. marshinov
          13.08.2017 12:22

          Это Cart вероятнее всего, а не Basket:)


      1. dom1n1k
        11.08.2017 13:30

        Расскажет в очевидных/стандартных/распространенных случаях, но они таковы ведь далеко не всегда.


    1. franzose
      11.08.2017 12:06
      +2

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


      1. maxru
        11.08.2017 13:29

        Предложите своё решение, заменяющее тупые геттеры/сеттеры, пожалуйста.


        1. franzose
          11.08.2017 13:44
          +1

          Ну, например, использование конструктора для передачи зависимостей. Адекватное название всяких «статусных» методов.


          Например, вместо publication.setStatus(1) или publication.setStatus(publication.published) сделать publication.publish(), publication.unpublish() и так далее.


          1. maxru
            14.08.2017 14:27

            А у вас количество зависимостей, которые необходимы для инициализации объекта, всегда совпадает с количеством сеттеров?


            1. franzose
              14.08.2017 14:34

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


  1. SirEdvin
    11.08.2017 12:25
    +5

    Тут есть две проблемы:


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

    Если вы в контексте проекта, то для вас почти любой будет читаем. А так будете страдать.


    1. Free_ze
      11.08.2017 14:49
      +5

      Мир пользователя API и программиста нутрянки очень сильно отличается. API нужно документироваь, нутрянку — нежелательно (в топике об этом). Если пользователю приходится лезть внутрь библиотеки, то у нее плохая документация.


  1. KvendyZ
    11.08.2017 12:39
    +2

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


  1. plastilinko
    11.08.2017 13:24
    +2

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


  1. maxru
    11.08.2017 13:28
    -1

    Индусский кэп


  1. olegarch
    11.08.2017 21:23

    > Хороший код, как хорошая шутка — не требует объяснений
    .
    Что с хорошо написанным кодом работать проще и удобнее — очевидно. Но утверждение, что любой хороший код не требует обьяснений — это попытка на основе частного утверждения (I) посторить общее (A). В общем случае это не верно.
    Бывает такой код, что и хороший, и ничего не понятно без обьяснений (или документации). Чтоб далеко не ходить — приведу в качестве примера процедуру поиска минимальной редактирующей последовательности или арифметический кодировщик.


  1. GrafDL
    12.08.2017 06:50
    -1

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