Я уж думал, что совсем свихнулся. Моя числодробилка периодически показывает, какую итерацию она сейчас считает. Запустил, понял, что надо бы немного поменять алгоритм. Нажал Ctrl+C, поправил код, снова пускаю. Пишет:
а = -1 а = -0.9 а = -0.8 а = 0.3 а = -0.7
И почему же она на 0.3 скакнула, а потом вернулась обратно на –0.7 вернулась? Опять жму Ctrl+C, снова лезу в алгоритм, всё просматриваю — не может такого быть! Я этот код долго вылизывал, нечему там ломаться. Запускаю по новой.
а = -1 а = -0.9 а = 0.6 а = -0.8 а = -0.7 а = 0.7
Такого не может быть, потому что такого не может быть никогда! Я поиском по коду смотрел — переменная меняется только в строчке «for a = -1:0.1:1». Понял, в чём было дело, только когда появилось сообщение «запущенный в бэкграунде процесс завершён». Я случайно не прервал выполнение программы, а отправил её в фон, откуда она и посылала мне свои «приветы».
Пару лет назад мы небольшой командой энтузиастов занимались настройкой геймерских серверов в локалке. Юзеры очень уж просили поставить World Of Warcraft — игра тогда вызывала у всех дикие восторги, а оплачивать это дело народ, как водится, не хотел.
Думаю, понятно, что родного близзардовского сервера у нас не было, но суровые разработчики-единомышленники со всего интернета уже давно пытались анализировать протокол обмена клиента с официальным сервером и методом реверс-инжиниринга слепить свой. В итоге получались относительно рабочие, но страшно глючные поделки, на которых пользователи, как ни странно, охотно играли. Одну из таких поделок мы и решили поставить у себя.
Об «особенностях» игры на нашем сервере можно рассказывать очень долго. Мелочи вроде того, что мобы набрасывались на игрока через стену, ползали как альпинисты по скалам или, провалившись сквозь землю, пускали заклинания прямо из преисподней, — далеко не самые весёлые моменты.
У магов в WoW есть заклинание «полиморф», превращающее цель в овцу на какое-то время. Пока чары не спадут, жертва может только бегать и блеять. Однажды игрок из Альянса превратил в овцу игрока-неприятеля из Орды, после чего овца вдруг резво забралась на ездовую лошадь и, пристроившись сверху в интересной позе, поскакала по своим делам. Картина была шедевральная. Пока разработчики долго боролись с багом, довольные юзеры хихикали, снимая скриншот за скриншотом.
Меня всегда удивляло, что код комментируют так сухо и бездушно. Привожу пример моих комментов одной VBA-процедуры, написанных в разные моменты времени:
Первая версия:
/* Сделано через жопу. Прошу прощения у того, кто будет дорабатывать — меня заставили сделать именно так. */
Исправленная версия:
/* Cобрался с силами и исправил код так, чтобы он выглядел более логичным и читаемым. Концептуально он остался жопой, но теперь стал больше похож на аппетитную женскую попку, чем на суровую мужицкую задницу. */
Комментирование — занятие крайне интересное и творческое. Сделайте немного интереснее жизнь человеку, которому придётся потом разбираться в вашем коде!
В своей деятельности я придерживаюсь инженерного подхода, а не научного. Но вот сомнения стали одолевать...
Лет пять назад выпала мне халтурка — написать парсер не сильно прямого языка — объектно-ориентированного расширения SQL. Порекомендовали меня одной конторе, поскольку их штатный программер просидел над этим делом год, нарисовал много схем и, доказав, что это контекстно-зависимая и не LR грамматика, заявил, что быстро написать парсер — дело неподъемное.
Я не стал научно доказывать возможность или невозможность, выкинул ANTLR, взял старый добрый bison написал на коленке грамматику, добавил ручками переключение контекстов... Неделя работ. Остальные два месяца занимался стилем форматирования выходного файла.
А потом задумался. Штатный программер получил никак не меньше 15000 баксов, и работа осталась "неиспорченной". Такую работу можно было еще работать и работать. А я, как урод, решил проблему за жалкие 2 штуки. Ну и кто после этого дурак?
Случилось это в стародавние времена, когда даже «спектрумы» ещё не появились на просторах нашей необъятной родины, а отдельные энтузиасты толкали в массы вычислительную технику, собранную на суперсовременном процессоре K580ИК80. Происходило всё это в общаге, где у одного энтузиаста был собран такой монстр. Работал на нем BASIC, причём довольно неторопливо.
Пришел как-то к нам в комнату знакомый — тут ли, спрашивает, водится компьютер? Получив положительный ответ, попросил посчитать на нем задачку. Ввод исходников занял где-то полчаса, после чего состоялся пробный запуск. Программа ушла глубоко в себя и не подавала признаков жизни.
На вопрос, чего он такого напрограммировал, товарищ рассказал, что ему надо посчитать плотность плазмы в ТОКАМАКе. Когда у нас прошел первый шок от серьёзности задачи, ему посоветовали урезать количество итераций в программе, чтобы закончить расчёты в этой пятилетке, и вывести на экран обратный отсчет, чтобы можно было спокойно сходить пообедать или хотя бы попить чайку.
Настал момент боевого запуска. Программа стартует, на экране появляется четырёхзначное число, постепенно уменьшающееся. Народ ждёт, болтает, счетчик тикает. Когда пошёл отсчёт последнего десятка, внимание всей комнаты было приковано к экрану. Постепенно стихли разговоры и повисла напряженная тишина. На цифре «4» можно было услышать, как на другом конце общежития летает муха.
Три. Два. Один. (Все напряглись, как будто сейчас должно рвануть). Ноль. (Гробовая тишина).
Минус один. (Тишина, общий шок). Минус два. (Взрыв хохота).
На минус трёх программа начала строить графики, но смеялись мы ещё долго.
Мы давно уже собираемся со знакомыми программистами: чайку попьём, поболтаем, программку вместе напишем. На очередную встречу один из наших прибегает с флешкой и кричит: «Народ, срочно надо программу доделать!»
Написать ему надо было физический симулятор каучукового попрыгунчика. На флешке уже была небольшая заготовка; все собрались, стали помогать, и через час наступило время тестирования.
Всё шло нормально, пока кто-то не решил запустить шарик так, чтобы он, отскочив от пола, ударился об угол. После столкновения попрыгунчик начинал как-то совершенно неестественно скакать на одном месте.
Начался кропотливый двухчасовой безуспешный дебаг. Мы были столь поглощены поиском ошибки, что даже не заметили, как застенчивый, новенький в нашей компании программист тихонько куда-то отошёл и вернулся с настоящим попрыгунчиком.
Оказалось, что мячик действительно скачет настолько странно. Словами не передать, как мы радовались! С тех пор запомнили крепко: физические процессы при возможности надо тестировать вживую.
Делали один проект на Flash. После сдачи проекта и отправки исходников заказчику получили от него следующее письмо:
...И ещё немного смущает movie clip с красной надписью «Х*Й!» (дико извиняюсь). Очень хотелось бы узнать предназначение данного объекта.
Хотел бы добавить, что SWF — это декомпилируемый исходник, и, по моему мнению, комментарии с матом внутри кода, а также переменные с названиями fuck и eblan как минимум не отражают суть их назначения и, конечно же, не являются оптимальными.
Мне бы очень не хотелось, чтобы при разборе более продвинутыми пользователями нашего SWF-файла были найдены такие «оплошности».
Лабораторная по предмету «Операционные системы», тема — batch-файлы. Мы с другом выполнили все задания, ждем, когда препод соизволит их проверить. От скуки был написан virus.bat: :A start cmd goto A
Результат — растущая куча окошек DOS. «Вирус» тут же был оптимизирован: start cmd call virus
Нет предела совершенству, и код был сжат до одной строки: start virus
Также была написана версия с повышенной жестокостью: start virus /REALTIME /ABOVENORMAL call virus
Теперь каждое созданное окно начинало безудержно плодить новые окна. Компьютер печально вис через пару десятков секунд. Тут же была разработана вакцина vaccine.bat, убивавшая все окна: taskkill /F /T /IM cmd*
Ради интереса в начало вакцины была добавлена строчка start vaccinе. После чего начались «войны в памяти» — мы запускали вакцину и какой-нибудь из вирусов и наблюдали, кто кого победит.
Серьёзный космический проект. Интегрируется система дифференциальных уравнений движения спутника. С точки зрения программеров — примитивное консольное приложение, которое периодически выводит в левый верхний угол экрана время, в течение которого летает спутник, и его координаты. Все данные мы сверяем с аналогичной программой, созданной в другом институте — так сказать, проверяем друг друга на вшивость.
Всё бы хорошо, но время от времени спутник «прыгает назад» во времени часов на двенадцать. При этом в каждый момент времени он по нашим расчётам находится там, где и должен быть — вроде как ошибок нет.
Однако временные скачки напрягают, и после изучения кода я таки нахожу баг — даже и не баг, а глупую опечатку. Исправляю, запускаю прогноз движения... и спутник «улетает» со свехсветовой скоростью за пределы галактики!
Восстанавливать старый код смысла нет. Продолжаю поиски и через час нахожу второй баг, который полностью компенсирует влияние первого. Между двумя ошибками и стоял оператор вывода информации на экран.
С тех пор я помню: при отладке программер, как правило, наблюдает сложный результат интерференции нескольких багов и исправление одного из них не всегда меняет ситуацию в лучшую сторону.