Дэна Мерфи и ждать, пока он прочтет мне лекции по CONS, CDR и CAR.
Сейбел: Как вы считаете, есть ли разделы формальной компьютерной науки, которые непременно должен изучить будущий программист?
Козелл: Конечно, и таких немало. Какой-нибудь курс по объектно- ориентированному программированию в абстрактом ключе, хотя во многих учебных заведениях с этим очень плохо. В университете, где я читал лекции, мне пришлось повоевать с другими преподавателями по поводу использования C++ при обучении объектно-ориентированному программированию. Я спрашивал их, уверены ли они, что студенты смогут отделить философскую концепцию объектно-ориентированного программирования от странных особенностей того же C++ как ее прикладного воплощения.
В книге Кнута есть и много других полезных вещей. Я окружен людьми, для которых списки - это что- то из области магии. Они не знают ничего о 83 типах деревьев и о том, чем одни лучше других. Они не понимают ничего в сборке мусора. Они не разбираются в структурах и методах.
Или взять сортировку и поиск. Если в языке программирования нет функции сортировки, они ничего не будут знать о разных методах сортировки, о поиске, о том, когда надо строить индексы, не будут понимать, что значит “наша база данных хранит данные в виде В-дерева”. В хорошем курсе обучения, я считаю, нужно не просто объяснить, как, к примеру, создать связный список в Си - это чисто техническая задача, - но и рассказать о принципах работы связных списков вообще.
Сейбел: Среди самых известных проектов, в которых вам приходилось участвовать, был ARPANET. Вы, Уилл Кроутер и Дэйв Уолден писали программное обеспечение к первым компьютерам IMP новой сети. Как вы попали в этот проект?
Козелл: Наш руководитель Фрэнк Харт относился к своему отделу как к своеобразному инкубатору молодых программистов. Он передвигал людей из проекта в проект. Когда один мой проект заканчивался, он решал, куда меня затем направить. Настоящие консультанты начинали свою работу с командировок в Вашингтон и написания техзаданий; я, однако, был далек от этого. Тем не менее Фрэнк решил поставить меня третьим специалистом в проект IMP.
Осенью 1968 года, когда начали работать Дэйв, Уилли и остальные, я работал над другим проектом. Думаю, мой контракт был делом решенным, но к работе я приступил только в январе. К этому моменту сделано было не так много. Помнится, ребята написали часть кода, но ничего еще не работало. Когда я пришел, Дэйв и Уилли как раз начали вчерне разрабатывать алгоритм работы всей системы в целом и делить фронт работ. Я тоже попросил себе кусок-другой. Как программисты мы все были очень разные, но каждый должен был точно знать, как работает каждая строка кода, в том числе потому, что это была относительно небольшая программа. Сложная, но небольшая.
Я знал, что к моему приходу они не могли далеко продвинуться, потому что процесс ассемблирования у них не был автоматизирован. Им приходилось нести перфоленту в комнату с Honeywell 516 и прогонять через него всю эту перфоленту, чтобы получить распечатку, набивая для этого целую коробку перфоленты, которую они потом несли к другой машине, потому что к Honeywell не был подключен строковый принтер, чтобы распечатать результат ассемблирования. Программировать так было очень утомительно. Первое, что я сделал в рамках проекта, - написал кросс-ассемблер для нашего PDP-1.
После этого на PDP-1 появилась возможность редактировать файлы, ассемблировать их, распечатывать результат, запускать ТЕСО-макросы и так далее. Единственное, что надо было набивать, - относительно небольшая бинарная исполняемая программа, которая предназначалась для машины Honeywell.
Сейбел: Что было самым трудным в написании программ для IMP - заставить их работать быстрее?
Козелл: Интересный вопрос. Так, давайте посмотрим. Мы не слишком много думали о размере программы - предполагалось, что в системе будет достаточно памяти для буферизации. И что кода будет не так уж много. Если бы он был, скажем, на 10% больше, чем он получился в итоге после максимального сжатия, рабочих буферов памяти стало бы немногим меньше. Поэтому мы не беспокоились о том, сколько инструкций все займет.
Сейбел: То есть какой объем.
Козелл: Да. Какой объем. Но нас чрезвычайно заботила скорость, поскольку приходилось учитывать пропускную способность. Перед нами стоял вопрос: как организовать систему, чтобы она была отказоустойчивой и сама восстанавливала свою работу, вместо того чтобы умереть?
Второй проблемой было заставить все это работать. В системе было много новых, непроверенных элементов. Мы не знали заранее, будут ли работать протоколы. Уилл предложил несколько новых идей, связанных с алгоритмами маршрутизации, - будут ли они удачными? Таких вопросов было очень много. Например, по поводу отслеживания заторов. Могли ли мы быть уверены, например, в том, что если пользователи всего мира отправят пакеты одному бедолаге, то мы сможем отбрасывать их в правильном порядке, не дав ему утонуть?
Сейбел: С подобными проблемами до вас никто не сталкивался?
Козелл: Совершенно верно. Это был в то же время и исследовательский проект - много новой теории. Было написано несколько диссертаций, многие думали, что разбираются в вопросе. Пришло время воплотить эту теорию на практике. Нам предстояло увидеть, работают ли теория очередей и алгоритмы маршрутизации на самом деле.
Третьим большим вызовом была отладка системы, устранение неисправностей. Например, внезапно пропала связь с городом Цинциннати (штат Огайо). Что случилось? Как это исправить? Звонишь в Цинциннати, а тебе отвечает заспанный ночной охранник - там сейчас три часа ночи. Нужно, чтобы он поднялся и посмотрел на ту мигающую коробочку в углу. Что он расскажет? Что с этим делать? Даже если система вновь заработала, как выяснить, что пошло не так? Как избежать этой проблемы в будущем? Не забывайте, что я считался великим-отладчиком-всего-и-вся, мастером-на-все-руки.
Помню, как был удивлен Уилл, когда я нашел в программе ошибку, которую не мог найти никто. Она скрывалась в одном из модемных протоколов и посылала неправильный пакет в неправильное время. Я сделал несколько заплаток, так что смог поместить маркер в пакет, и когда программа замечала тот самый пакет, она устанавливала в систему заплатку, которая наблюдала за соответствующей операцией и при ее выполнении останавливала работу системы. После этого можно было запустить отладочные программы, чтобы выяснить, что произошло. Как только я все это сделал, поиск бага занял две минуты, так как вредоносный пакет все еще находился в памяти и не был затерт другой информацией.
Была еще одна проблема из разряда неприятных, но не смертельных. Порча памяти из-за неправильного указателя. Сама по себе порча была незначительной, но спустя несколько тысяч машинных циклов программа вылетала, потому что одна из структур данных оказывалась поврежденной. Та поврежденная структура данных использовалась постоянно, поэтому мы не могли просто добавить в код команду “Остановить программу, когда она изменится”. Я немного поразмыслил и наконец придумал двух- или трехступенчатую систему заплаток. Как только память портилась, первая заплатка активировала вторую, которая работала с другой частью кода. Это, в свою очередь, активизировало запись третьей заплатки в еще один участок. Наконец, когда эта третья заплатка замечала, что происходит что-то не то, она останавливала систему. Я придумал, как откладывать проверку до нужного момента с помощью такой динамической системы заплаток. К счастью, это сработало, и мы смогли быстро устранить неполадку.
Сейбел: Что наталкивает на подобные удачные идеи?
Козелл: Если я досконально разобрался в системе, будь то ПО для IMP или система разделения времени для PDP-1, несмотря на то, что она мультипрограммная, многослойная и основана на работе с прерываниями, все равно вся ее динамика находится у меня в голове. Я знаю, что и в каком порядке должно происходить и что не должно происходить. Это позволяет всегда представить примерную модель происходящего.
Надо сказать, что многие из возникавших тогда проблем относились к двум разным моделям компьютеров, и их анализ требовал недюжинной фантазии. Например, что-то происходит не так на первой машине, а последствия проявляются на второй. Я не могу остановить работу, первая машина уже обработала на 6000 пакетов больше, чем вторая, и вдруг вторая говорит, что один из пакетов поврежден. Что тогда делать? Всем нам троим приходилось садиться и прослеживать весь процесс в ретроспективе, чтобы найти ошибку и “вылечить” систему.