Кодеры за работой. Размышления о ремесле программиста - Питер Сейбел
Шрифт:
Интервал:
Закладка:
Диагностировать ее было трудно, так как она была связана с синхронизацией по времени. Машины использовались не по назначению, как концентраторы терминалов. Люди подвешивали псевдотерминалы к реальным терминалам. Это делали студенты в лаборатории или сотрудники брисбенской компании, производившей ПО для горной промышленности: множество отсеков и в конце стеклянная стена, а за ней компьютеры, в том числе двухпроцессорная машина от SGI. Было нелегко, и я рад, что мы все же нашли ошибку.
Обычно такие ошибки не сидят годами, но отыскать их крайне трудно. Нужно как бы приостановить все, думать о них постоянно, видеть их во сне... А заканчивается все тем, что вы делаете элементарные вещи. Так бывает со многими ошибками. Все заканчивается бисекцией, по методу волка и забора[49]. Вы постоянно следите за выполнением, за состоянием памяти, пытаетесь прикинуть размер ошибки, течение исполнения программы, понять, к каким данным можно обратиться. Если это куча голых указателей, дело плохо: следует обратиться к более современным инструментам, которые появились вместе с гигагерцными процессорами, вроде Valgrind и Purify.
Инструментирование и наличие контролируемой модели всей иерархии памяти - это большое дело. Роберт О'Каллагэн, могучий новозеландский ум, создал собственный отладчик на базе Valgrind: он записывает каждую инструкцию, и можно в любой момент восстановить состояние программы целиком. Это не только отладчик, путешествующий во времени. Это целая база данных: вы видите структуру данных, замечаете поле с безумными значениями, выясняете, кто делал там последнюю запись. Вы идете от следствий к причинам - в отладке это занимает очень много времени. Это в тысячу раз медленнее, чем все происходит в реальном времени, но у вас есть надежда.
Можно также использовать записывающие виртуальные машины - они записывают состояние только при системных вызовах и на границах ввода/вывода. Они могут воссоздать состояние поврежденной программы на каждой границе - правда, со всем, что между границами, намного сложнее. Зато все можно закончить быстро, практически в реальном времени, потом перенести программу в Chronomancer, запустить ее в медленном темпе, воссоздать все состояния и найти ошибку.
К сожалению, технология отладки мало исследована. Вот еще пример пропасти между учеными и практиками. Ученые создают доказательства правильности, часто вручную, - правда, эта работа все больше автоматизируется благодаря POPLmark и подобным инструментам. Но в реальной жизни везде есть только отладчики, встречаются даже развалюхи родом из 1970-х, вроде GDB.
Сейбел: В реальной жизни есть еще разрыв между приверженцами символических отладчиков и операторов вывода?
Айк: Да. Поэтому я использую GDB и доволен тем, что в нем, по крайней мере на Маке, есть возможность поставить точку прерывания, и это обычно работает. Я могу наблюдать за адресом, могу засечь момент, когда правильные биты сменяются неправильными. Это довольно полезно. Я также использую команду printf для бисекции. Когда я уже близок к цели, то обычно пытаюсь сделать что-то внутри GDB или пользуюсь командными сценариями (скриптами), хотя они очень слабы. Язык сценариев сам по себе очень слаб. По-моему, Ван Якобсон добавил циклы, но не знаю, использовались ли они в настоящем GDB, после семинаров, организованных Фондом свободного программного обеспечения.
Однако отладчики могут сделать бесконечно больше, чем делают сейчас, и в этом смысле Chronomancer и Replay - шаг вперед. Они изменили для меня весь процесс. Но вот насчет многопоточности не знаю. Есть Helgrind и другие динамические детекторы гонок, которыми мы пользуемся. Они дают ложные срабатывания, которые надо отсеивать. С ними пока еще не все до конца понятно.
Многопоточные процессы страшат меня - до того как я женился и завел детей, они съели немалую часть моей жизни. Не все задумываются насчет параллелизма и всех возможных комбинаций команд, происходящих даже в небольших сценариях. Если ваш код соединяется с чужим, он выходит из-под контроля. Вы не можете мысленно смоделировать происходящее. Большинство людей не могут. Я мог бы стать одним из этих всезнаек с сайта Slashdot: когда я писал в своем блоге, что против многопоточности, кое-кто говорил: “Да он ничего не знает, это несерьезно”. Давай, болтай. Я слетал в Австралию и Новую Зеландию, мне достались кое-какие бонусы. Но все это было так мучительно и продолжалось слишком долго. Как сказал Уайльд о социализме, “Он отнимает слишком много вечеров”.
Сейбел: Как вы проектируете код?
Айк: Я много прототипирую. Создаю нечто вроде высокоуровневого псевдокода и затем постепенно заполняю его снизу вверх. Этот псевдокод я обычно не пишу, а держу в голове, и иду снизу вверх, пока оба конца не сойдутся. Часто я работаю с готовыми фрагментами кода, добавляя новую подсистему или что-то постороннее, и почти все делаю снизу вверх. Если в середине я сталкиваюсь с трудностями, то опять пишу псевдокод и начинаю работать все в том же направлении — снизу вверх, пока не закончу его. Я стараюсь не затягивать с этим, так как проверить псевдокод невозможно - надо смотреть, как он работает, выполнять его шаг за шагом, убеждаясь, что он делает именно то, чего от него ждешь.
Еще до этого этапа я могу установить кое-какие связи между объектами, вчерне набросать модули. Обычно есть два-три алгоритма, и можно прикинуть их сложность - линейная она или константная. Всякий раз, когда я выполнял поиск с линейной сложностью, который затем складывался в квадратичный, для веб-разработчиков это была проблема. Поэтому мы предпочитаем делать много структур данных с константным временем доступа. Но даже и тогда эта константа может не быть единицей - она может быть достаточно большой, чтобы о ней побеспокоиться.
Поэтому мы создаем множество прототипов, работаем над разными кусками с обоих концов, которые сводим в середине. Я считаю, что сейчас мы в Mozilla недостаточно переписываем код. Мы слишком консервативны. У нас открытый исходный код, поэтому вокруг нас создаются сообщества, мы заинтересованы в новых людях. Мы работаем в интересах пользователей и поэтому не можем позволить себе трехлетний перерыв на переписывание - хотя если очень постараться, то смогли бы.
Но если вам нужно избрать другой путь, и вы не знаете в точности какой, - переписывайте. Если хотите понять, что, черт возьми, вы тут делаете, потребуется несколько попыток. Код становится лучше по своему проектному решению, вы останавливаетесь на этой версии, начинаете ее латать, пока не дойдете до предела. Это нечто вроде эволюционного тупика для кода. Возможно, при приемлемых невозместимых издержках этот код останется на годы. А может, потребует замены. Вдруг в мире открытого исходного кода появится более совершенная стандартная библиотека?
(adsbygoogle = window.adsbygoogle || []).push({});