Джоэл Сполски. Работа над ошибками малой кровью.
Работа над ошибками малой кровью Автор: Джоэл СполскиПереводчик: Александр Башков Редактор: Юрий Удовиченко 8 ноября 2000 годаПервые версии интерпретатора языка BASIC на компьютере TRS-80 позволяли заводить только две строковые переменные, A$ и B$. По его образу и подобию я был произведён на свет только с двумя ячейками для хранения информации об ошибках в голове. Одновременно я могу помнить информацию только о двух ошибках в программе. Если вы попросите меня запомнить третью, то какая-нибудь из трёх обязательно упадёт на пол, закатится под диван и затеряется там в реликтовых залежах пыли.Ведение базы данных ошибок в программе - один из признаков хорошей программистской команды. Не перестаю удивляться тому, как редко разработчики прибегают к этому. Одно из типичных программистских заблуждений — это вера в то, что можно сведения о всех ошибках удержать в памяти или на отрывных листочках.Если вы позволите мне отнять немного вашего времени, я расскажу вам о приятном, совершенно безболезненном способе отслеживать ошибки в программах в духе предыдущих статей: "графики работ малой кровью" и "спецификации малой кровью". Прежде всего вам понадобится база данных (СУБД). Команда из двух человек, пописывающих чуть-чуть кода по выходным, вероятно, удовлетворится простым текстовым файлом. Более крупной команде уже потребуется настоящая система отслеживания ошибок. В настоящий момент продается несчётное количество подобных продуктов. (Беззастенчивая самореклама: одну из них — FogBUGZ — написали мы в Fog Creek Software. Это веб-ориентированная, несложная в использовании и достаточно мощная программа). Давайте последим за какой-нибудь ошибкой от момента рождения до конца её бренного пути. Возьмём для примера ошибку 1203. Вот какую информацию о ней выдаёт база данных: ID-Номер 1203 Проект Bee Flogger 2.0 Раздел Ftp Клиент Название Загрузка файла роняет ftp сервер Назначено Закрыто Статус Закрыто-Решено-Исправлено Важность 2 - Необходимо исправить Архитектура 2.0 Alpha Версия Сборка 2019 Компьютер Макинтош iMac Джилл. MacOS 9.0, 128Mb ОЗУ, 1024x768, миллионы цветов Описание 1 ноября 2000 Открыто Джилл, очень-очень хорошим тестером. * Запустить Bee Flogger* Создать новый документ без имени содержащий букву "а"* Щёлкнуть кнопку ftp на панели* Попробовать загрузить документ по ftp на сервер ОШИБКА: ftp сервер не отвечает.Команда ps -augx показывает, что ftp сервер вообще не выполняется.В корневом каталоге содержится дамп памяти. ТРЕБУЕТСЯ: ftp сервер не должен падать.1 ноября 2000 Джилл, очень-очень хороший тестер, поручила работу над ошибкой Вилли, ведущему разработчику. 2 ноября 2000 (вчера) Решено - Исправлять не будем - Вилли, ведущий разработчик. Не наш код, Джилл. Это proftpd, входящий в поставку Linux. 2 ноября 2000 (вчера) Возобновлено (поручено Вилли, ведущему разработчику) Джилл, очень-очень хоршим тестером. Неубедительно. Мне никогда не удавалось уронить proftpd другими ftp клиентами. Наш же клиент роняет его каждый раз. Ftp серверы сами по себе не падают. 3 ноября 2000 (сегодня) Вилли, ведущий разработчик поручил работу над ошибкой Майку, простому программисту. Майк, взгляни-ка сюда. Может твой код в клиенте делает что-то не то? 3 ноября 2000 (сегодня) Решено - Исправлено. Майк, простой программист. Я думаю, что я передавал имя пользователя вместо пароля или что-то типа того... 3 ноября 2000 (сегодня) Реактивировано (поручено Майку, простому программисту) - Джилл, очень-очень хорошим тестером. Всё то же самое в 2001-й сборке. 3 ноября 2000 (сегодня) Отредактировано Майком, простым программистом. О как! Очень странно. Надо будет взглянуть внимательнее. 3 ноября 2000 (сегодня) Отредактировано Майком, простым программистом. Мне кажется это в MikeyStrCpy()... 3 ноября 2000 (сегодня) Решено - Исправлено Майком, простым программистом. Уфффф!!! Исправлено! 3 ноября 2000 (сегодня) Закрыто Джилл, очень-очень хорошим тестером. Похоже-таки исправлено в сборке 2022 - закрываю. Итак, вот что произошло. Майк, простой программист, колдовал над новой возможностью своей превосходной программы для макинтошей: ftp клиентом. В один прекрасный момент из хулиганских побуждений он написал свою собственную функцию копирования строк. Вот им за их дурацкое требование повторного использования кода! Ха-ха-ха! Беда приходит нежданно, Майк, когда ты не используешь повторно код! На этот раз никто не ждал, что Майк забудет завершить копируемую строку нулём. И ошибка осталась незамеченной, потому что при отладке строка копировалась в заранее обнулённую область памяти.Позже на той же неделе, Джилл, очень-очень хороший тестер, терзала код, нажимая все клавиши подряд и выполняя другие, столь же коварные тесты. (По странному совпадению, практически всех хороших тестеров зовут Джилл или в крайнем случае Джиллиан). Внезапно произошло что-то очень странное — ftp сервер, на котором она проверяла клиента, упал! Да, я знаю, что это был Линукс, а компьютеры под Линуксом никогда не падают (только вот не надо фыркать, вы не на slashdot'е), но эта чёртова штука таки упала! А ведь Джилл даже не дышала на ftp сервер. Она просто пыталась загрузить на него файл, используя код для Mac-а, написанный Майком. Поскольку Джилл была очень-очень хорошим тестером, она аккуратно вела запись всех своих действий. Она перезагрузила всё, что было можно. Начала повторять свои действия на чистой машине, и — гляньте-ка — это случилось снова! Ftp сервер опять упал! Дважды за один день! Вот тебе, Линус! Джилл взглянула на запись своих действий. Там было порядка двадцати шагов. Некоторые из них, похоже, не имели отношения к проблеме. После некоторых экспериментов Джилл сократила число действий до четырёх, которые всегда вызывали ошибку. Теперь она была готова описать ошибку.Джилл ввела информацию об ошибке в базу данных. Кстати, даже сам процесс записи информации об ошибке требует определенной дисциплины: бывают хорошие описания, а бывают и плохие.Три составные части хорошего описания ошибкиИ говорил Господь, и сказал Он: "Сначала следует тебе вынуть чеку святую. Затем следует сосчитать до трёх, не более и не менее. Три — число, до коего должен ты считать; и количество счёта твоего должно быть три. До четырёх не следует считать, а равно и до двух, кроме как ежели после двух последует три. Пять категорически исключается. И когда число три, будучи по счёту третьим числом, достигнуто будет, не сумняшеся метни Святую Гранату Антиохову во врага своего, который, будучи грешен передо Мною, ласты-то и склеит."Монти Питон и Святой ГраальЗапомнить правила составления хорошего описания ошибки совсем нетрудно. Каждое хорошее описание ошибки должно содержать ровно три вещи: Какие шаги привели к ошибке. Что вы ожидали увидеть. Что вы в самом деле увидели. Просто, да? Увы, нет. В бытность свою программистом я периодически получал описания ошибок, где отсутствовала та или иная часть.Если вы не расскажете мне, как воспроизвести ошибку, я, наверное, просто не пойму, о чём вы вообще говорите. "Программа виснет и оставляет на столе дурно пахнущий объект, похожий на мешок навоза". Отлично, дорогой. Но я ничем не смогу тебе помочь, пока ты не расскажешь мне, что именно ты делал. Хочу отметить, что существуют две ситуации, в которых трудно точно воспроизвести действия, ведущие к ошибке. Бывает, что просто никак не вспомнить, какие именно шаги привели к ошибке, или, бывает, информацию об ошибке вам прислали из полевых условий. (Какие ж они полевые? Ни пшеницы, ни васильков. Ну да ладно.) Вторая ситуация — это когда ошибка воспроизводится не каждый раз. Но и тут стоит составить перечень действий, отметив, что ошибка происходит не всегда. В этих случаях бывает очень сложно локализовать ошибку, но попробовать можно.Если вы не опишете, чего ожидали, я могу не понять, почему это, собственно, ошибка. На заставке следы крови. И что с того? Может быть я порезал палец, когда кодировал это место. А вы чего ожидали? А-а-а! Вы говорите, в спецификации написано "без крови"? Ну тогда понятно, почему вы решили, что это ошибка.Часть три. Что вы в самом деле увидели. Если вы мне не расскажете об этом, я и не узнаю, в чём же ошибка. Ну, это и так понятно.Вернемся к нашим баранамКороче, Джилл ввела информацию об ошибке. В хорошей системе учёта ошибок работа над ошибкой автоматически поручается ведущему разработчику проекта. И в этом кроется вторая идея — ошибкой, пока она не закрыта, в каждый заданный момент времени должен заниматься только один человек. Ошибка подобна горячей картофелине — если она у вас, или сами ею занимайтесь, или перекиньте кому-нибудь ещё.Вилли, ведущий разработчик, взглянул на описание ошибки и решил, что, вероятно, что-то не в порядке с ftp сервером, и пометил её как "исправить невозможно". В конце концов, не они же писали код ftp сервера.Когда ошибка разрешена, она назначается обратно тому, кто открыл её. Это важный момент. Ошибка не исчезает только потому, что программист так решил. Золотое правило гласит, что закрыть ошибку может только тот, кто её открыл. Программист может только "решить" ошибку, в смысле — "ага, я думаю, ошибка исправлена", но реально закрыть ошибку и убрать её из списка может только человек, увидевший её впервые. Только он может подтвердить, что ошибка в самом деле исправлена, или согласиться с тем, что по каким-либо причинам исправить её невозможно.Джилл получила е-мэйл: ошибка опять вернулась к ней. Она посмотрела комментарии Вилли. Что-то ей показалось неверным. Куча народа годами использует этот ftp сервер с различными приложениями, и он не падает. Это происходит только когда используется код Майка. Джилл реактивировала ошибку, объяснив своё решение, и вернула её на рассмотрение Вилли. Вилли поручил ошибку Майку для исправления.Майк изучил ошибку, думал долго и упорно, но, тем не менее, сделал неверные выводы. Он исправил несколько несвязанных между собой ошибок и решил, что в их число попала ошибка Джилл. Ошибка вернулась к Джилл с описанием "решена-исправлена". Джилл попробовала повторить шаги, ведущие к ошибке, и глядите-ка, ftp сервер опять упал. Она опять реактивировала ошибку и теперь поручила её исправление непосредственно Майку.Майк был озадачен, но, в конце концов, он-таки нашёл источник ошибки. (Догадались, что это было? Я оставлю ответ на этот вопрос в качестве домашнего задания читателю. В тексте содержится достаточно подсказок). Он исправил её, проверил, и — эврика! Ftp сервер больше не падал. Опять он пометил ошибку как "решено-исправлено". Джилл тоже повторила все действия, приводившие к ошибке, и убедилась, что ошибка исправлена. После этого она с чистой совестью закрыла её.Десять рекомендаций для успешного отслеживания ошибокХороший тестер должен всегда стремиться сократить до минимума число действий, необходимых для воспроизведения ошибки. Следование этому правилу может оказать неоценимую помощь программисту, который будет искать эту ошибку. Помните, что закрыть ошибку может только тот, кто её открыл. Кто угодно может решить её; но только тот, кто первым увидел ошибку, может быть уверен, что то, что он видел - исправлено. Существует много способов разрешить ошибку. Программа FogBUGZ, например, позволяет сделать это следующими способами: исправлена, не подлежит исправлению, отложено, не воспроизводится, повторная, особенность дизайна. Не воспроизводится — значит, что никто не смог воспроизвести ошибку. Программисты часто используют этот вердикт, если в описании ошибки опущены шаги для воспроизведения ошибки. Вы должны аккуратно отслеживать версии программы. Каждая сборка программы, которая передается тестеру, должна иметь номер версии, чтобы несчастный тестер не проверял ошибку, которая и не должна быть исправлена в этой версии. Если вы программист, и вам не удается сподвигнуть тестеров на использование базы данных учёта ошибок, перестаньте обращать внимание на информацию об ошибках, переданных вам в любой другой форме. Если ваш тестер присылает вам информацию об ошибке по электронной почте, отправляйте его письма обратно с короткой припиской: "пожалуйста, поместите эту информацию в базу данных. Я не имею возможности отслеживать информацию об ошибках, поданных с помощью электронной почты". Если вы тестер, и у вас проблеммы с программистами, которые не используют базу данных учёта ошибок, не давайте им информацию об ошибках ни в какой другой форме. Помещайте информацию в базу данных, она сама сообщит им об этом через электронную почту. Если вы программист, и некоторые из ваших коллег не используют базу данных учёта ошибок, начните назначать им ошибки через базу. В конце концов, до них дойдёт. Если вы менеджер, и вам кажется, что никто не использует базу данных учёта ошибок, которую вы выбили большой кровью, начните назначать программистам новые задачи в форме ошибок. Система отслеживания ошибок также является отличным средством учёта заданий. Избегайте соблазна добавить новые поля в базу данных. Примерно раз в месяц кому-нибудь в голову приходит "светлая" идея добавить к базе данных новое поле. Вам приносят самые разные мудрые идеи, например: указывать файл, в котором обнаружена ошибка; или вести учёт, в каком проценте повторов ошибка воспроизводится; вести учёт версий всех DLL, которые были запущены на компьютере, когда произошла ошибка; и так далее. Очень важно не поддаваться этим идеям. Иначе рано или поздно экран ввода информации об ошибке будет представлять собой форму с тысячью полей, которые необходимо заполнить, и никто не будет вводить эту информацию. Чтобы база данных учёта ошибок приносила толк, ее должны использовать все. И если ввод информации об ошибке будет требовать слишком больших усилий, люди найдут обходные пути. Если вы пишете код, пусть даже в одиночку, и не ведёте систематизированный учёт всех найденных в коде ошибок, вы обречены поставлять низкокачественный продукт. В хороших командах база данных учёта ошибок не просто используется, это становится привычкой. И программисты начинают её использовать для поддержки своих рабочих планов, список назначенных им ошибок делают стартовой страницей своего браузера. И в конце-концов, многие начинают мечтать о тех временах, когда можно будет поручить завхозу ликвидацию ошибки по отсутствию пива в ближайшем холодильнике.