Вредные советы: зачем нужен неподдерживаемый код и как его писать

Неподдерживаемый код: как создавать и зачем он нужен

Мы решили собрать несколько советов по написанию неподдерживаемого кода.

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

Более того, внимательно следуя этим правилам, разработчик сохранит и своё рабочее место — все будут бояться eго сложного кода и бежать от него.

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

Нарушайтe соглашeния

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

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

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

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

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

Результат после использования wrap — два элемента, один из которых вложен в другой:

Добавим к скрипту следующую строчку: div.append('</span>');. Как вы думаете, что произойдёт? </span> добавится в конец div, сразу после img? Ничего подобного! Искусный ниндзя уже нанёс свой удар и поведение кода стало неправильным.

Как правило, методы jQuery работают с элементами, которые им переданы, но не в данном случае. Вызов img.wrap(div) клонирует div и оборачивает вокруг img уже озлобленную суррогатную копию клон. Исходная переменная при этом не меняется.

После использования append появляются два независимых div — содержащий span и скрытый клон с img. Люди, привыкшие уважать соглашения не предполагают, что wrap неявно клонирует элементы, ведь в jQuery это делает только clone.

Пишите короче

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

Давайте рассмотрим тернарное условие в jQuery:

Программист, встретивший эту строку, предпримет попытки понять, чему же равно i, а потом наверняка прибежит к вам за разъяснениями. Смело отвечайте: «короче — всегда лучше», затем посвятите его в путь ниндзя-разработчика и вручите «Дао дэ цзин».

Сокращайте названия переменных

Самый удобный способ скрытно «улучшить» код — использовать однобуквенные переменные: a, b, c

Такую переменную нельзя найти, используя функцию поиска в текстовом редакторе. Если же кто-то нашёл её, то не сможет понять предназначение.

Другой вариант — использовать акронимы. Например, ie для Inner Element или mc для Money Counter.

Не используйте i для цикла

В местах, где переменные из одной буквы общеприняты, например, в счетчике цикла, ни в коем случае не используйте стандартные названия по типу i, j или k. Выбирайте нечто более экзотическое, например, x, y или z.

Эффективность такого подхода особенно заметна, когда тело цикла занимает несколько страниц, ведь заметить, что переменная является счетчиком цикла, не пролистывая до его начала — невозможно.

Транслитерируйте и изменяйте

Когда использовать длинные и понятные имена попросту приходится, тоже есть выход. Например, транслитерировать слова: var ssilka или var ssylka.

Не забудьте использовать разные названия в разных частях проекта, чтобы ещё больше запутать код. Можно ведь и сокращать названия, тогда в одном месте будет написано var link, а в другом — var lnk. Мало того, что такой подход очень действенен и количество ошибок при поддержке кода увеличивается во много раз, так он ещё и предоставляет возможность проявить креативность!

Абстрагируйтесь

Хороший вариант использования полноценных имён — абстрактные названия, например: data, value, item или elem.

Вообще, используйте data везде, где это возможно, ведь каждая переменная содержит некоторые данные. Уже заняли это имя? Попробуйте value — такой же универсальный вариант, согласитесь.

Добавляйте цифры

«Общие» названия закончились, а фантазия иссякла? Можно добавить цифры и получить бесконечный набор переменных: data1, data777, value327, elem9

Используйте тип переменной как имя

Другой вариант — назвать переменные по типу данных, которые она хранит. Например: arr, num, obj

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

Придумывайте похожие имена

Ваш код достоин понять только истинно внимательный программист. Так как же проверить, достоин ли читающий?

Мы предлагаем использовать похожие имена переменных, например, data и date. Заметить разницу при беглом прочтении практически невозможно, а уж заметить опечатку и поправить её…

Подумайте о синонимах

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

Допустим, если метод показывает что-то на экране — назовите его display… (например, displayElement), а в другом месте объявите аналогичный метод как show… (showFrame).

Иными словами, намекните на тонкое различие между способами работы в методах, когда его нет и в помине.

Если вы работаете в команде — договоритесь между собой так, чтобы один обязательно использовал display, другой render, а третий — paint.

Справедлив и обратный вариант, когда у двух функций есть важные отличия. В такой ситуации используйте одно слово для их описания. Например, с print начинается метод печати на принтере printPage, а также метод добавления текста на страницу printText.

Интересно будет и добавить элемент неожиданности. Допустим, читающий код программист, думает: «Куда же выводит сообщение printMessage?», а он выводит не туда, куда все, а в новое окно.

Забудьте про словарь терминов

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

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

Используйте имена повторно

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

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

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

Продвинутый вариант этого подхода — незаметно (!) подменить переменную на нечто похожее, например:

Человек, пожелавший добавить действия с elem во вторую часть функции, будет крайне удивлён. Только при отладке, посмотрев весь код, он обнаружит, что имел дело с клоном! Регулярные встречи с этим приемом на практике доказывают, что защититься невозможно. Эффективно даже против опытного ниндзя-программиста.

Добавляйте подчеркивания

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

Этим шагом вы достигните двух целей сразу:

  1. Увеличится длина кода и уменьшится его читабельность.
  2. Ваш преемник потратит много рабочего времени на поиск смысла ваших действий.

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

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

Покажите любовь к программированию

Такие имена, как superElement, megaFrame или niceItem покажут силу вашей любви к разработке, а при благоприятном положении звёзд могут даже привести к просветлению читающего код.

К тому же, соответствуют требованию к «понятным» именам, ведь что-то же написано: super, mega или nice, хотя и не несёт никакой конкретики. Читающий может попробовать поискать в этом глубинный смысл и замедитировать на часок-другой оплаченного рабочего времени.

Перекрывайте внешние переменные

Повторное использование имён можно реализовать и таким способом:

Зашедший в середину функции render, скорее всего, не заметит, что переменная user поменяла своё значение. Он внесёт правки и только после отладки поймёт, что оказался в ловушке.

Добавьте «мощности» функциям

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

Стоит добавить хотя бы одно-два «сверх-действия» к своей функции, но они не должны быть очевидны из названия. Истинный же ниндзя-разработчик сделает их и неочевидными из тела функции.

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

Ещё больше увеличивайте «мощность»

Если смотреть на названия таких функций, как isReady, checkPermission или findTags, то становится ясно, что они ничего не меняют. Вы уже понимаете, к чему мы идём? Да, нужно добавить сюда нечто полезное, причём сразу с проверкой.

Представьте то удивление, что возникнет на лице вашего коллеги, увидевшего, что функция с названием isNumber меняет значения переменных. Такое, несомненно, расширит его границы разумного.

Ещё одна вариация такого подхода — возврат нестандартного значения.

Среди блюстителей соглашений известно, что функции is и check обычно возвращают true или false. Покажите им оригинальность своего мышления, пусть вызов checkPermission вернёт объект с результатами проверки! А что, полезно, как-никак. Да и те разработчики, кто попытается написать проверку if (checkPermission(date))…, будут удивлены результатом. Когда они придут к вам, скажите: «Надо читать документацию!» и отправьте эту статью.

Заключение

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

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

Перевод статьи «How To Write Unmaintainable Code»