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

продолжение, начало в «СР» №2 за 2006 г.

запутывание кода

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

Запутанный C.Участвуйте в интернет-соревнованиях по созданию запутанного кода на C и учитесь у его мастеров.

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

Джуд Незаметный(ссылка на название романа Томаса Харди Jude the Obscure). Всегда находите наиболее неочевидный способ решения обычных задач. Например, вместо использования массивов для конверсии числа в строку, используйте код вроде этого:

char *p;
switch (n)
{
case 1:
p = "one";
if (0)
case 2:
p = "two";
if (0)
case 3:
p = "three";
printf("%s", p);
break;
}

Постоянство - это пугало для маленьких.Если вам нужна константа-символ, используйте множество различных форматов ' ', 32, 0x20, 040. Свободно пользуйтесь тем фактом что 10 и 010 являются разными числами в C или Java.

Приведение типов.Передавайте все данные как void* и затем используйте приведение к нужному типу. Вместо этого можно использовать смещение указателя для доступа к данным внутри структуры.

Вложенный switch.Конструкция switch внутри другого switch - это самый сложный для понимания человеческим мозгом вид вложенности.
Используйте неявные преобразования. Заучите все тонкости правил неявного преобразования в языке программирования и используйте их на всю катушку. Не используйте переменные с форматированием (в COBOL или PL/I) или процедуры преобразования (такие как sprintf в C). Вместо этого используйте числа с плавающей точкой в качестве индексов массивов, символьные переменные в качестве счетчиков циклов, и вызывайте строковые функции, передавая им числа. В конце концов, все преобразования понятны и только сделают ваш код более сжатым. Программист, поддерживающий код, будет благодарен вам за это, поскольку для понимания ваших программ ему придется выучить целый раздел документации про неявные преобразования, который он раньше всегда пропускал.

Просто числа.Используя ComboBox’ы, в качестве вариантов значений switch ставьте просто числа и ни в коем случае не именованные константы. Точки с запятыми! Всегда используйте точки с запятыми там, где это допускает синтаксис. Например:

if(a);
else;
{
int d.;
d = c;
}
;


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

array = new int []
{
111,
120,
013,
121,
};

Непрямые преобразования.Java предоставляет большие возможности запутывания при преобразованиях. Простой пример - если вы хотите преобразовать double в String, используйте окружной путь, через Double:

new Double(d).toString()

а не простой

Double.toString(d)

Можно, конечно, сделать и еще более закрученным способом.
Кроме того, вы получите дополнительное преимущество - этот код создает временные объекты, остающиеся в памяти после выполнения преобразования. Вложенность. Увеличивайте вложенность кода, насколько сможете. Хорошие кодеры могут добиться до 10 уровней вложенности () в одной строке и 20 уровней {} в одной функции. Программистам на C++, кроме этого, доступны возможности создания вложенных директив препроцессора, не зависящих от вложенности кода. Старайтесь размещать начало и конец блока таким образом, что в распечатке кода они окажутся на разных страницах. По возможности, используйте вместо вложенных выражений if вложенные тернарные операторы ?:, чем больше они занимают, тем лучше.

Числовые значения.Если у вас есть массив с 100 элементами, используйте числовое значение 100 в как можно большем количестве участков кода. Никогда не используйте константу для 100 и не ссылайтесь на нее как myArray.length. Усложните изменение этого значения, используя 50 вместо 100/2 или 99 вместо 100-1. Можно еще более замаскировать 100, проверяя условия a == 101 вместо a >100 или a >99 вместо a >= 100.

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

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

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

Оригинальный подход C к массивам.Компиляторы C преобразуют myArray[i] в *(myArray + i), что эквивалентно *(i + myArray) что, в свою очередь, эквивалентно i[myArray]. Профессионалы знают, где найти этому применение. Для лучшей маскировки, рассчитывайте индекс в функции:

int myfunc(int q, int p) { return p%q; }
...
myfunc(6291, 8)[Array];

К сожалению, это можно использовать только в C, но не в Java.

Д л и н н ы е с т р о к и.Старайтесь поместить как можно больше кода в одну строку. Это сократит расход лишних переменных и сделает исходные файлы короче за счет удаления переносов строк и пустых символов. Удалите все пустые символы возле операторов. Хорошие программисты запросто превзойдут ограничение в 255 символов на строку, существующее в некоторых редакторах. Преимущество длинных строк в том, что тем, кто не может читать шрифт 6-го размера, придется прокручивать окно по горизонтали, чтобы прочесть их.

Исключения.Я собираюсь открыть вам один малоизвестный секрет программирования. Исключения напрягают. Правильно написанный код никогда не генерирует исключений, поэтому они не нужны. Не тратьте на них свое время. Создание собственных унаследованных исключений - это для некомпетентных программистов, которые знают, что их код ошибается. Программу можно сильно упростить, окружив одним блоком обработки исключений try/catch в Main, который будет просто вызывать System.exit(). В Java также можно навесить на каждый метод полный набор стандартных исключений, вне зависимости от того, выбрасывает он их или нет.

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

Используйте забытые потоки.Пояснений не требуется.

Код с неясным поведением.Участвуйте в обсуждениях того, что должны делать всякие не самоочевидные куски кода вроде a=a++; или f(a++,a++);, а затем используйте эти примеры в своем коде. В C, эффекты пре- и постинкрементного кода, такого как

*++b ? (*++b + *(b-1)) 0

не определены стандартом языка. Выбор порядка их вычисления остается за компилятором, что делает этот метод мощным средством запутывания кода. Также можно использовать в этих целях сложные правила разбиения на лексемы в C и Java, удаляя из кода все пробелы.

Ранний возврат из функций.Жестко следуйте указаниям не использовать goto, return в середине кода и break с метками, особенно если это позволит увеличить вложенность if/else как минимум на 5 уровней.

Избегайте {}.Не используйте {} в блоках if/else, если для этого нет надобности. Имея глубоко вложенную смесь выражений if/else и блоков, особенно с неадекватными отступами, можно запутать даже опытного программиста. В Perl, для еще лучших результатов, можно использовать if после выражений.

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

Волшебные индексы матриц.Используйте специальные значения в определенных местах матриц в качестве флагов. Например, элемент [3][0] в матрице преобразования координат.

Массивы с волшебными элементами.Если вам нужно несколько переменных определенного типа, определите массив и обращайтесь к ним по номеру. Выберите соглашение о номерах, известное только вам, и нигде не документируйте его. И даже не пытайтесь определить константы для индексов. Все просто обязаны знать, что глобальная переменная [15] является кнопкой Cancel. Это всего лишь современная версия использования абсолютной числовой адресации в ассемблере.

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

if(a)
if(b) x=y;
else x=z;

Препроцессор макросов является мощным инструментом запутывания кода.Главным средством служат несколько уровней макросов, вложенных таким образом, что для понимания, что они делают, придется изучать несколько различных .hpp-файлов. Помещая исполняемый код в макросы и затем, включая их во все .cpp-файлы (даже те, которые их не используют), можно увеличить количество необходимых в случае изменения кода перекомпиляций. Используйте шизофрению. Java в плане объявления массивов страдает шизофренией. Можно объявлять их как в стиле старого C: String x[] (используется смешанная префиксно-постфиксная запись) или в новом стиле String[] x, использующем чисто префиксную запись. Если вам действительно нужно запутать людей, смешайте оба вида записей, например:

byte[ ] rowvector, colvector , matrix[ ];

что эквивалентно

byte[ ] rowvector;
byte[ ] colvector;
byte[ ][] matrix;

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

if ( function_A() == OK )
{
if ( function_B() == OK )
{
/* Нормальная обработка */
}
else
{
/* обработка ошибок для Function_B */
}
}
else
{
/* обработка ошибок для Function_A */
}

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

#define begin { " or " #define end }

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

import MyPackage.Read;
import MyPackage.Write;

используйте:

import Mypackage. *;

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

/*
/* Название процедуры:
/*
/* Исходное название процедуры:
/*
/* Автор:
/*
/* Дата создания:
/*
/* Даты исправлений:
/*
/* Авторы исправлений:
/*
/* Исходное имя файла:
/*
/* Цель:
/*
/* Назначение:
/*
/* Смысл:
/*
/* Используемые классы:
/*
/* Константы:
/*
/* Локальные переменные:
/*
/* Параметры:
/*
/* Дата создания:
/*
/* Назначение:
*/

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

тестирование

Мне не нужно тестировать свои программы. У меня модем с коррекцией ошибок.
- Om I. Baud


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

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

Не пишите никаких контрольных примеров.Никогда не проводите тестирование покрытия кода. Автоматическое тестирование - это для зануд. Выясните, какие функции нужны в 90% случаев использования ваших подпрограмм и выделите 90% времени на их тестирование. В итоге, этот способ приведет к тому, что протестировано будет только около 60% кода и получается, что вы сэкономили 40% времени. Тем самым вы сможете вписаться в график в конце проекта. Когда кто-нибудь заметит, что все эти красивые рекламируемые функции не работают, вас уже и след простынет. Известные большие компании тестируют код таким образом, поступайте и вы так. Если же вы еще будете поблизости - смотрите далее.

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

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

Убедитесь, что программа работает только в режиме отладки. Если определить TESTING как 1

#define TESTING 1

то это дакт чудесную возможность отделить блоки

#if TESTING==1
#endif

содержащие незаменимые части кода, такие как

x = rt_val;

таким образом, что если кто-нибудь установит TESTING в 0, то программа перестанет работать. При минимальной работе воображения, можно нарушить работу программы таким образом, что компилятор этого не заметит.

выбор языка

Философия есть битва против околдования нашего разума средствами нашего языка.
- Людвиг Витгенштейн.

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

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

Избегайте Ada.Около 20% этих методов нельзя использовать в Ada. Отказывайтесь работать на нем. Если ваше начальство заставляет вас, настаивайте, что никто больше не использует Ada, и укажите, что его нельзя использовать с вашим набором утилит, которые так хорошо работают с C. Используйте ассемблер. Переделайте все общие функции на ассемблере.

Используйте QBASIC.Оставьте все важные библиотечные функции написанными на QBASIC, а затем просто напишите обертку на ассемблере для преобразования моделей адресации памяти.

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

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

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

общение с окружающими


Ад - это другие.
- Жан-Поль Сартр, Нет выхода, 1934.

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

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

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

Никогда не отвечайте на телефон.Используйте автоответчик, который говорит: "Спасибо за звонок в нашу службу поддержки. Чтобы поговорить с оператором нажмите "1"или оставьте сообщение после звукового сигнала. Запросам по электронной почте необходимо присваивать номер и забывать про них. На любой вопрос должен быть стандартный ответ: "Возможно, ваш счет блокирован. Ответственный за восстановление в данный момент недоступен."

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

Сбейте их с толку.Тонкость - это хорошая вещь, хотя иногда в качестве тонкого инструмента лучше всего использовать кувалду. Таким образом, расширяя идею вводящих в заблуждение комментариев, создайте классы с именами вроде FooFactory, содержащие комментарии, ссылающиеся на паттерны проектирования "Банды четырех" (оптимально - с гиперссылками на бессмысленные UML-документы), не имеющие никакого отношения к созданию объектов. Играйте на иллюзии компетентности у программистов службы поддержки. Более хитрый способ - создать Java-классы с защищенными конструкторами и методами вроде Foo f = Foo.newInstance(), которые возвращают действительно новые экземпляры вместо ожидаемого синглетона. Количество побочных эффектов такого подхода безгранично.

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

самоделки

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

Самодельная форма Бэкуса-Наура.Всегда документируйте синтаксис команд в собственном уникальном недокументированном варианте формы Бэкуса-Наура. Никогда не объясняйте синтаксис, приводя примеры правильных и неправильных команд, поскольку это демонстрирует недостаток у вас академических знаний. Убедитесь, что нету очевидного способа отличить терминальный символ (тот, который вводится) от нетерминального (представляющего фразу в синтаксисе) Никогда не используйте шрифты, цвета, прописные буквы и другие визуальные подсказки, помогающие их отличить. Используйте в вашей нотации те же знаки препинания, что и в синтаксисе языка команд, таким образом, что читатель не сможет разобраться, являются ли (...), [...], {...} или "..." частью команды или описывают, является ли параметр обязательным или повторяющимся. В конце концов, если кто-то не сможет понять ваш вариант формы Бэкуса-Наура, он не имеет права пользоваться вашей программой.

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

трюки с другими языками

Программирование на Бейсике вызывает повреждения мозга.
- Эдсгер Вайб Дейкстра.

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

Соединения в SQL.Используйте совместно различные варианты синтаксиса соединений (joins), пусть народ помучается.

Область видимости в JavaScript."Оптимизируйте" код JavaScript, используя тот факт, что код функции имеет доступ к локальным переменным кода, вызвавшего функцию.

Объявления в Visual Basic.Вместо:

dim Count_num as string
dim Color_var as string
dim counter as integer

используйте

Dim Count_num$, Color_var$, counter%

Безумие Visual Basic.При чтении из текстового файла, прочитайте на 15 символов больше чем надо, затем вставьте настоящую текстовую строку:
ReadChars = .ReadChars (29,0)
ReadChar = trim(left(mid(ReadChar,len(ReadChar)-15,len(ReadChar)-5),7))
If ReadChars = "alongsentancewithoutanyspaces"
Mid,14,24 = "withoutanys"
and left,5 = "without"

Только для Delphi/Pascal.Не используйте функции и процедуры. Используйте выражения label/goto и прыгайте по коду туда-сюда. Кого угодно приведет в бешенство попытка отладить такой код. Можно вообще заполнить код этими выражениями полностью, перемещаясь по нему совершенно бессмысленным образом.

Perl.Используйте постфиксную форму if и unless в конце особо длинных строк.

Lisp.LISP - это язык мечты для того, кто пишет нечитаемый код. Взгляните на этот безумный пример:

(lambda (*<8-]= *<8-[= ) (or *<8-]= *<8-[= ))
(defun :-] (<) (=< 2))
(defun !(!)(if(and(funcall(lambda(!)(if(and '(< 0)(< ! 2))1 nil))(1+ !))
(not(null '(lambda(!)(if(< 1 !)t nil)))))1(* !(!(1- !)))))

Visual Foxpro.Этот трюк специфичен для Visual Foxpro. Переменная не определена и не может быть использована, если ей не присвоено значение. Вот что произойдет, если вы проверите тип переменной:

lcx = TYPE('somevariable')

Значение lcx будет 'U' (не определено). Но если вы присвоите переменной локальную область видимости, это определит ее и присвоит ей логическое значение FALSE:

LOCAL lcx
lcx = TYPE('somevariable')

Значение lcx теперь является 'L'(логическое). Кроме того, значение переменной определено, как FALSE. Представьте себе всю мощь использования этого метода для написания нечитаемого кода:

LOCAL lc_one, lc_two, lc_three... , lc_n
IF lc_one
DO ужасно_длинная_процедура_которая_никогда_не_будет_выполнена WITH
обязательно_передайте_кучу_параметров
ENDIF
IF lc_two
DO ужасно_длинная_процедура_которая_никогда_не_будет_выполнена WITH
обязательно_передайте_кучу_параметров
ENDIF
PROCEDURE ужасно_длинная_процедура_..
* поместите сюда кучу кода который не будет выполняться
* почему бы не скопировать сюда всю главную процедуру
ENDIF

разнообразные трюки

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

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

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

Система единиц СИ и национальные системы.В инженерных расчетах есть два способа счета. Один - это преобразовать всех входные величины в систему СИ, выполнить расчеты и преобразовать результат обратно в привычную систему. Другой способ - использовать при расчетах все системы одновременно. Всегда выбирайте его, это наш метод!

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

"О программе".Окно "О программе" должно содержать только название программы, имена разработчиков и написанное заумным юридическим языком соглашение о копирайте. Еще можно добавить пару мегабайт кода, которые будут показывать веселые шевелящиеся картинки. Однако, в этом окне не должно быть назначения программы, номера версии, даты последнего изменения в коде, ссылки на веб-сайт с обновлениями или адреса электронной почты автора программы. В итоге все пользователи будут использовать разные версии, и пытаться инсталлировать версию N+2 перед версией N+1. Перемены тихой сапой. Чем больше изменений вы можете сделать между версиями, тем лучше - вы же не хотите, чтобы пользователям надоел старый API или пользовательский интерфейс, который они используют годами. А еще вы можете делать изменения, не предупреждая пользователей, что заставит их быть всегда начеку.

Помещайте прототипы C в отдельные файлы вместо общих заголовков.У этого метода есть двойное преимущество в том, что каждое изменение типа данных параметров придется изменять в каждом файле и компилятор или компоновщик не сможет определить расхождения в типах. Особенно это окажется полезным при переходе от 32- к 64-битным платформам.

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

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

Инверсия True и False.Поменяйте местами определения true и false. Вроде бы очевидное действие, но очень эффективное. Спрячьте

#define TRUE 0
#define FALSE 1

где-нибудь глубоко в дебрях кода программы, в файле, в который никто не заглядывает. Затем используйте явные сравнения таким образом:

if ( var == TRUE )
if ( var != FALSE )

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

if ( var )

Другой способ - это назначить TRUE и FALSE одинаковые значения, хотя большинство посчитает, что это мошенничество. Можно использовать значения 1 и 2 или -1 и 0 - это более хитрый способ, и вы не вызовете подозрений. В принципе, можно использовать этот метод в Java, объявив статическую константу с именем TRUE, хотя вас могут заподозрить в непрофессионализме, поскольку в Java существует встроенный литерал true.

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

Избегайте библиотек.Создайте иллюзию незнания стандартных библиотек вашего средства разработки. Если вы используете Visual C++, игнорируйте MFC или STL и напишите всю обработку строк и массивов заново. Это поможет вам сохранить умение работать с указателями и автоматически помешает попыткам доработки кода.

Создайте собственный способ сборки.Сделайте его настолько сложным, что никто никогда не сможет откомпилировать код с изменениями. Храните в секрете все программы, которые могут упростить сборку. Никому не говорите, что компилятор javac доступен в виде класса и под страхом смерти не признавайтесь, что очень легко написать программу, которая перебирает файлы и компилирует их, вызывая sun.tools.javac.Main.

Развлечения с Make.Используйте сгенерированные из makefile пакетные файлы для копирования исходных файлов из разных директорий с
недокументированными правилами перезаписи. Это позволит делать несколько версий приложения без всяких систем контроля версий, и помешает вашим преемникам разобраться, какую из версий процедуры DoUsefulWork() они должны отредактировать.

Коллекционируйте стандарты кодирования.Найдите все советы о том, как писать читаемый код и целенаправленно не следуйте им.
IDE, не я!. Поместите весь код в makefile. Ваши последователи будут действительно удивлены, как вам удалось написать makefile, который создает пакетный файл, который создает какие-то файлы заголовков и затем собирает приложение. Таким образом, они никогда не поймут, какие побочные эффекты будут от изменения и не смогут перейти к современной среде разработки. Для максимального эффекта используйте устаревшие средства сборки, вроде ранней тупой версий NMAKE, которая не понимала зависимостей.

Обход стандартов кодирования.В некоторых компаниях существует строгая политики неиспользования численных значений; вместо них необходимо использовать именнованные констаты. Очень легко извратить намерения, с которыми вводилась такая политика. Например, хитрый C++ программист может написать:

#define K_ONE 1
#define K_TWO 2
#define K_THOUSAND 999

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

Сочетайте обновления и исправления ошибок.Никогда не выпускайте версии только с исправлениями ошибок. Обязательно добавьте к ним изменения формата баз данных, сложные переделки пользовательского интерфейса и полностью переделанные интерфейсы администрирования. Таким образом, поскольку людям будет сложно произвести обновление, они привыкнут к ошибкам и начнут их считать особенностями программы. А у тех, кому действительно нужно, чтобы эти "особенности" работали по-другому, появится стимул к переходу на новые версии. Это сократит количество работы по поддержке и позволит получить больше прибыли с покупателей.

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

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

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

Используйте ненужный код синхронизации.Поместите в программу использование объектов синхронизации там, где они не нужны. Однажды мне попалась критическая секция в коде, где не могло быть второго потока. Программист, который ее туда поместил, сказал, чтобы было сделано для того, чтобы пометить код, как "критический".
Постепенный выход из строя. Если ваша система включает в себя драйвер устройств для NT, заставьте приложение выделить буфер для ввода-вывода, заблокировать его на время операции и освободить потом. Это приведет к тому, что приложение повесит NT, если его убить в то время, когда буфер заблокирован. У клиентов некому будет поменять драйвер устройства, так что особого выбора у них не будет.

Собственный язык сценариев.Встройте в свое приложение собственный язык сценариев, компилируемый в байт-код во время исполнения.

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

void* Realocate(void*buf, int os, int ns)
{
void*temp;
temp = malloc(os);
memcpy((void*)temp, (void*)buf, os);
free(buf);
buf = malloc(ns);
memset(buf, 0, ns);
memcpy((void*)buf, (void*)temp, ns);
return buf;
}


Здесь:

- заново изобретена стандартная функция;
- слово Realocate написано неверно. Нельзя недооценивать силу творческого подхода к грамматике;
- создание временной копии входного буфера без причины;
- беспричинное преобразование типов: memcpy() принимает (void*), поэтому надо привести указатели, хотя они и так (void*). Тем более, что туда можно передавать все что угодно и так;
- temp не освобождается. Это вызовет медленную утечку памяти, которая не проявится до тех пор, пока программа не проработает несколько дней; - копирование из буфера больше, чем нужно в некоторых случаях. Это вызовет core dump в Unix, но не в Windows;
- очевидно, что os и ns означают old size и new size;
- после выделения памяти под buf, заполнить ее 0. Не используется calloc(), поскольку кто-нибудь когда-нибудь перепишет спецификацию ANSI таким образом, что calloc() будет заполнять буфер чем-нибудь отличным от 0. То, что мы все равно запишем поверх буфера старые значения, никого не волнует.
Как избавиться от предупреждений о неиспользуемых переменных. Если компилятор выдает такое предупреждение - не удаляйте переменную. Вместо этого, придумайте способ использовать ее. Вроде такого:

i = i;

Размер имеет значение.Очевидно, что чем больше функция, тем лучше. И чем больше в ней переходов и goto, тем лучше. Таким образом, любые изменения должны быть проанализированы во множестве сценариев. Программист, обслуживающий код, запутается в его нагромождениях. Если функция действительно огромная, она станет Годзиллой для программистов поддержки – монстром, втаптывающим их в землю еще до того, как они поймут что происходит.

Картина стоит тысячи слов; Функция стоит тысячи строк.Сделайте каждый метод как можно больше - надеюсь, вы никогда не делаете методы короче, чем несколько тысяч вложенных строк кода.

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

#include

Stdcode.h наличествует. Но в нем есть ссылка на другой файл -

#include "a:\\refcode.h"

а refcode.h нету.

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

философия

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

Примером такого элитарного мышления является интерфейс JDBC. Он упрощает жизнь разработчику JDBC, но делает ее кошмаром для программистов служб поддержки. Он гораздо более топорный, чем интерфейс FORTRAN, появившийся вместе с SQL три десятилетия назад.

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

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

сапожник без сапог

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

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

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

Эта статья - шутка! Я извиняюсь, если кто-нибудь понял ее слишком буквально. Канадцы считают неудобным помечать шутки :). Никто не обращал внимания, когда я рассказывал о том, как писать читаемый код. Оказалось, что люди готовы слушать про глупые вещи, которые надо делать, чтобы все испортить. Проверка на наличие паттернов нечитаемого кода является быстрым способом защититься от злонамеренной или случайной неряшливости при программировании.



Roedy Green, Canadian Mind Products. Перевод Zju.


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

©1999-2024 Сетевые решения