К сожалению, технология отладки мало исследована. Вот еще пример пропасти между учеными и практиками. Ученые создают доказательства правильности, часто вручную, — правда, эта работа все больше автоматизируется благодаря POPLmark и подобным инструментам. Но в реальной жизни везде есть только отладчики, встречаются даже развалюхи родом из 1970-х, вроде GDB.
Сейбел: В реальной жизни есть еще разрыв между приверженцами символических отладчиков и операторов вывода?
Айк: Да. Поэтому я использую GDB и доволен тем, что в нем, по крайней мере на Маке, есть возможность поставить точку прерывания, и это обычно работает. Я могу наблюдать за адресом, могу засечь момент, когда правильные биты сменяются неправильными. Это довольно полезно. Я также использую команду printf для бисекции. Когда я уже близок к цели, то обычно пытаюсь сделать что-то внутри GDB или пользуюсь командными сценариями (скриптами), хотя они очень слабы. Язык сценариев сам по себе очень слаб. По-моему, Ван Якобсон добавил циклы, но не знаю, использовались ли они в настоящем GDB, после семинаров, организованных Фондом свободного программного обеспечения.
Однако отладчики могут сделать бесконечно больше, чем делают сейчас, и в этом смысле Chronomancer и Replay — шаг вперед. Они изменили для меня весь процесс. Но вот насчет многопоточности не знаю. Есть Helgrind и другие динамические детекторы гонок, которыми мы пользуемся. Они дают ложные срабатывания, которые надо отсеивать. С ними пока еще не все до конца понятно.
Многопоточные процессы страшат меня — до того как я женился и завел детей, они съели немалую часть моей жизни. Не все задумываются насчет параллелизма и всех возможных комбинаций команд, происходящих даже в небольших сценариях. Если ваш код соединяется с чужим, он выходит из-под контроля. Вы не можете мысленно смоделировать происходящее. Большинство людей не могут. Я мог бы стать одним из этих всезнаек с сайта Slashdot: когда я писал в своем блоге, что против многопоточности, кое-кто говорил: «Да он ничего не знает, это несерьезно». Давай, болтай. Я слетал в Австралию и Новую Зеландию, мне достались кое-какие бонусы. Но все это было так мучительно и продолжалось слишком долго. Как сказал Уайльд о социализме, «Он отнимает слишком много вечеров».
Сейбел: Как вы проектируете код?
Айк: Я много прототипирую. Создаю нечто вроде высокоуровневого псевдокода и затем постепенно заполняю его снизу вверх. Этот псевдокод я обычно не пишу, а держу в голове, и иду снизу вверх, пока оба конца не сойдутся. Часто я работаю с готовыми фрагментами кода, добавляя новую подсистему или что-то постороннее, и почти все делаю снизу вверх. Если в середине я сталкиваюсь с трудностями, то опять пишу псевдокод и начинаю работать все в том же направлении — снизу вверх, пока не закончу его. Я стараюсь не затягивать с этим, так как проверить псевдокод невозможно — надо смотреть, как он работает, выполнять его шаг за шагом, убеждаясь, что он делает именно то, чего от него ждешь.
Еще до этого этапа я могу установить кое-какие связи между объектами, вчерне набросать модули. Обычно есть два-три алгоритма, и можно прикинуть их сложность — линейная она или константная. Всякий раз, когда я выполнял поиск с линейной сложностью, который затем складывался в квадратичный, для веб-разработчиков это была проблема. Поэтому мы предпочитаем делать много структур данных с константным временем доступа. Но даже и тогда эта константа может не быть единицей — она может быть достаточно большой, чтобы о ней побеспокоиться.
Поэтому мы создаем множество прототипов, работаем над разными кусками с обоих концов, которые сводим в середине. Я считаю, что сейчас мы в Mozilla недостаточно переписываем код. Мы слишком консервативны. У нас открытый исходный код, поэтому вокруг нас создаются сообщества, мы заинтересованы в новых людях. Мы работаем в интересах пользователей и поэтому не можем позволить себе трехлетний перерыв на переписывание — хотя если очень постараться, то смогли бы.
Но если вам нужно избрать другой путь, и вы не знаете в точности какой, — переписывайте. Если хотите понять, что, черт возьми, вы тут делаете, потребуется несколько попыток. Код становится лучше по своему проектному решению, вы останавливаетесь на этой версии, начинаете ее латать, пока не дойдете до предела. Это нечто вроде эволюционного тупика для кода. Возможно, при приемлемых невозместимых издержках этот код останется на годы. А может, потребует замены. Вдруг в мире открытого исходного кода появится более совершенная стандартная библиотека?
Это возвращает нас к ремеслу программирования. Вы не просто пишете код в соответствии со старым проектным решением. Вы хотите постоянно практиковаться, а это значит думать о проектном решении кода и применять свой опыт в написании кода к этому решению.