Однажды я где-то прочитал цитату, имевшую приблизительно следующий смысл:

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

Кажется, это заявление я прочитал в каком-то крупном СМИ. Статья называлась примерно так: «Опасайтесь плохого кода, он может вас убить; хотя постойте, он невидим, так что не стоит беспокоиться!». Весьма успокаивающее послание для читателей, как считаете? Сейчас я думаю, что авторы статьи просто пытались создать сенсацию из наличия таящегося «плохого кода» в авиалайнерах, поездах и беспилотных автомобилях, которых становится в нашем обществе всё больше, и таким образом увеличить количество просмотров.

Так как же объяснить концепцию «плохого кода» обывателю?


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

Для таких людей я представлю ответ на вопрос: «Если вы кодер, то чем вы занимаетесь?»

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

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

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

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

Создай мне устройство для поворота ручки!


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


Это и есть нужная нам система — ручка, поворачивающая другую ручку.

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


Одно победное очко плохому коду! Он прост и в нём меньше подвижных деталей!

Требуется изменение! Ручка будет перемещена в другое место!


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


Упс! Требование к продукту изменилось!

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


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

Изменение требований! Ручка должна поворачиваться медленнее!


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

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


Две вставки и рычаг смешной формы? Кто тебя будет поддерживать, плохой код?

Объяснение аналогии: ну и что с того?


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

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

Это правда, и вполне подходит для соло-кодинга и хобби-проектов. Одному богу известно, что я написал десятки тысяч строк плохого кода (в моём случае на ванильном JS), но это было нормально, потому что мне никогда не приходилось поддерживать этот код и добавлять в него что-то новое (зацените эти 2422 строки исходного кода www.python-gui-builder.com, одного из моих хобби-сайтов, написанного в 2020 году). Код работал и я его развернул, а потом никогда больше не возвращался к нему.

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

  1. «Вот устройство для поворачивания ручки, оно состоит из двух колёс и ремня», или
  2. «Это вставка для удерживания соединительного рычага, вот соединительный рычаг, его конец нужно вставить в небольшое отверстие здесь, в этой маленькой вставке...»

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

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


  1. markmariner
    26.04.2023 09:14
    +27

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

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

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


    1. Rio
      26.04.2023 09:14
      +3

      Так точно. Да и сами картинки здесь, как по мне, очень неудачные. После первой картинки можно было бы предположить, что далее потребовалось не сдвинуть ручку параллельным переносом, а, скажем, изменить её угол. И тут бах, и на первой картинке слева оказывается хороший код а справа - плохой.


      1. CrazyElf
        26.04.2023 09:14
        -1

        Да, картинки вообще ни о чём ((


      1. Linder666
        26.04.2023 09:14
        +1

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


    1. rescr1pt
      26.04.2023 09:14
      +1

      Так и есть, нельзя заранее предугадать в какую сторону может повернуться проект. Из-за излишней декомпозиции можно подорваться на "over-partitioning".


  1. BattleAngelAlita
    26.04.2023 09:14
    +2

    На кривошипно-шатунном механизме ДВС ездят уже больше 100 лет, так что претензии к нему немного натянуты.


  1. DenisPantushev
    26.04.2023 09:14
    +3

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

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

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

    Все не предусмотришь.

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

    НЕТ других решений.

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

    В ИТ для этого служат классы (солид, кстати, нарушает этот принцип) и на более крупном уровне - микросервисы.

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


  1. GarryC
    26.04.2023 09:14
    +2

    "Чем отличается врач от инженера? Врач убивает пациентов по одному."


  1. mafia8
    26.04.2023 09:14

    Когда пишешь о коде, есть одно правило: Нельзя использовать код. Можно использовать булочки и вилки, можно использовать трубы и тяжелые чугунные батареи, можно использовать всё что угодно. Но только не код.


  1. VladimirFarshatov
    26.04.2023 09:14
    +1

    Нда.. работала одно время моя жена оператором в Билайн .. по ее словам "хуже систем она не встречала в своей жизни". чтобы ответить звонящему надо было прошерстить несколько программ, и всё это в ограниченное время. Правка косяков - от нескольких дней. Каждый день рассылка новых фич, которые надо было заучить за первые 10 минут .. и всё это за копейки.

    Может что и изменилось, но судя по статье - сильно сомневаюсь.. ;)


  1. winmasta
    26.04.2023 09:14
    +2

    Добавление ремня сразу нарушает принцип YAGNI


  1. zodchiy
    26.04.2023 09:14

    Хороший код - он легко читается и легко модифицируется всей командой.

    Отличный код - он легко читается и модифицируется junior-ом.

    Идеальный код - он легко читается и понимается практически любым специалистом домена.


  1. rdp
    26.04.2023 09:14
    +1

    По логике автора ещё лучше создать сервис DKaaS (Door Knob as a Service) снабдив ручку всеми существующими сенсорами и дистанционным исполнительным механизмом для всех степеней свободы. А также настраиваемым преобразователем между ними с монетоприёмником и блек джеком.


  1. REPISOT
    26.04.2023 09:14

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

    Это неверно. Обязательная сертификация и тестирование есть. Например, КТ-178 для авиации. Другое дело, как это контролируется и кем. Не думаю, что в контролирующем органе сидят высококлассные программисты, которые проверяют код.