Сейбел: Каким образом вы решаете, что необходимо масштабное переписывание? Благодаря Джоэлу Спольски Netscape в некотором смысле стала примером того, как опасно масштабное переписывание.
Айк: В Netscape хотели, чтобы приобретенная ими компания, потрясавшая известной книгой о шаблонах проектирования, вывела их на первое место благодаря новому движку рендеринга, который стал бы для всех ориентиром. Сверху это смотрелось хорошо: там использовались C++ и шаблоны проектирования. Но было множество проблем.
А вот вторая причина того, что мы взялись за переписывание: я трудился в mozilla.org и был сильно недоволен Netscape, как и Джейми, — тот вообще собирался уходить. Я считал, что нужно пустить на наше поле новых работников, а со старым запутанным кодом, сделанным на коленке в 1994 году, сделать это было нельзя. И с моим прекрасным кодом интерпретатора в стиле ядра UNIX.
Нам нужна была большая перезагрузка. Четыре года с момента выпуска программы! Не говоря ничего такого топ-менеджерам, поскольку они и слушать об этом не желали, мы стали искать оптимальное решение за них. В итоге полетело несколько топ-менеджерских голов. Правда, менеджеры, в отличие от меня, все равно сказочно заработали на опционах. Но для Mozilla это было выгодно.
Сегодня можно назвать это удачей, поскольку развитие Сети ускорилось. Видимо, Microsoft — некоторые утверждают, что это было связано скорее с антимонополистскими расследованиями, чем с желанием его руководителей, — хотела плотно оседлать Сеть и не допустить ее эволюции. Это дало нам возможность заняться переписыванием, размахивая знаменем стандартов (довольно сомнительный ход, особенно с учетом качества стандартов). Как и Джоэл, я скептично смотрю на переписывание. Трудно примирить все интересы, найти деньги и при этом правильно отреагировать на требования рынка. Исключений единицы.
Те случаи переписывания, о которых я говорил раньше, связаны с прототипами. Это крайне важно, а объем работы намного меньше. Можно порезать кучу кода, не очень много по числу строк, но с большими последствиями, и удовлетворить всем нужным инвариантам. Или это компиляция «на лету», или еще что-то, что позволяет решить задачу.
Сейбел: Вы занимались литературным программированием в духе Кнута?
Айк: Я делал кое-что наподобие его первоначальных программ — просто классно, мне очень нравилось. Это было извлечение слов. Там было некое подобие древовидного хеша, программирование было целиком литературным. Потом Дуг Макилрой сделал все то же самое, только с конвейером.
Наши программы подробно откомментированы, но нет средства изъять из них прозу и проверить ее — хотя бы вручную — относительно кода. Разработчики Python сделали в этом смысле кое-что интересное. Все что я сделал — не более чем подробное комметирование. Я периодически обновляю старые комментарии, но это тяжело, и иногда мне это не удается, и я жалею, что кто-то из-за меня получил неверную информацию.
Сейчас мне нравятся возражения Макилроя. Это не то что полное опровержение литературного программирования, но близко к тому. Не хочется писать много — неважно, прозы или кода. В каком-то смысле, на низшем уровне код должен говорить сам за себя. На более высоких уровнях — гигантские функции, границы модулей — уже нужна документация. Документирующие комментарии, или документарные строки. Встраивание тестов в комментарии. Думаю, разработчики Python сделали тем самым большое дело.
Кое-что, как видно, пришло из литературного программирования — документарные строки, встроенные тесты. Хотелось бы, чтобы языки поддерживали больше таких вещей. Мы пытались включить встроенную документацию в ES4 через поддержку метаданных первого класса или интроспекции, но не смогли договориться между собой.
Сейбел: Вы читаете чужой код?
Айк: Это часть моей работы. Ревизия кода — обязательный шаг перед коммитом, который был когда-то необходим в основном из-за плохой кадровой политики Netscape, но мы до сих пор пользуемся им, а также делаем интеграционные ревизии. Мы устраиваем также особые «суперревизии», когда изменяется много модулей и вы не знаете всех скрытых инвариантов, которые Джо Шмо[50], который больше не работает в Mozilla, держал в своей голове. В принципе, есть люди, способные охватить взглядом целостную картину. Иногда мы обходимся без этого, когда все хорошо знают, что делают, и понимают друг друга без слов, как джедаи. Но лучше поступать так не слишком часто.
У нас нет предварительных ревизий проектных решений. Поэтому иногда такие ревизии случаются потом сами. «У тебя слишком много кода. Вернись-ка назад и сделай по-другому». Но так бывает редко. Мы не навязываем «модель водопада», жестко последовательную схему разработки. Когда я занялся программированием в начале 1980-х, она была как раз в моде, просто кошмар. Вы пишете документацию, потом код, потом понимаете, что код не годится, вы его полностью меняете — и вся документация насмарку.
Сейбел: Вы говорите о коде, который пишется для Mozilla. А вы читали когда-нибудь код не по работе, а ради самообразования?
Айк: В этом смысле открытый исходный код — потрясающая вещь. Я люблю смотреть код, который пишут люди с разных концов света, хотя посвящаю этому не так много времени. Больше всего меня привлекают серверные фреймворки, а еще такие языки, как Python и Ruby.
Сейбел: То есть их реализации?
Айк: Реализации и код библиотек. Возьмем библиотеки Ajax: приятно видеть, насколько умны могут быть люди и как с небольшим набором инструментов — замыкания, прототипы, объекты — можно создавать удобные, порой очень удобные абстракции. Нельзя сказать, что они всегда крепко скроены или безопасны, — но до чего удобны!
Сейбел: Как вы поступаете, если надо прочесть большой кусок кода?
Айк: Я начинаю «сверху». Если фрагмент достаточно велик, у вас есть указатели функций, а течение исполнения программы не слишком ясно. Иногда я пропускаю его через отладчик и терзаю таким вот способом. Я также смотрю на шаблоны низкого уровня, которые могу распознать. Если это языковой процессор или в нем есть понятные мне системные вызовы, я пытаюсь выяснить, как используются эти примитивы. Как они используются на более высоких уровнях? Это позволяет мне немного освоиться с кодом. Но по-настоящему его понимаешь, когда создается целостный образ, когда смотришь на код сверху, снизу, с разных сторон, возясь с отладчиком, пропуская через него код шаг за шагом, как бы это ни раздражало.
Если удается посмотреть, что происходит в куче — проследить указатели, пройтись по списочным ячейкам, что-то еще, — осознаешь, что это стоило труда, как бы тошно ни казалось. Для меня это так же важно, как чтение исходника. Исходник можно читать долго, можно застрять в нем, смертельно скучая и понапрасну уверяя себя, что понимаешь вон то темное место.
Создавая регулярные выражения в JavaScript, я обращался к Perl 4. Я пропускал его через отладчик и читал код. Это давало мне идеи: реализация в обоих языках оказалась схожей. Их рекурсивный характер с поиском с возвратом был немного необычен, так что пришлось поднапрячься. Удалось только отладить некоторые регулярные выражения и проследить за исполнением. Другие программисты, как я слышал, тоже говорили об этом: нелегко пробираться сквозь код, понимать, как динамическое состояние системы выглядит при беглом взгляде или при проверке базовой функциональности. Я согласен с ними.
Сейбел: Вы делаете то же самое с собственным кодом, даже если не ищете ошибку?
Айк: Разумеется, я делаю проверку на вменяемость. И делаю много операторов-утверждений, и если они срабатывают, я тут же оказываюсь в отладчике. Но иногда пишешь код, применяя разные хитрые вспомогательные схемы. Тестируешь его, он работает... пока не пропустишь его через отладчик. Особенно если в нем есть особо заумный кусок, срабатывающий, только если звезды сходятся определенным образом. Используешь условные точки прерывания, точки прерывания по изменению данных, наконец, ловишь его, когда этот код срабатывает, — ага, звезды сошлись! И понимаешь, что живешь не на планете сказок. Если, пребывая в исходном коде, вы чувствуете себя обитателем этой планеты, беритесь за отладчик. Это важно, я так всегда поступаю.
Сейбел: Вы обнаруживаете проблему, когда пробираетесь сквозь исходник, держа в уме, что должно произойти вот это и вот это, но ничего не происходит?
Айк: Да, или — это моя личная проблема — я живу на планете сказок. Сейчас я постарел, стал скептичнее, работаю лучше, но все еще настроен слишком оптимистично. В каком-то уголке моего сознания Говорящий сверчок шепчет: «Да у тебя там, должно быть, ошибка, ведь ты наверняка о чем-то забыл». Со мной так всегда.
Иногда я точно знаю это — знаю, что где-то ошибся, — и покрываюсь потом. У меня свербит не то в заднем мозгу (где это, кстати?), не то в микротрубочках. Так или иначе, я чувствую, что должен быть начеку, и отладчик помогает мне быть начеку. Он помогает мне принять решение или понять, что вот этот тест-вектор не покрывает всех комбинаций кода, так как передо мной обширное гиперпространство.
Сейбел: Кроме чтения кода многие программисты читают еще и книги по специальности. Есть ли книги, которые вы можете порекомендовать?
Айк: Мне надо было бы читать побольше. Но это как в музыке: главное — практика. Можно узнать очень многое, читая чужой код. Мне очень нравились книги Брайана Кернигана, написанные предельно логично — написать небольшой фрагмент кода, использовать его заново по мере продвижения, строить модули. Еще «Искусство программирования» Кнута, тома 1-3, особенно та часть, где говорится о получисленных алгоритмах. Двойное хеширование — я люблю эти главы. Лемма о золотом сечении, которую требуется доказать в качестве упражнения.
Но, по-моему, по книгам не слишком-то научишься программировать. Программирование отчасти близко инженерному искусству: в один прекрасный день может понадобиться математика. И есть куча практических вещей, которые даже не поднимаются на уровень инженерного искусства, как оно понимается в строительстве и технике. Возможно, со временем все это чуть больше формализуется.