Как сделать код html нечитаемым

как писать нечитаемый код (гарантированная работа на всю жизнь 😉

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

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

Quidquid latine dictum sit, altum sonatur.
(Что угодно, сказанное по-латински, звучит как мудрость.)

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

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

Творческое использование ошибок.Если вы вынуждены использовать осмысленные названия переменных и функций, делайте в них орфографические ошибки. Делая ошибки в одних названиях и не делая в других (например, SetPintleOpening и SetPintalClosing), можно сделать невозможным использование grep и поиска в IDE. Это работает на удивление хорошо. Можно также использовать слова на разных языках или разные варианты написания одного и того же слова.

Используем абстракции.Придумывая названия функций и переменных, часто используйте абстрактные слова, такие как it, everything, data, handle, stuff, do, routine, perform, а так же цифры, например routineX48, PerformDataFunction, DoIt, HandleStuff и do_args_method.

Используйте формы множественного числа из других языков.Скрипт в VMS отслеживал «statii», возвращаемые различными «VAXen». Языки Эсперанто, Клингон и Хоббитанский вполне пригодны для таких целей. Можно использовать «oj» из Эсперанто для создания форм множественного числа. Тем самым вы приближаете мир во всем мире.

ПроПисНые БукВы.Используйте прописные буквы в начале слогов внутри слова случайным образом. Например, ComputeRasterHistoGram().

Повторное использование имен.Как только правила языка допускают, используйте одинаковые имена для классов, конструкторов, методов, переменных, полей, параметров и локальных переменных. Более того, повторное используйте имена локальных переменных внутри блоков <>. Целью здесь является принуждение изучающего код программиста к аккуратному отслеживанию области видимости любой переменной. В частности, в Java, маскируйте обычные методы под видом конструкторов.

Используйте ограничения компилятора на длину имен.Если компилятор различает, скажем, только первые 8 символов имен, то изменяйте окончания, например var_unit_update() в одном случае и var_unit_setup() в другом. Компилятор воспримет оба случая как var_unit.

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

Расширенные символы ASCII.Расширенные символы ASCII чудесно подходят в качестве имен переменных, в том числе и символы Я, Р и с. Их практически невозможно набрать в простом текстовом редакторе, не используя copy-paste.

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

Математические названия.Выбирайте имена переменных, обозначающие математические операторы, например:

openParen = (slash + asterix) / equals;

Эмоционально насыщенные имена.Выбирайте имена переменных с эмоциональным значением, не имеющим отношения к программе, например:

marypoppins = (superman + starship) / god;

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

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

Соглашения.Игнорируйте Sun Java Coding Conventions, тем более что и сам Sun им не следует. К счастью, компилятор никому не расскажет о том, что вы их нарушили. Целью является использование имен, отличающихся лишь прописными и строчными буквами. Если вы вынуждены подчинятся соглашению о использовании прописных букв, вы можете нарушить его в случае неоднозначного выбора, например использовать оба варианта: inputFilename and inputfileName. Придумайте собственное безнадежно сложное соглашение об именах и затем ругайте всех, кто ему не следует.

Строчная буква l очень похожа на цифру 1.Используйте строчную букву l для обозначения констант типа long, например 10l скорее всего будет принято за 101 а не за 10L, которым оно является. Запретите любые шрифты, в которых явно различаются uvw, wW, gq9, 2z, 5s, il17|!j, oO08, `'», ;,. m nn rn, <[()]>. Подходите к делу творчески. Используйте недостатки шрифтов, в которых трудно различить указаные выше символы в парах идентификаторов вроде parselnt и parseInt или D0Calc и DOCalc. Идеальной парой имен переменных являются swimmer и swimner. А как вам такое имя переменной: swirnrner? 🙂
Кстати l является отличным выбором для имени переменной, так с первого взгляда этот символ похож на константу 1.

Похожие по написанию и звучанию имена переменных.Если у нас есть переменная с именем xy_z, почему бы не сделать несколько других переменных с именами xy_Z, xy__z, _xy_z, _xyz, XY_Z, xY_z и Xy_z. Преимущество переменных, отличающиеся от других только знаками подчеркивания и регистром символов, в том, что они мешают тем, кто запоминает имена по их звучанию или побуквенному написанию, вместо того, чтобы запоминать их полностью.

Повторное использование имен глобальных переменных в качестве локальных.Объявите глобальный массив в модуле A и локальный с таким же именем в заголовке модуля B. Таким образом, будет казаться, что в модуле B используется глобальный массив, хотя на самом деле это не так. Не упоминайте это в комментариях.

Кд нпснй бз глснх грзд мньш.Используя сокращения в именах переменных или методов, веселья ради используйте несколько различных вариантов одного и того же слова и даже иногда используйте его без сокращений. Это принесет победу над теми бездельниками, которые пользуются поиском текста для изучения только одного аспекта вашей программы. Используйте в качестве хитрости различные варианты написания, смешивая международное colour, американское color и жаргонное kulerz. При использовании полных названий существует только один способ написания. Это слишком легко запомнить. А вот сокращенные названия можно делать разными, поэтому, используя их, можно сделать несколько различных переменных с одинаковым назначением. Дополнительным преимуществом этого подхода является то, что читающему код программисту легко запутаться в похожих переменных.

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

o_apple obj_apple.Используйте префиксы o или obj для каждого экземпляра класса, чтобы продемонстрировать ту большую полиморфную картину, которую вы себе представляете.

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

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

Настаивайте на использовании всей доступной информации в префиксах имен. К примеру, a_crszkvc30LastNameCol. У команды поддержки ушло три дня, чтобы понять, что это громадное имя переменной означает константную ссылку являющуюся аргументом функции, в которой содержится информация из колонки базы данных типа Varchar[30] с названием LastName, являющейся частью первичного ключа таблицы. Грамотно скомбинировав эту методику с принципом «все переменные должны быть public» вы получите способ изготовления кода, мгновенно устаревающего сразу после написания.

Опять венгерская нотация.Еще один фокус с венгерской нотацией заключается в том, чтобы «изменить тип переменной, но ее имя не менять». Это уже произошло при переносе Windows-приложений : win16 WndProc(HWND hW, WORD wMsg,WORD wParam, LONG lParam) превратилась в Win32 WndProc(HWND hW, UINT wMsg,WPARAM wParam,LPARAM lParam), где w предполагает, что параметр является словом, хотя на самом деле это длинное целое. Логическим завершением этого подхода станет переход на Win64, когда параметры станут 64-битными целыми, а старые префиксы w и l останутся навсегда.

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

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

Маскировка кода как комментариев и наоборот.Включите участок кода который закомментирован, но не выглядит таковым.

Без подсветки синтаксиса заметите ли вы, что три строки кода закомментированы?

Пространства имен.Struct/union и typedef struct/union являются различными пространствами имен в C (но не в C++). Используйте одинаковые имена в обоих пространствах имен. Сделайте их, если возможно, почти совместимыми.

typedef struct <
char* pTr;
size_t lEn;
> snafu;
struct snafu <
unsigned cNt
char* pTr;
size_t lEn;
> A;

Спрятанные макросыСпрячьте определения макросов среди бессмысленных комментариев. Программист устанет читать комментарии и пропустит определение макроса. Удостоверьтесь, что макрос заменяет внешне нормальную операцию присваивания чем-нибудь совершенно невменяемым, к примеру:

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

#define fastcopy(x,y,z) /*xyz*/

fastcopy(array1, array2, size); /* ничего не делаем */

кстати, комментарий в этой строке нарушает принципы запутывания кода (прим. перев.)

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

#define local_var xy_z

разделите "xy_z" на две строки:

#define local_var xy\
_z // local_var OK

Таким образом, поиск xy_z по файлам ничего не даст, а для препроцессора С "\" в конце строки означает ее продолжение на следующей строке.

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

Не меняйте имен.Вместо глобальных переименований для синхронизации двух частей кода используйте много TYPEDEF для одного символа.

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

Перегрузка для загрузки.В C++ переопределите стандартные функции с использованием #define. Это будет выглядеть, как будто вы используете стандартную функцию, в то время как вы будете использовать нечто совершенно другое.

#define.Выражение #define в C++ заслуживает посвящения ему отдельной статьи за его возможности в плане запутывания кода. Используйте определенные с помощью #define переменные с именами в нижнем регистре, маскируя их под обычные переменные. Никогда не используйте параметры для макросов препроцессора. Используйте только глобальные определения с помощью #define. Одним из наиболее впечатляющих вариантов использования препроцессора, о котором я слышал, было требование пятикратного прохода по коду, перед тем как его можно было скомпилировать. Мастер запутывания кода, грамотно используя #define и #ifdf, способен заставить файлы заголовков определять различные вещи в зависимости от того, сколько раз они включены. Это становится особенно интересным в случае включения одного заголовочного файла в другой. вот особенно запутывающий пример:

#ifndef DONE

// put stuff here to declare 3rd time around
void g(char* str);
#define DONE

#else // TWICE
#ifdef ONCE

// put stuff here to declare 2nd time around
void g(void* str);
#define TWICE

// put stuff here to declare 1st time around
void g(std::string str);
#define ONCE

#endif // ONCE
#endif // TWICE
#endif // DONE

Развлечение начнется при передаче функции g() параметра char*, поскольку будут вызываться различные версии g() в зависимости от того, сколько раз был подключен заголовочный файл.

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

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

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

Документируйте "Как?" вместо "Зачем?".Документируйте только детали работы программы, а не цель ее работы. Таким образом, при ошибке будет невозможно понять, что вообще должен делать код.

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

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

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

Кобол на перфокартах.Всеми силами сопротивляйтесь новым веяниям в области средств разработки. Не верьте, что до любого объявления можно перейти одним кликом и исходите из предположения, что код, разработанный в Visual Studio 6.0 будет поддерживаться человеком, использующем edlin или vi. Настаивайте на использовании драконовского стиля комментариев, чтобы похоронить за ними исходный код.

Комментарии Монти Пайтона.Для метода с названием makeSnafucated вставьте JavaDoc /* make snafucated */. Нигде не определяйте, что означает слово snafucated. Только дурак не знает точно, что означает snafucated. Примеры использования этого метода можно посмотреть в Sun AWT JavaDOC.

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

Bubblegum b = new Bubblegom();

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

swimmer = swimner + 1;

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

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

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

Холостые интерфейсы.Напишите пустой интерфейс с названием вроде WrittenByMe и реализуйте его во всех ваших классах. Затем напишите классы- обертки для всех используемых встроенных классов Java. Идея заключается в том, чтобы все объекты в вашей программе реализовывали этот интерфейс. В конце концов, напишите все методы таким образом, что их аргументы и возвращаемые значения будут иметь тип WrittenByMe. Это сделает практически невозможным разобраться в том, как работают методы, и заставит использовать множество веселых преобразований типов. Кроме того, заставьте всех в команде написать собственный личный интерфейс (например, WrittenByJoe) и реализовать его в их классах. Затем вы сможете ссылаться на объекты с помощью переменных большого количества бессмысленных типов интерфейсов.

Гигантские обработчики.Никогда не создавайте отдельные обработчики событий для компонентов. Для всех кнопок в проекте создайте один обработчик и заполните его гроздьями if. else чтобы выяснить, какая кнопка была нажата.

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

Обертки, обертки, обертки.Если вам приходится использовать чужой код, отделите ваш код от чужого грязного кода как минимум одним слоем оберток. Иначе что вы будете делать, если когда-нибудь автор чужого кода поменяет названия всех методов? Конечно, можно будет глобально переименовать все вызовы в VAJ (Visual Age for Java) или сделать обертку уже потом. Но возможность такой ситуации является отличным поводом для того чтобы изолировать чужой код раньше, чем с ним сделают что-нибудь невменяемое. Один из главных недостатков Java в том, что невозможно решить множество мелких задач без бессмысленных методов-оберток, которые не делают ничего, кроме вызова другого метода с таким же или похожим именем. Это означает, что есть возможность написать обертки до четырех уровней вглубь, и никто не обратит внимания. Для еще большего помрачения рассудка переименуйте методы-обертки, используя различные синонимы из словаря. Это создаст иллюзию того, что методы что-то действительно делают. Кроме того, множество синонимов затруднит выработку единой терминологии для проекта. Чтобы никто не посмел привести ваш код к меньшему уровню оберток, кое-где пропускайте обертки и вызывайте код напрямую.

И еще неМНОГО оберток.Все функции API должны быть окружены обертками минимум 6-8 раз, с объявлениями функций в различных исходных файлах. Используйте #define для создания кратких ссылок на эти функции.

Перемены и перестановки.Измените порядок следования параметров в методе с названием drawRectangle(height, width) на drawRectangle(width, height) без изменений в имени метода. Через несколько релизов поменяйте их обратно. С первого взгляда понять, какой из вариантов вызывается, будет невозможно. Читателю предоставляется возможность самому придумать другие варианты использования этого способа.

Тема с вариациями.Вместо передачи параметра в один метод, создайте столько методов, сколько сможете. Например, вместо setAlignment(int alignment) где alignment является константой со значениями, соответствующимb left, right и center, создайте три метода: setLeftAlignment, setRightAlignment и setCenterAlignment. Само собой, для полного эффекта, скопируйте общий код во все три метода, затруднив поддержание их согласованными.

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

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

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

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

Глобальные объявления, как много в этом звуке!Если бы Господь Бог не хотел, чтобы мы использовали глобальные переменные, он бы их не изобрел. Не разочаровывайте Господа Бога, используйте глобальные переменные, где только можно. Каждая функция должна использовать и устанавливать как минимум две из них, даже если для этого нет никакой причины. В конце концов, любой хороший программист быстро поймет, что это испытание, по результатам которого настоящие программисты будут отделены от любителей.

Таки да, опять глобальные переменные.Глобальные переменные помогут вам не объявлять параметры для функций. Используйте этот метод целиком. Выберите одну или две глобальные переменные, чтобы описать, что делать с другими. Обслуживающие программисты ошибочно считают, что у функций C не должно быть побочных эффектов. Сделайте так, чтобы функции сохраняли результаты и данные о своем внутреннем состоянии в глобальных переменных.

Локальные переменные.Не используйте локальных переменных. Если вы испытываете искушение использовать их, лучше сделайте их полями экземпляра или статическими полями, чтобы разделить их с другими методами класса. Это сократит работу в будущем, когда другим методам понадобятся похожие переменные. Программисты, использующие C++, могут также сделать все переменные глобальными.

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

Roedy Green, Canadian Mind Products. Перевод Zju.
обсуждение статьи

Сетевые решения. Статья была опубликована в номере 02 за 2006 год в рубрике PRIcall

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *