Pull to refresh

Причины и следствия

Reading time3 min
Views1.2K
Здесь я хочу поделиться с вами тремя примерами неадекватного кода. И в то же время постараюсь разобрать и классифицировать каждый случай. Тем самым расскажу не только «что такое плохо?», но и «почему?»


Недостаток знаний/опыта.


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

Похожий код уже публиковался на хабрахабре. Коротко. По ссылке: выборка идентификатора для вставки нового элемента в таблицу базы данных MySQL (выбирается наибольший идентификатор, прибавляется единица, вставляется новая запись). Автор шедевра, который я вам хочу представить, пошел еще дальше. ID выбирается случайно, попытки вставить запись не прекращаются до тех пор, пока генератор псевдослучайных чисел не угадает свободный ID.

Код выглядел примерно так:
$id = 0;
while (!$id || mysql_error()) {
    $id = rand(1, 10000000);
    mysql_query("INSERT INTO `table` (id) VALUES ('".$id."'");
}

Причина. Незнание автором особенностей SQL (auto_increment в частности).
Совет. Учиться, учиться и еще раз учиться. Читать умные книжки, смотреть чужие коды, критиковать собственный код, просить совета у более опытных программистов.


Непонимание.


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

Выглядело это так:
readln(x);
if sqrt(x) = x/sqrt(x) then
    writeln(x, ' - полный квадрат')
else
    writeln(x, ' - не является полным квадратом');

Причина. Я не проанализировал свой код. С математической точки зрения, условие «sqrt(x) = x/sqrt(x)» выполняется всегда (при x > 0), и лишь благодаря ограничению разрядной сетки операндов программа выполняла свою функцию (в конце дробной части возникала погрешность).
Совет. Понять свой код. Убедиться в том, что в программе протекают задуманные процессы.


Невнимательность.


И напоследок страшная сказка на ночь. Следующий код, в отличие от приведенных выше, никогда и никем не был написан (я очень на это надеюсь). Хотя его аналоги на других языках программирования, похоже, встречаются на самом деле. Например, #define TRUE FALSE (С, я полагаю?), упомянутый ранее. Или пресловутая «собака» (@) в PHP.

Ассемблер:
push    ss
mov     ss, 01f7
;       ...
pop     ss

Я не стану уверять вас, что этот код работоспособен (с ассемблером имел дело давно… и неправда). Общий смысл, который я хотел передать: в стек помещается адрес сегмента стека, в регистр адреса сегмента стека пишется случайное значение, потом некоторые действия и «востановление» регистра адреса сегмента стека из «стека». Что будет дальше никому неизвестно. Подобные случаи грозят очень долгой отладкой.

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


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


upd: Ввиду появления большого количества защитников «случайных» идентификаторов в таблицах БД, отвечу всем сразу: если необходимо скрыть реальные ID, нужно использовать mod_rewrite, а не коверкать БД.
Tags:
Hubs:
Total votes 79: ↑48 and ↓31+17
Comments95

Articles