Лисп-хакер, один из первых разработчиков Netscape и владелец ночного клуба, Джейми Завински (Jamie Zawinski, JWZ) принадлежит к той избранной группе хакеров, которых узнают как по настоящим именам, так и по трехбуквенным инициалам.

Завински начал программировать еще подростком — поступил в лабораторию искусственного интеллекта при университете Карнеги-Меллона в качестве программиста на языке Лисп. Пробыв в колледже ровно столько, чтобы его возненавидеть, он около десяти лет проработал в мире Лиспа и искусственного интеллекта, удивительным образом погрузившись в умирающую хакерскую субкультуру, пока другие программисты, его сверстники, вырастали на микрокомпьютерах.

Он работал в Калифорнийском университете в Беркли с Питером Норвигом, который описал его как «одного из лучших программистов, которых он когда-либо нанимал», а затем в Лисп-компании Lucid, где участвовал в разработке редактора Lucid Emacs, позже переименованного в XEmacs, которая в итоге пришла к большому расколу проекта Emacs — одному из самых известных в истории свободного ПО.

В 1994 году он наконец покинул компанию Lucid и мир Лиспа и перешел в Netscape, где стал одним из первых разработчиков UNIX-версии браузера Netscape Navigator, а позже — почтового клиента Netscape.

В 1998 году Завински, как и Брендан Айк, стал одним из основателей mozilla.org — организации, которая занималась переводом браузера Netscape в проект с открытым исходным кодом. Однако год спустя, разочарованный в отсутствии прогресса на пути к выпуску продукта, он покинул проект и приобрел ночной клуб DNA Lounge в Сан-Франциско, которым владеет до сих пор. В настоящее время Завински отдает все свои силы борьбе с Калифорнийским управлением по контролю за потреблением алкоголя, рассчитывая превратить клуб в место встречи любителей живой музыки всех возрастов.

В этом интервью мы среди прочего говорим о том, почему C++ — отвратительный язык программирования, о радости оттого, что миллионы людей используют созданные тобой программы, а также о том, как важно «пинать» подающих надежды программистов.

Сейбел: Как вы научились программировать?

Завински: О, это было так давно, что я едва помню. Впервые я использовал компьютер для программирования, наверное, в восьмом классе. У нас было несколько компьютеров TRS-80, и мы дурачились с Бейсиком. По-моему, это вообще были внеклассные занятия. Помнится, невозможно было даже сохранять программы, так что мы просто вводили те, что печатались в журналах и так далее. Затем я прочел стопку книг. Помню, я читал книги по языкам, которые не мог использовать на наших компьютерах, и писал на бумаге программы на языках, о которых только прочитал.

Сейбел: Что это были за языки?

Завински: Один из них — APL. Я прочел статью про него и подумал, что это классный язык.

Сейбел: Ну да, не нужно иметь навороченную клавиатуру. А в старших классах были компьютерные уроки?

Завински: В старших классах мы изучали Фортран. И все.

Сейбел: Как же вы пришли к Лиспу?

Завински: Я читал много фантастики. Мне казалось, что искусственный интеллект — это действительно классно, что компьютеры скоро покорят мир. И я решил почитать что-нибудь еще на эту тему. У меня в старших классах был приятель, Дэн Зигмонд, мы обменивались книгами и поэтому оба выучили Лисп. Однажды он пошел на встречу группы пользователей компьютеров Apple в Университете Карнеги-Мел-лон — там можно было просто обменяться программами, и Дэн надеялся добыть кое-что бесплатно. Он разговорился с каким-то студентом колледжа, и тот сказал: «Ого, пятнадцатилетний парень, который знает Лисп, — это фантастика. Спроси Скотта Фальмана насчет работы». Дэн так и поступил. Фальман взял его на работу. Тогда Дэн сказал: «Возьмите и моего друга», — то есть меня. Так что в итоге мы оба оказались у Фальмана. Думаю, он размышлял примерно так: «Раз уж эти школьники интересуются такими штуками, не будет большого вреда, если они поболтаются в лаборатории». Нам поручили самую простую грязную работу — надо было что-то перекомпилировать, когда выходила новая версия компилятора, и попробуй пойми, как это делается. Просто жуть. Представьте: двое ребят-школьников, а вокруг аспиранты занимаются языками программирования и искусственным интеллектом.

Сейбел: Значит, запустить программу на Лиспе вам впервые удалось в Карнеги-Меллоне?

Завински: Пожалуй, да. Какое-то время мы дурачились с языком XLISP, который использовался на Маках. Хотя, думаю, это было позже. Я там по-настоящему научился программировать (на рабочих станциях PERQ, установленных для проекта Spice) на языке Spice Lisp, который затем стал языком CMU Common Lisp. Странное это было место. Мы узнавали, что такое разработка программного обеспечения, на ежедневных собраниях — просто слушали и все. Но встречались и действительно забавные персонажи, например парень, который был кем-то вроде нашего менеджера — присматривал за нами. Звали его Скеф Хоу-ли — этакий белобрысый детина довольно дикого вида. Выглядел просто устрашающе. Говорил он мало. Сколько раз, бывало, сижу я в своем отсеке — работаю, что-то делаю, пишу программу на Лиспе. И тут, шаркая, подходит босой Скеф с кружкой пива и становится позади меня. Я ему: «Привет», — а он в ответ буркнет что-то или вообще промолчит. Просто стоит и смотрит, как я жму на клавиши. Я что-то делаю, и тут он вдруг: «Пффф, ошибка», — и уходит. А я остаюсь в полном недоумении. Такой дзэнский подход: учитель стукнул меня палкой — значит, надо помедитировать.

Сейбел: Я связался по электронной почте с Фальманом, и он написал, что вы были талантливы и быстро всему учились. Но он также припомнил вашу недисциплинированность. «Мы потихоньку пытались научить его работать в команде, научить писать такой код, чтобы вы или кто угодно еще мог его понять и через месяц». Вы помните эти уроки?

Завински: Не помню, чтобы я учился чему-то такому. Конечно, очень важно писать код, к которому потом сможешь вернуться. Но мне сейчас 39, а тогда было 15, и кое-что уже забылось.

Сейбел: В каком году это началось?

Завински: В 1984 или 1985. Думаю, летом, когда я из 10 класса перешел в 11. Занятия в школе заканчивались часа в четыре или около того, я отправлялся туда и оставался там до восьми-девяти вечера, хотя и не каждый день. Так или иначе, я проводил там немало времени.

Сейбел: И после школы вы ненадолго пришли в Университет Карнеги-Меллона?

Завински: Да. Дело в том, что я ненавидел учиться в старших классах. Это было самое жуткое время в моей жизни. И перед выпуском я спросил Фальмана, не возьмет ли он меня на полный день. Он ответил: «Нет, но у меня есть друзья, которые начинают новое дело. Поговори с ними». Это была фирма Expert Technologies (ETI). Кажется, Фальман был в деле. Они разрабатывали систему автоматической пагинации «желтых страниц» на Лисп, и я уже знал там кое-кого, кто работал с Фальманом. Они взяли меня, и все было хорошо, но через год я запаниковал: «Господи, я же устроился на эти две работы совершенно случайно, такое больше не повторится. Что будет, когда я уйду отсюда?» Без диплома колледжа мне светил разве что Макдональдс. Значит, надо было добывать диплом.

План был такой: я работаю на полставки в ETI, а остальное время учусь, тоже в половинном режиме. На деле же вышло, что работать и учиться пришлось по полной. Так продолжалось недель шесть, может, даже девять. Знаю только, что успел пропустить выбор курсов на семестр, так что деньги было уже не вернуть. Но не успел получить какие-нибудь оценки. В общем, учусь я или нет, непонятно.

Это было ужасно. В школе тебе говорят: мол, у нас тут один отстой и тесты, но в колледже все будет лучше. Поступаешь в колледж, и первый год там все то же самое. И тебе говорят: в магистратуре будет лучше. Все тот же отстой, только в другом месте — не для меня. Вставать в восемь, зубрить. Мне не разрешили пропустить курс «Введение в вычислительную технику», где объясняли, как пользоваться мышью. «Я полтора года работаю в этом университете, — говорил я, — и знаю, как пользоваться мышью». «Нет, мы не можем позволить вам, — отвечали мне. — У нас такой порядок». И все в таком же духе. Я не выдержал и бросил колледж. И рад, что сделал это.

Потом я работал в ETI года четыре или около того, пока компания не стала разваливаться. Мы работали на Лисп-машинах серии TI Explorer, и я — кроме того, что работал над экспертными системами, — тратил массу времени на возню с пользовательским интерфейсом и на понимание того, как они вообще работают, сверху донизу. Я любил их, любил копаться в операционной системе и понемногу осознавать, как это все устроено.

Я написал кучу кода и разместил в нескольких группах новостей объявление о том, что ищу работу, предлагая при этом взглянуть на фрагмент моего кода. Питер Норвиг увидел его и назначил мне собеседование. Моя тогдашняя подружка переехала сюда, в Калифорнию, чтобы учиться в Университете Беркли, и я переехал вместе с ней.

Сейбел: Норвиг тогда был в Беркли?

Завински: Да. Это была очень странная работа. Там был целый выводок практикантов, которые исследовали понимание людьми естественных языков: это были лингвисты по образованию, которые слегка занимались программированием. И нужен был тот, кто собрал бы написанные ими куски и обрывки кода и сляпал бы из них что-то работающее.

Это было невероятно трудно, потому что у меня не хватало подготовки, чтобы понять, что, черт возьми, они там делают. То и дело получалось так: я остолбенело смотрю на что-то и не знаю, что это значит и в каком направлении двигаться, что читать, чтобы понять это. И я спросил Питера. Он внимательно выслушал меня и сказал: «В общем ясно, что пока это для тебя непонятно. Во вторник сядем, и я тебе все объясню». Значит, делать мне было пока нечего. Я углубился в работу с оконными системами, скринсейверами и другими штуками, связанными с пользовательским интерфейсом, которыми раньше занимался для забавы.

После шести-семи месяцев я почувствовал, что трачу свое время впустую. Я не делал для них ничего серьезного, это было похоже на каникулы. Позже не раз, действительно много работая, я оглядывался и спрашивал себя: «Зачем ты оставил эту работу, похожую на каникулы? Что тебе не нравилось? Тебе платили за разработку скринсейверов!»

В конце концов я устроился в компанию Lucid — одну из двух оставшихся Лисп-компаний. По-настоящему меня заставило уволиться чувство, что в Беркли я ничего не достигну. Вокруг меня были сплошь лингвисты, кое с кем я до сих пор дружу, они хорошие ребята — но не программисты. Абстрактные понятия им намного интереснее решения реальных задач. Я хотел делать что-то такое, чтобы можно было ткнуть пальцем и сказать: «Смотри, какую классную штуку я сделал».

Сейбел: Именно работая в Lucid, вы начали заниматься графическим редактором XEmacs. А когда вы туда пришли, вы что-нибудь писали на Лиспе?

Завински: Да, в одном из первых проектов, над которым я работал. Я, правда, не помню, что это был за компьютер, но это точно был 16-про-цессорный компьютер с поддержкой параллельных вычислений, на котором мы использовали собственную реализацию языка Common Lisp с управляющими структурами, позволяющими распараллеливать задачи на разные процессоры.

Я немного поработал над задачей уменьшения накладных расходов при создании потоков, чтобы, например, выгоды от применения параллельного вычисления чисел Фибоначчи не сводились на нет накладными расходами создания стека для каждого потока. Мне это действительно нравилось. Я впервые имел дело с таким замысловатым компьютером.

А до этого я поднимал Лисп на новых типах машин. Обычно это означало, что кто-то уже написал компилятор под новую архитектуру железа и скомпилировал загрузчик Лиспа. Затем я брал бинарный, вроде бы работающий код и расшифровывал формат загрузчика новой машины, чтобы затем написать небольшую программу на Си, которая бы загрузила бинарные файлы на страницу памяти, сделала ее исполняемой и передала ей управление. После чего, вполне возможно, вы получали командную строку Лиспа и могли вручную загружать другие программы.

Из-за отсутствия нормальной документации этот процесс для каждой новой архитектуры был непростым делом. Приходилось компилировать код на Си, а затем просматривать и редактировать его в Emacs байт за байтом. Давайте-ка посмотрим, что же произойдет, если вот этот бит установить в ноль... Рухнет или нет?

Сейбел: Когда вы говорите, что не было нормальной документации, это значит, что документация была неточной или что ее не было вовсе?

Завински: Нет, документация была, но зачастую она не отвечала действительности. Возможно, ошибка вкралась несколькими версиями раньше — кто знает? Но в определенный момент ты изменяешь этот бит, и машина уже не воспринимает твою программу как исполняемый модуль, и тебе приходится выяснять, что же произошло.

Сейбел: Ну, такое случается сплошь и рядом, начиная от низкоуровневого системного программирования и заканчивая высокоуровневым API, когда всё начинает работать совсем не так, как ты ожидаешь, или не так, как написано в документации. Как вы справлялись с этим?

Завински: Да просто начинаешь ожидать этого. Чем раньше поймешь, что сбился с пути, тем раньше сможешь выяснить, где именно. Лично я пытался создать исполняемый файл. Я знал, что компилятор Си может создавать исполняемые файлы. Поэтому алгоритм работы был такой: берешь хороший исполняемый файл и начинаешь его ковырять, пока он не превратится в плохой. Это основной механизм обратной разработки (reverse engineering).

Думаю, именно в компании Lucid я исправил самый сложный компьютерный баг. Я дошел до момента выполнения исполняемого файла, когда тот пытался загрузить интерпретатор Лиспа, но после выполнения 500 инструкций процесс загрузки падал. Тогда я начал выполнять процесс загрузки пошагово, чтобы выяснить, где же он падает. Хотя это было бессмысленно, создавалось впечатление, что процесс падал каждый раз в другом месте. Я стал исследовать ассемблерный код компьютерной архитектуры, о которой имел лишь смутное представление. Наконец до меня дошло. «Господи, при пошаговом выполнении он делает что-то не то. Возможно проблема связана с временными задержками». В итоге я понял, что происходило: дело в том, что это была одна из первых машин с упреждающим исполнением команд. В этом случае выполнялись обе ветви кода. Но GDB при пошаговой отладке выполнял только одну из ветвей. Так что баг был в GDB.

Сейбел: Здорово.

Завински: Точно. Но это меня подкосило. «Господи! Мне придется отлаживать GDB, который я первый раз вижу». Чтобы обойти ошибку отладчика, нужно остановить выполнение процесса перед инструкцией ветвления, задать точки останова в обеих ветвях и продолжить выполнение. Именно таким способом мне удалось воспроизвести ситуацию и понять, что же происходит на самом деле. Затем я потратил около недели на исправление GDB, но так и не смог понять, в чем же дело. Я предполагал, что из-за проблем с одним из регистров отладчик считал, что всегда выполняется одна из ветвей условия или что-то в этом роде. Поэтому я изменил команду пошагового выполнения инструкций, чтобы определить, когда оно дойдет до инструкции ветвления, и там сказать: «Стоп, это не делай». Теперь я мог просто пошагово выполнять программу. Выполнение в конце концов останавливалось, я вручную задавал точку останова и продолжал выполнение. Когда что-то отлаживаешь, понимая, что не только путь выбран неверный, так еще и инструмент никуда не годится, — что может быть хуже.

Разработка систем на Лиспе была особенно запутанной, поскольку GDB был совершенно неприменим к Лисп-коду, который не содержал никакой отладочной информации. Причина была в том, что интерпретатор Лиспа был разработан с помощью компилятора, о котором GDB не имел ни малейшего понятия. Думаю, для некоторых платформ создавались стековые фреймы, которых отладчик GDB просто не понимал. На этом этапе GDB был способен лишь на пошаговый прогон ассемблерного кода. Поэтому мы хотели избавиться от него как можно скорее.

Сейбел: А потом у вас появился отладчик Лиспа, и вы оказались во всеоружии.

Завински: Ага.

Сейбел: И примерно в то же время компания Lucid сменила курс, решив создавать интегрированную среду разработки для C++.

Завински: Это началось еще до меня: когда я пришел туда, интегрированная среда разработки уже создавалась. Люди начали переходить с Лиспа на Energize — так называлась эта среда разработки. Это был отличный продукт, но он появился на два-три года раньше, чем нужно. Никто — по крайней мере, никто среди пользователей UNIX — не думал, что им вообще это нужно. Сейчас все используют такие возможности, но тогда мы тратили кучу времени, объясняя, почему эта штука лучше, чем vi и GCC. Еще я делал кое-что для Emacs. Кажется, тогда я уже переписал компилятор байт-кода. Зачем мне это было нужно? Правильно, потому что я делал что-то вроде адресной книги.

Сейбел: Базу данных для Большого Брата?

Завински: Ага. Но работала она ужасно медленно. Я стал выяснять, почему, и понял, что компилятор ни к черту не годится. Я переписал компилятор, что и привело к моей первой ссоре с непримиримым Стеллменом. Тогда я много чего узнал о Emacs.

Сейбел: А изменения в компиляторе коснулись формата байт-кода или только процесса компиляции?

Завински: Я сделал несколько изменений: внес исправления в интерпретатор байт-кода, написанного на Си, а также добавил несколько новых инструкций для повышения производительности. Но компилятор мог быть сконфигурирован, чтобы генерировать байт-код в старом формате или использовать преимущества нового.

Так вот, я написал новый компилятор, а Стеллмен заявил: «Не вижу необходимости в этих изменениях». А я ему в ответ: «Да что вы? Теперь генерируется более быстрый код». А он: «О'кей, тогда пришли мне все изменения исходников и объясни каждую измененную строку». Тогда я ответил: «Нет, я не буду этого делать. Я полностью переписал старый компилятор, потому что он был дерьмовым». Это ему не понравилось. Мой компилятор был добавлен только потому, что я выпустил его, тысячи людей начали им пользоваться, компилятор им понравился, и они надоедали Стеллмену два года. Вот он и добавил мой компилятор, чтобы его больше не доставали.

Сейбел: Вы подписали передачу авторских прав на этот компилятор компании Free Software Foundation?

Завински: Да, я сделал это сразу же. По-моему, это было первое, о чем говорилось в том электронном письме. Там было что-то вроде: «Пришли мне изменения и подпиши это». Я подписал и сказал: «Остальное я выполнить не могу. Я не могу прислать вам изменения. Это просто смешно. Тут все описано, взгляните сами». Вряд ли он смотрел на это хоть раз.

Толкуют, будто были какие-то судебные разборки между Lucid и FSF. Это полная ерунда. Мы подписывали бумаги о передаче авторских прав на все, что делали для FSF. Им было зачем-то нужно утверждать, будто мы делали это не всегда. Бывало, мы подписывали одни и те же бумаги несколько раз, потому что они говорили, будто потеряли их. Кажется, подобная шумиха была с подписыванием бумаг по XEmacs, но это было позже, когда я уже ушел.

Сейбел: Итак, вы начали с Лиспа, но явно не зациклились на нем на всю жизнь. Что было потом?

Завински: Следующим языком, на котором я создавал что-то серьезное, был Си. Казалось, будто вернулись времена программирования на ассемблере под Apple II: это был ассемблер PDP-11, который считал себя настоящим языком. Программирование на Си, как вы наверное знаете, малоприятное занятие, поэтому я старался как можно дольше держаться подальше от всего этого. А C++ — просто гадость. С ним все не так. Так что я старался как можно дольше держаться от него подальше и в Netscape писал на Си. Это было просто — ведь мы были нацелены на небольшие компьютеры, на которых нельзя было нормально использовать программы на C++, потому что код распухал до безумия, как только были задействованы библиотеки. И потом компиляторы для C++ постоянно менялись, что приводило к массе проблем с несовместимостью. Поэтому мы с самого начала выбрали для себя ANSI С, и он хорошо служил нам. После всего этого Java отчасти воспринимался как возврат к Лиспу — в том смысле, что этот язык не лезет из кожи вон, желая отпугнуть вас. Им удобно пользоваться.

Сейбел: В каком смысле?

Завински: Автоматическое управление памятью. Функции выглядят именно как функции, а не как подпрограммы. Очень много сделано для обеспечения модульности. В коде на Си всегда есть искушение применить оператор goto только потому, что это просто.

Сейбел: Значит, сейчас вы в основном используете языки Си и Perl?

Завински: Ну, я вообще сейчас не много программирую. В основном пишу глупые маленькие скрипты на Perl для поддержания работы моих серверов. Я написал кучу дурацких программ поиска картинок для моих МРЗ-файлов или нечто вроде того. Простенькие одноразовые программки.

Сейбел: Вам нравится Perl или он просто всегда под рукой?

Завински: Терпеть его не могу, ужасный язык. Но он установлен абсолютно везде. Садишься за компьютер — и не нужно никого просить установить Perl, чтобы выполнить свой скрипт: Perl там уже есть. Это единственный аргумент в его пользу.

У него неплохая коллекция библиотек. Часто есть библиотека, позволяющая делать именно то, что тебе нужно. Пусть библиотеки иногда неважно работают, но это уже что-то. Не то, что с Java, когда пишешь что-нибудь на этом языке и пытаешься понять, что вышло. Я сам с трудом установил Java на своем компьютере. Это ужасно. Мне кажется, Perl — противный язык. Если научиться использовать его хоть немного, можно сделать его похожим на Си или, скорее, на JavaScript. Сумасшедший синтаксис, непонятные структуры данных. Немного хорошего можно сказать о Perl.

Сейбел: Но он не так плох, как C++.

Завински: Нет, конечно, нет. Они созданы для разных задач. Есть задачи, которые намного проще реализовать на Perl (или подобном ему языке), чем на Си, только потому, что все так называемые скриптовые языки ориентированы на работу с текстом. Вот чего я действительно не понимаю, так это различия между «программированием» и «написанием скриптов». По-моему, чепуха все это. Но если основная твоя работа заключается в обработке текста или запуске программ (например, запустить wget, получить от нее какой-то HTML и сопоставить его с образцом), то гораздо легче это сделать на Perl, чем даже на Emacs Lisp.

Сейбел: Не говоря о том, что Emacs Lisp не слишком удобен для работы с утилитами командной строки.

Завински: Ну да, хотя я все время писал разные мелкие утилиты с помощью Emacs. Было время, на раннем этапе работы в Netscape, когда часть процесса сборки включала запуск скриптов с помощью команды emacs -batch для работы с некоторыми файлами. Это никому не нравилось.

Сейбел: Представляю... А как насчет XScreenSaver — все еще работаете над ним?

Завински: Я до сих пор пишу новые скринсейверы — только ради развлечения и только на Си.

Сейбел: Применяете ли вы какую-нибудь интегрированную среду разработки?

Завински: В основном Emacs. Правда, недавно я портировал XScreen-Saver на OS X. Я сделал это так: реализовал заново Xlib на базе Cocoa (графической основе Маков), поэтому мне не пришлось переписывать код всех скринсейверов. Они все еще обращаются к Xlib, но я реализовал все соответствующие методы. Сделано это было на Objective-C, который оказался отличным языком программирования, и работа доставила мне огромное удовольствие. Он определенно напоминает Java в лучших его проявлениях, но также напоминает и Си. То есть в основном это Си, и можно напрямую использовать Си-код, вызывая нужные функции без лишних усилий.

Сейбел: Работая в компании Lucid, что вы узнали по технической части кроме политической составляющей разработки Emacs?

Завински: Работая там, я точно стал более хорошим программистом. Во многом потому, что был окружен действительно очень умными людьми. Все, кто там работал, были великолепны. Просто здорово находиться в коллективе, в котором, если кто-то скажет: «Это чепуха» или «Нужно сделать это вот так», — можно просто верить на слово, не сомневаясь, что он знает, о чем говорит. Это было на самом деле здорово. Не скажу, что раньше я не бывал среди умных людей, но это был именно коллектив высококлассных специалистов в равной степени.

Сейбел: А насколько велика была команда разработчиков?

Завински: В компании было человек 70 — точно не знаю, и около 40 из них разработчики. В команде Energize было 20-25 человек. Все разработчики делились по направлениям. Кто-то работал над компиляторами, кто-то над серверной частью базы данных. Кто-то работал над пользовательским интерфейсом, не связанным с Emacs. Я и еще двое-трое занимались интегрированием Emacs с внешним окружением. Так получилось, что я работал в основном над Emacs, пытаясь сделать так, чтобы нашим редактором Emacs 19 можно было пользоваться, чтобы он не падал то и дело и чтобы под ним запускались все пакеты, которые должны запускаться.

Сейбел: То есть вы хотели, чтобы Emacs, который являлся составной частью вашего продукта, был полнофункциональной версией Emacs.

Завински: Изначально мы не собирались включать Emacs в наш продукт. Идея была такая: на вашей машине уже стоит Emacs, вы берете наш продукт, и они совместно работают. Например, на вашей машине установлен компилятор GCC и наш продукт, и они совместно работают.

Кажется, одним из первых кодовых названий нашего продукта было что-то вроде Hitchhiker (попутчик), так как идея была в том, что он будет брать и интегрировать все имеющиеся у вас инструменты — заставит их «общаться» между собой, предоставив им необходимый уровень коммуникации.

Но это не сработало. Мы стали выпускать собственные версии GCC и GDB, потому что не успевали за изменениями этих систем, по крайней мере, успевали не всегда. То же самое было и с Emacs. Поэтому мы выпустили все целиком. В конце концов мы пошли таким путем: «Так, мы заменили Emacs. Черт. Нам пришлось это сделать, поэтому нужно заставить его работать нормально». Только на режим эмуляции vi я потратил уйму времени.

Сейбел: И это несколько недель вашей жизни, которые вам никогда не хотелось бы пережить снова.

Завински: И не говорите. Это было настоящее испытание. Кажется, в результате все заработало. Настоящая проблема была не в том, что режим эмуляции vi работал плохо, а в том, что пользователи были вынуждены постоянно выходить и перезапускать vi. И что бы я ни делал, эту проблему никак не удавалось решить. Пользователь говорил: «Я думал, она будет запускаться за полсекунды, а она запускается за четырнадцать. Это просто смешно. Я не могу этим пользоваться».

Сейбел: Почему вы ушли из компании Lucid?

Завински: Lucid разваливалась. Людей то и дело отправляли в неоплачиваемый отпуск. Я разослал письма своим знакомым: «Привет, кажется, мне скоро будет нужна новая работа». Одним из них был Марк Андрессен. Он сказал: «Забавно, что ты об этом упомянул, ведь на прошлой неделе мы как раз создали компанию». Так я нашел работу.

Сейбел: Итак, вы ушли в Netscape. Над чем вы работали?

Завински: Я практически сразу начал работать над версией браузера для UNIX. К тому моменту было написано совсем немного кода — результат нескольких дней работы. Немногим больше было сделано для версий под Windows и Мак. Модель системы состояла из крупного куска бизнес-логики, независимой от платформы, и небольшой части кода, отвечающего за представление для каждой платформы.

Сейбел: Это был полностью новый код?

Завински: Полностью новый. Большинство основателей компании Netscape были разработчиками браузера NCSA/Mosaic. Они разработали разные версии, которые по сути представляли собой три разные программы. И все шестеро, делавших это, оказались в Netscape. Они не использовали повторно старый код, но уже решали подобную задачу ранее.

Сейбел: То есть они просто начали писать код с чистого листа?

Завински: Именно так. Я никогда не видел код браузера Mosaic (кстати, я до сих пор его не видел). Как раз в это время у нас были судебные разбирательства: университет утверждал, что мы использовали их код, но мы, кажется, как-то уладили этот вопрос. Ходили слухи, будто мы действительно использовали их код, но мы этого не делали.

И зачем? Каждый хочет попробовать еще раз заново, верно? Во время разработки программы находишь ответы на многие вопросы, и, получив шанс выкинуть все и начать с нуля, конечно же, воспользуешься этим шансом. Во второй раз все должно получаться гораздо лучше. И действительно получается. Например, общепринятая архитектура не предоставляла возможность параллельной загрузки изображений. А ведь это действительно важная возможность. Поэтому мы разработали лучшую архитектуру.

Сейбел: Но это похоже на классический случай синдрома второй системы.

Завински: Вот именно.

Сейбел: Так как же всем вам удалось его избежать?

Завински: Самым святым для нас были сроки. Или мы выпустим новый продукт за полгода, или умрем, пытаясь это сделать.

Сейбел: Как вам удалось справиться со сроками?

Завински: Мы осмотрелись и поняли, что если не сделаем это за полгода, кто-нибудь опередит нас. Поэтому мы решили, что справимся с этим за шесть месяцев.

Сейбел: Учитывая, что вначале была определена дата, вам нужно было жертвовать либо возможностями системы, либо качеством. Как вы поступили?

Завински: Мы долго обсуждали возможности системы. Ну, на самом деле не так и долго, но нам казалось именно так, потому что тогда каждый день был как неделя. В конце концов мы определили все возможности. У нас была белая доска, на которой мы писали наши идеи, связывая их друг с другом. Всего нас было человек шесть-семь, точно не помню. Группа умных, самовлюбленных людей, которые сидят в одной комнате и орут друг на друга неделю или около того.

Сейбел: Шесть-семь человек — это вся команда разработчиков Netscape или только версии для UNIX?

Завински: Это была вся команда разработки клиентской части. Были еще ребята, отвечавшие за серверную часть, которые в основном занимались разработкой собственной версии Apache. Мы мало общались с ними, так как были заняты. Мы завтракали вместе, но не более того. Мы выяснили, что должно быть в системе, и распределили работу так, чтобы над каждой частью проекта работало не более двух человек. Я занимался UNIX-частью, а Лу Монтулли делал основную работу по сетевой составляющей серверной части. Предварительная версия команды была следующей: Эрик Бина занимался общей компоновкой системы, Джон Миттельхаузер и Крис Хаук занимались пользовательским интерфейсом под Windows, Алекс Тотич и Марк Ланетт — пользовательским интерфейсом под Мак. Потом эти команды слегка увеличились. Мы совещались, потом расходились по своим отсекам и стучали по клавиатуре 16 часов в сутки, пытаясь сделать так, чтобы хоть что-то работало.

Обстановка была отличная, мне правда нравилось. Поскольку каждый считал себя правым, мы постоянно спорили, но быстро понимали друг друга. Кто-нибудь заглядывает в твой отсек и говорит: «Какого хрена ты сохранил этот код? Так нельзя делать, это же дерьмо собачье. Ты идиот». Отвечаешь ему: «Да пошел ты!», смотришь на свой код, исправляешь ошибки и сохраняешь его. Мы были весьма резкими парнями, но зато не тратили лишнее время, потому что никто ни с кем не церемонился, не объяснял подолгу, почему считает что-то неправильным. Можно было просто сказать: «Да это куча дерьма, я не буду это использовать». И вопрос тут же решался. Да, атмосфера была напряженная, но мы сделали все довольно быстро.

Сейбел: То есть для быстрого создания программы требовалась многочасовая интенсивная работа?

Завински: Да уж, не курорт. Я знаю, что мы поступали именно так, и это работало. Ответить на этот вопрос можно так: а есть ли примеры того, как кто-то быстро и качественно создал здоровенную систему, обедая дома и регулярно высыпаясь? Бывало ли такое? Не знаю. Может, и бывало.

Но не всегда нужно делать все как можно быстрее. Нужно не перегореть за два года, а быть в состоянии проработать еще десять. А при 80-часовой рабочей неделе это невозможно.

Сейбел: Чем вы больше всего гордитесь из того, над чем работали?

Завински: На самом деле я горжусь самим фактом того, что мы выпустили это. Всю систему. Я был полностью сконцентрирован на своей части — создании пользовательского интерфейса для UNIX. Но горжусь я именно тем, что мы вообще выпустили систему и людям она понравилась. Пользователи сразу же стали переходить с NCSA Mosaic, говоря: «Ух ты, это лучшая система, которую мы когда-либо видели». У нас на панели инструментов была кнопка для страницы What's Cool (Что есть классного), чтобы показать миру все эти безумные веб-сайты, созданные к тому времени, — штук двести, наверное! Не сказать, чтобы я сильно гордился кодом, скорее именно тем, что дело сделано. Код во многих отношениях был не очень хорош — слишком я торопился. Но все было закончено. Мы выпустили систему — это было главное.

В ту ночь, выпустив бета-версию .96, мы все сидели по разным углам комнаты и смотрели, как идет закачка с прикрученным звуковым сигналом. Это было потрясающе. А через месяц программой, которую написал я, пользовались два миллиона человек. Это было невероятно. Это определенно стоило потраченных усилий — повлиять на жизнь людей, сделать так, чтобы их времяпрепровождение стало веселее, или приятнее, или удобнее благодаря тому, что мы сделали.

Сейбел: После этой бешеной гонки в какой-то момент надо было вернуться к качеству полученного кода. Как вы, ребята, справилась с этим?

Завински: Честно говоря, не очень. Никогда не было времени начать все сначала и переписать код. Да и вообще не слишком это здорово — начинать все заново и переписывать код.

Сейбел: На каком-то этапе вы также работали и над почтовым клиентом, да?

Завински: Когда мы работали над версией 2.0, Марк зашел в мой отсек и сказал: «Нам нужен почтовый клиент». Я ответил: «Отлично, я уже работал над почтовыми клиентами». Я тогда жил в Беркли и несколько недель почти не появлялся в офисе — сидел часами в кафе и набрасывал что-то, пытаясь выяснить, чего же хочу от почтовой программы. Я делал списки, что-то из них вычеркивал, думая, когда же приду к чему-нибудь. Как должен выглядеть пользовательский интерфейс?

И вот я вернулся на работу и стал писать код. Потом Марк снова зашел и сказал: «Мы тут взяли еще одного парня, он занимался почтовыми клиентами. Будете работать вместе». Это был Терри Вейссман, просто фантастический человек — мы прекрасно сработались. И совсем в другом ключе, по сравнению с работой над браузером на ранней стадии.

Мы совсем не кричали друг на друга. Просто не представляю, как можно было так работать, да и вообще, работал ли так хоть кто-нибудь еще. Мы распределили свою работу следующим образом. Я делал набросок дизайна и начинал понемногу писать код, и раз в несколько дней мы смотрели на список задач и говорили друг другу: «Я буду работать над этим. — А я над этим». И расходились.

Мы сохраняли код в репозитории и встречались снова. Он говорил: «Ладно, я с этим разобрался, а ты что делаешь?!» — «Работаю вот над этим». — «Хорошо, тогда я займусь вон тем». Так мы в некотором роде делили задачи между собой, и все шло превосходно.

Бывали и разногласия. Я предложил добавить фильтрацию на уровне папок, поскольку у нас не было времени сделать это как следует. Он сказал: «Нет-нет, я правда думаю, что мы должны сделать все как надо». А я: «Да у нас же нет времени!» Но он все сделал той же ночью.

Еще кое-что: мы с Терри виделись редко — он жил в Санта-Крус, я в Беркли. До работы нам было ехать примерно одинаково, но с разных сторон. А поскольку по работе нам нужно было общаться только между собой, то мы договаривались так: «Если ты согласен, чтобы я не приезжал, то и я согласен, чтобы ты не приезжал». — «Давай».

Сейбел: Вы вдвоем много переписывались по электронной почте?

Завински: Да, постоянно. Это было еще до эры мгновенных сообщений (Instant messenger, IM) — сейчас, конечно, мы бы прибегли именно к ним, потому что постоянно слали друг другу электронные письма. И переговаривались по телефону.

Итак, мы выпустили версию 2.0 с почтовым клиентом, хорошо принятую пользователями. Потом мы работали над версией 2.1, и я уже начал думать, что работа подходит к концу, но это оказался один из случаев, когда мы так и не смогли выпустить версию с первого раза. Мы с Терри были уже на полпути, когда зашел Марк и сказал: «Мы покупаем такую-то компанию. И там разрабатывают почтовый клиент, похожий на ваш». Я ответил: «Да, хорошо, но у нас уже есть такая программа». Он пояснил: «Понятно, но мы растем очень быстро, и нам все труднее нанимать на работу хороших людей. Иногда можно их нанять, купив другую, хорошо знакомую компанию». — «Ладно. Чем они будут заниматься?» — «Работать над вашим проектом». — «Черт, тогда я займусь чем-нибудь другим».

И как только Netscape купила эту компанию (которая называлась Collabra), нас с Терри отдали под их руководство. Эта компания выпускала почтовый клиент, во многом очень похожий на наш, за исключением того, что он работал только под Windows и потерпел полный крах на рынке.

А потом им крупно повезло — их купила компания Netscape. После чего Netscape передала бразды правления этой компании. Но вместо того чтобы отвечать только за почтовую программу, они оказались во главе всего подразделения по разработке клиентской части. Мы с Терри работали над Netscape 2.1, когда это произошло и начался процесс переписывания. Тогда стало понятно, что Netscape 3.0 будет выпущен слишком поздно, и наша версия 2.1 превратилась в версию 3.0, потому что нужно было выпустить на рынок основную версию.

А потом версия 3.0, над которой они начали работу, стала версией 4.0, которая, как вы знаете, стала одной из самых больших неудач в области программных разработок. Главным образом это и погубило компанию. Она умирала долго, но это было неотвратимо. Процесс переписывания был инициирован новоприобретенной компанией, которая ничего особенного не добилась, пренебрегла всей нашей работой и нашими достижениями, а сразу же начала страдать синдромом второй системы и потянула нас ко дну.

Они полагали, что, оказавшись у руля, просто обязаны поступать по-своему. Но когда они делали это по-своему в своей компании, они провалились. И когда люди, добивавшиеся успеха, говорили им: «Послушайте, правда, не используйте C++, не используйте потоки», они отвечали: «О чем вы говорите? Вы ничего не понимаете».

Именно такие решения, как отказ от C++ и использования потоков, позволили нам выпустить продукт вовремя. Другой важной составляющей было то, что мы всегда выпускали версии под все платформы одновременно. Это решение они тоже считали глупым: «У 90% пользователей установлена Windows, так что мы сосредоточим усилия на работе версии под Windows, а позже портируем ее под остальные платформы». Так поступали многие компании, потерпевшие крах. Если вы собираетесь выпускать кроссплатформенный продукт, то история показывает, как именно не следует поступать. Если вы действительно хотите выпускать кроссплатформенное решение, то разрабатывать все нужно одновременно. А портирование приводит к паршивому результату на второй платформе.

Сейбел: Версия 4.0 создавалась с нуля?

Завински: Ну, не то чтобы совсем с нуля, но в итоге они переписали каждую строку кода. И использовали C++ с самого начала. Я боролся против этого изо всех сил и, черт возьми, был прав. Все стало распухать, появились проблемы с совместимостью, потому что когда пишешь на C++, невозможно прийти к согласию, какие именно 10% языка можно безопасно использовать. Кто-нибудь говорит: «Мне нужны шаблоны», а затем выясняется, что нет двух компиляторов, которые реализуют шаблоны одинаково.

А когда весь опыт написания кода говорит о том, что мультиплатформенный код означает работу и под Windows 3.1, и под Windows 95, вы даже не представляете, насколько это важно. Поэтому разработка версии под UNIX (к счастью, это была уже не моя проблема) стала настоящим кошмаром, как и разработка версии для Мака. Это означало, что стал невозможным выпуск под старые версии Windows, такие как Win16. Пришлось сокращать количество поддерживаемых платформ. Может быть и пришло время так поступить, но причины были ни к черту. В этом не было необходимости.

Может показаться, что это мой горький, сугубо личный взгляд на вещи, будто мы с Терри создали великолепную штуку и теперь наказаны за свой успех, а в качестве наказания нами управляют идиоты. То время в Netscape стало несчастьем для меня. Начался период, когда я оставался в компании, ожидая, когда Netscape перейдет в другие руки.

Сейбел: И вы проработали там пять лет?

Завински: Да. И еще один год после продажи Netscape, потому что незадолго до этого стартовал проект mozilla.org, и снова стало интересно. Так что я остался из-за него.

Сейбел: Вам все-таки пришлось иметь дело с C++?

Завински: Ну, скорее с Java. В какой-то момент мы решили переписать браузер на Java. Мысли у нас были такие: «Ура! Мы выкинем весь код версии 4.0, который грозит потопить нашу компанию, и это точно сработает, ведь мы знаем, что делаем!»

Но не сработало.

Сейбел: Не сработало, потому что язык Java был еще сырым?

Завински: Нет. Нас снова разбили на четко определенные группы. Трое работали над почтовым клиентом. И мы сделали его. Мы сделали действительно отличный почтовый клиент — быстрый, со многими удобными функциями, он лучше сохранял ваши данные и никогда не тормозил при записи больших файлов. Мы воспользовались многими преимуществами механизма многопоточности языка Java, работа с которым оказалась не такой мучительной, как я ожидал. Работать на самом деле было приятно. С помощью разработанного нами API мы видели все направления, в которых он мог бы развиваться.

Кроме одной вещи, с которой он не справлялся, — отображения сообщений. Он генерировал HTML, а для его отображения нужен был слой отображения HTML, который тогда не был готов и не был готов никогда. Работа группы планирования пошла насмарку, и именно они были причиной отмены всего проекта.

Сейбел: Значит, вам приходилось бороться с сырыми на тот момент библиотеками Java для построения пользовательского интерфейса.

Завински: Нет, я бы так не сказал. Все работало. Просто в середине окна был большой белый прямоугольник, где мог отображаться только обычный текст. Они подходили к проекту очень академично, оперировали такими понятиями, как объектная модель документа (Document Object Model, DOM) и описание типа документа (Document Type Definition, DTD). «Нам нужно создать вот тут еще один уровень абстракции и создать здесь делегирование для делегирования вон того делегирования. И может быть, на экране наконец появится буква».

Сейбел: По-моему, вас сильно раздражает перепроектирование.

Завински: Да. К концу дня доделай эту чертову хрень! Хорошо, конечно, переписывать код, чистить его, чтобы с третьего раза он-таки получился красивым. Но суть-то не в этом, ты сидишь здесь не для того, чтобы писать красивый код, а для того, чтобы выпускать продукт.

Сейбел: Любители перепроектирования часто говорят: «Ну, все пойдет как по маслу, после того как мы прикрутим эту библиотеку. На самом деле мы сэкономим кучу времени».

Завински: Это чистая теория.

Сейбел: Иногда она оправдывает себя на практике, если человек мыслит здраво, а библиотека не слишком переусложнена. Тогда это действительно экономит время. Можете ли вы четко обозначить свою позицию?

Завински: Я знаю, что это банально, но всегда оказывается верным принцип «чем хуже — тем лучше». Если тратишь время на создание совершенной библиотеки, которая будет делать то, что тебе хочется, и позволит сопровождать версии от 1.0 до 5.0, все прекрасно. Но знаете что: пока три года создаешь версию 1.0, конкурент создаст аналогичный продукт за полгода — и ты вне игры. Ты никогда не выпустишь версию 1.0, потому что кто-то успел раньше.

В версии твоего конкурента, выпущенной за полгода, код — полное дерьмо, и они собираются переписать его за два следующих года, но, видите ли, они могут себе это позволить, потому что ты уже без работы.

Сейбел: Иногда, когда время поджимает, приходится выкидывать большой кусок кода, потому что кажется, что проще написать его заново.

Завински: Да, порою кое-что приходится списывать в утиль. Мне никогда не нравился такой подход, но если тебе достается чужой код, бывает проще написать все заново, чем использовать старый. Ведь нужно потратить время, чтобы понять тот код, выяснить, как им пользоваться, и понять его настолько, чтобы ты смог его отлаживать. Начать с нуля получится быстрее. Он может выполнять только 80% от того, что тебе нужно, но, может быть, именно эти 80% тебе и нужны.

Сейбел: А разве не та же логика — когда кто-то приходит и говорит: «Я не могу понять эту ерунду, я просто перепишу ее заново» — приводит к бесконечному переписыванию, что вам так не нравится в разработке программ с открытым исходным кодом?

Завински: Да. Но есть и другой аспект, помимо вопроса эффективности: намного интереснее писать свой код, чем пытаться разобраться в чужом. Так что совершенно понятно, почему так бывает. Но вся возня с Linux/GNOME — это постоянное метание между чьим-то хобби и настоящим продуктом. Что это? Исследовательский проект, с помощью которого мы экспериментируем и пытаемся понять, как должна выглядеть графическая среда пользователя? Или конкуренция с компанией Apple? Трудно заниматься и тем, и другим.

Но даже это утверждение, которое предполагает, что есть некто, принимающий решение, совершенно не соответствует истине. Все это — просто стечение обстоятельств. Вот и получается, что все постоянно переписывается, но так и не доводится до конца. Все просто прекрасно, если компьютер для тебя — это всего лишь игрушка, с которой всегда интересно повозиться, а не средство для достижения цели, не инструмент, с помощью которого доводишь интересное для себя дело до конца.

Сейбел: Кстати, насчет «интересно повозиться»: вы все еще получаете удовольствие от программирования?

Завински: Иногда. Сейчас я занимаюсь сисадминской работой, которую терпеть не могу, да и никогда не любил. Мне нравится работать над XScreenSaver, потому что в некотором роде скринсейвер (настоящий скринсейвер, а не библиотека XScreenSaver) — это совершенная программа: все делается с нуля и никаких версий 2.0. И ошибки в такой программе бывают редко. А если она падает (ай-ай-ай, произошло деление на нуль), просто ее исправляешь.

И никто никогда не попросит о новой функции для скринсейвера: «Хочу, чтобы он был более желтым». Ведь скринсейвер такой, какой есть. Вот почему для собственного удовольствия я пишу именно их. Это четкий результат, о котором не надо думать слишком много. Он не преследует тебя.

Сейбел: И вам нравятся головоломки из математики, геометрических построений и графики?

Завински: Да. Если повернуть это маленькое уравнение вот этак, что получится? Как сделать, чтобы эти шарики крутились более естественно и менее механически, чем это свойственно компьютеру? И все такое. Как сделать так, чтобы эти гармонические волны больше походили на чьи-то прыжки?

А затем я стал писать все эти мелкие глупые сценарии командной оболочки для самозащиты. Я знаю, что могу сделать это вручную, щелкнув на одной из 30 000 страниц, но почему бы не написать сценарий и не сэкономить время? Мне ничего не стоит это запрограммировать. А непрограммистам это кажется волшебством.

Мне очень понравилось портировать библиотеку XScreenSaver для Мака. Пришлось написать немало нового кода, обдумать API и всю общую структуру.

Сейбел: Вы проектировали API? Как вы структурировали код?

Завински: Я одновременно рассматривал существующие API и пытался найти лучший способ создать слой между миром X11 и миром Мака. Как мне все это структурировать? Какие API Мака подойдут лучше? Впервые за долгое время я сделал что-то и подумал: «Здорово! Пожалуй, тут я еще кое-что могу».

И это было незабываемое ощущение, потому что индустрия разработки ПО вымотала меня. Я не мог больше выносить всю эту политику как в мире корпораций, так и в среде свободных разработчиков. Я был сыт этим по горло. Я хотел работать над чем-то, где не было бы споров по всяким мелочам, и не хотел видеть, как мой продукт уничтожается бюрократическим решением, перед которым я бессилен.

Сейбел: А не было искушения вернуться и поработать над Mozilla?

Завински: Нет. У меня не было никакого желания снова погружаться в споры и эти долбаные противостояния по Bugzilla. Это совсем не весело. Но это неизбежно при создании больших продуктов. Если для работы над проектом требуется больше одного человека (что естественно для таких проектов, как Mozilla), по-другому не получится. Но я не хочу больше этих баталий, за многие годы это желание полностью выбили из меня. Как программист, я могу пойти работать где-то еще. Но мне это не нужно, да я и не хочу. Как только меня что-то достанет, я сразу ухожу. А если я организую собственную компанию, то не смогу там быть программистом, поскольку придется ею руководить.

Сейбел: Что вам нравится в программировании, кроме того что два миллиона человек пользуются вашим продуктом?

Завински: Трудно сказать. Думаю, поиск решения задачи. Это не совсем то же, что головоломка, да я и небольшой любитель головоломок. Просто пытаешься понять, как попасть из точки А в точку Б, и думаешь, как заставить машину выполнять то, что тебе нужно. Удовольствие от программирования заключается главным образом в этом.

Сейбел: Есть ли для вас понятие красоты кода? Помимо возможности поддержки, существует ли эстетическая составляющая?

Завински: Да, конечно. Когда что-то выражено очень верно — лаконично и по сути, — вроде хорошо сформулированного афоризма или мгновенной карикатуры, выполненной одним росчерком пера и очень похожей на оригинал. Что-то в этом духе.

Сейбел: Как вы думаете, программирование и писательская деятельность — это похожие интеллектуальные занятия?

Завински: В каком-то смысле да. Программирование все же гораздо строже. Но они очень близки во всем, что касается способности выражать собственные мысли. Никакого беспорядка: все, что приходит в голову и требует перевода в слова, выражаешь максимально четко. По-моему, именно этим программирование очень близко к сочинению прозы.

Мне кажется, здесь задействованы одни и те же отделы мозга, но выразить это словами нелегко. Я часто читаю код и чувствую, когда в нем что-то не так. Как и в большинстве договоров. Отсутствие гибкости, множество повторений. Смотрю на него и думаю: почему бы не разбить его на подпрограммы (которые мы называем параграфами). И то, что обычно вначале идут такие и такие определения, которые используются бла-бла-бла...

Сейбел: Поговорим о буднях программирования. Как вы проектируете код? Как структурируете его? Может быть, ваша недавняя работа над портированием XScreenSaver под OS X послужит примером?

Завински: Сначала я для затравки создаю маленькие демонстрационные программы, которые больше никем и никогда не используются. Делается это только для того, чтобы выяснить, как расположить окно на экране, и тому подобное. Поскольку я реализую протокол X11, то прежде всего беру один из скринсейверов и составляю список всех вызовов X11, которые он делает.

Потом я делаю для каждого из них заглушку и начинаю понемногу их заполнять, постепенно выясняя, как буду реализовывать тот или другой вызов.

На другом уровне, со стороны Мака, начинаем все с самого начала. Как расположить окно на экране? Затем в какой-то момент приходится прибегать к Xcode. При этом сложнее всего понять, как поднять и заставить работать систему сборки нормальным образом. Приходится экспериментировать, крутить то так, то сяк. Потом думаешь, может поместить этот кусок кода выше, чтобы он обращался вот к этому куску? А может быть, стоит вывернуть это наизнанку? Приходится перетасовывать немало кода, пока в голове не сформируется разумный поток управления. Потом я чищу код, перемещаю его в более подходящие файлы, так чтобы вот этот кусок кода был вместе с вот этим куском.

Это как рисовать жирные стрелки на схеме. Потом я перехожу к следующему скринсеиверу, а он использует другие три функции, которых не было в предыдущем, поэтому мне их тоже нужно реализовать. Каждая из этих задач достаточно проста. Но над некоторыми из них приходится попотеть, потому что в API для X11 есть миллион настроек для отображения текста на экране или для поворота прямоугольника. Постепенно этот кусок кода становится все сложнее. Но большинство задач довольно просты.

Сейбел: Итак, для каждого обращения к X11 вы пишете свою реализацию. А вам никогда не казалось, что у вас набирается куча практически одинакового кода?

Завински: Конечно. После двух-трех раз вырезания и вставки похожего кода думаешь: ага, пора остановиться и поместить этот код в подпрограмму.

Сейбел: Представим, что вы снова работаете над проектом такого же масштаба, что и почтовый клиент. Вы говорили о том, что пишете несколько абзацев текста и список функциональных возможностей. Это практически все, что вы сделаете до начала работы над кодом?

Завински: Да. Может, добавлю небольшое описание различий между библиотекой и клиентской частью. А может, и нет. Если бы я работал один, то я бы с этим не заморачивался, потому что для меня это очевидные вещи. Далее, первое, что я бы сделал, — это решил, сверху или снизу начинать. Можно начать так: расположить на экране окно с несколькими кнопками, а уже потом зарываться в детали и писать логику работы этих кнопок. А можно начать с другого конца — с разбора и сохранения почтовых сообщений. Можно начать с любой стороны или одновременно с двух сторон и затем встретиться посередине.

Я заметил, что получение чего-либо на экране как можно раньше помогает мне лучше сосредоточиться на задаче и понять, что делать дальше. Ведь если смотришь на огромный список задач и не знаешь, за что взяться, то на самом деле не важно, за что возьмешься в первую очередь. Но если есть на что конкретно смотреть, пусть даже это вывод отладочной информации синтаксического анализатора почтовых сообщений, — совсем другое дело! Это уже что-то: куда будем двигаться дальше? Ладно, вместо отображения этой древовидной структуры можно заняться генератором HTML или чем-то в этом духе. Или сделать более детальный разбор заголовков. Просто ищешь очередную задачу, которую нужно решить.

Сейбел: Вы применяете рефакторинг для сохранения целостности внутренней структуры кода? Или с самого начала способны четко представить, как различные части кода будут взаимодействовать между собой?

Завински: Обычно я достаточно хорошо представляю это. Очень мало таких случаев, когда я говорил себе: «Да я же сделал все шиворот-навыворот! Придется все переставить». Но иногда это происходит.

Когда пишу первую версию программы, я стараюсь поместить все в один файл. Потом я начинаю видеть в этом файле структуру. Вот эти блоки очень похожи. Вот в нем уже тысяча строк, так почему бы не переместить что-то в другой файл? Да и API в этом случае получается естественнее. Проектирование — это непрерывный процесс, никогда не знаешь, насколько проект хорош, пока программа не будет готова. Поэтому я предпочитаю как можно скорее снять пробу, получить что-нибудь на экране и посмотреть на это со всех сторон.

И потом, начав писать код, внезапно понимаешь: «Нет, это глупая идея. И почему я решил, что этот модуль сделать легко, когда на самом деле это гораздо сложнее?» Это такие вещи, которые не понять, пока не начнешь писать код и не почувствуешь, как они от тебя ускользают.

Сейбел: Каковы признаки того, что какие-то вещи от тебя ускользают?

Завински: Когда погружаешься во что-нибудь с мыслью «Так, здесь я за полдня напишу кусок кода такой-то длины», а потом приступаешь к работе и постепенно начинаешь чуять недоброе: «Ага, нужен еще кусок, надо бы и за него взяться. Да тут работы выше крыши!»

Сейбел: Я заметил, чем хороший программист отличается от плохого: хороший программист легко переходит от одного уровня абстракции к другому, он способен не смешивать эти уровни при внесении изменений и точно определяет уровень, на котором эти изменения нужно внести.

Завински: В том, где и что размещается, нужно придерживаться определенного стиля, это очень важно во всех отношениях. Решить какую-нибудь проблему на уровне, более близком к пользователю, или внести какое-то, возможно, более крупное изменение, которое отразится на всей системе? Любое из этих решений может быть правильным, и очень сложно понять, какое из них какое. Мне нужно сделать какое-то изменение, но является ли оно единичным частным случаем или таких случаев будет 12?

Думаю, одна из самых важных вещей, по крайней мере для меня, когда создаешь что-то с нуля, заключается как раз в том, чтобы как можно скорее довести программу до состояния, когда ты, программист, сможешь ее использовать. Хотя бы немного. Это подскажет, что делать дальше, — ты буквально почувствуешь, что нужно делать. Когда что-то уже есть на экране и есть кнопка, связанная с некоторой функцией, появляется ощущение, какая кнопка будет следующей. Конечно, это GUI-центричное описание того, что я имею в виду.

Сейбел: Мы немного говорили об ужасных ошибках, с которыми вы сталкивались, например та история с GNB. Но давайте еще немного поговорим о процессе отладки. Для начала, какие инструменты вы предпочитаете? Инструкции печати отладочной информации? Отладчики исходного кода (symbolic debugger)? Формальные доказательства корректности?

Завински: За последние годы многое изменилось. Когда я работал на Лиспе, процесс отладки заключался в запуске программы, ее остановке и последующем изучении данных. Был специальный инструмент, который позволял копаться в памяти, и я изменил его таким образом, что все эти функции стали доступны через цикл Чтение-Вычисление-Печать (то есть через Lisp Listener). Когда этот инструмент выводил содержимое объекта, появлялось контекстное меню, щелкнув на котором, можно было получить значение этого объекта. Все это упрощало следование по цепочкам объектов и всякое такое. Я уже тогда думал о подобных вещах: погрузиться в середину кода, искать, экспериментировать.

Позже, уже работая на Си и используя GNB в Emacs, я попытался сделать то же самое. Именно исходя из этой модели мы создавали Energize. Но мне кажется, что он так никогда нормально и не заработал. Со временем я вообще прекратил пользоваться такими инструментам, а просто вставлял инструкции печати и запускал все снова. И так раз за разом, пока не исправишь ошибку. Интересно, что при переходе на все более и более примитивные среды, такие как JavaScript, Perl, это становится единственным вариантом, поскольку там нет никаких отладчиков.

В те дни люди вообще слабо представляли, что такое отладчик. «Да зачем он тебе нужен? Что он делает — добавляет за тебя инструкции печати? Не понимаю. Что за странные слова ты говоришь?» В те дни отладка в основном заключалась в инструкциях печати.

Сейбел: Имела ли тут значение разница между Лиспом и Си? Помимо инструментов одно из отличий в том, что в Лиспе можно тестировать маленькие кусочки. Можно вызвать небольшую функцию, если в правильности работы есть сомнения, остановить ее на середине и посмотреть, что происходит. А в Си запускаешь программу целиком, во всем ее величии и сложности, и задаешь точку останова в каком-нибудь месте.

Завински: Лисп и аналогичные языки позволяют в этом отношении больше, чем Си. Perl, Python и им подобные в этом смысле немного более похожи на Лисп, но все равно мало кто так делает.

Сейбел: Но ведь GNB дает возможность заглянуть внутрь. Чем он вам не подходит?

Завински: Мне он всегда казался неприятным. Отчасти из-за того, что имеет отношение к Си. Я анализирую массив и вдруг вижу кучу чисел, и нужно лезть туда и вернуть все к нормальному виду. Он никогда не работал правильно, как мог бы работать с нормальным языком.

Сейбел: В то время как в Лиспе, если вы смотрите на массив, он выводится как нужно, поскольку отладчик знает, что есть что.

Завински: Вот именно. Мне всегда казалось, что GNB прыгает вниз-вверх, и в стеке все оказывается перепутанным. Идешь вверх по стеку, а нижняя часть стека из-за проблем в GDB изменяется. Или думаешь, что в регистре должно быть одно значение, но поскольку находишься в другом кадре стека, оно оказывается совсем другим.

Такое чувство, что я не могу по-настоящему доверять сведениям отладчика. Он что-то вывел, посмотрим — так, это число. Правильное оно или нет? Неизвестно. Зачастую вообще оказываешься без всякой отладочной информации. Берешь кадр стека, и кажется, будто у этой функции нет аргументов. Минут десять пытаешься вспомнить, через какой регистр передается нулевой аргумент. Потом сдаешься, заново компонуешь программу и добавляешь инструкцию печати.

Похоже, со временем инструменты отладки становятся все хуже и хуже. С другой стороны, люди наконец-то начинают понимать, что распределение памяти вручную — тупиковый путь. Сегодня это уже неактуально, поскольку наиболее сложные ошибки, когда приходится закапываться в структуры данных, происходят редко, ведь в Си они обычно были связаны с проблемами повреждения памяти.

Сейбел: Вы используете операторы утверждений (assertions) или другой более-менее формальный способ документирования или проверки инвариантов?

Завински: Мы тогда ходили вокруг да около, не зная, как приступиться к операторам утверждений в базовом коде Netscape. Очевидно, что добавление операторов утверждений — всегда хорошая идея как для отладки, так и, как вы говорили, для документирования. Этим выражается намерение. Мы добавили множество таких операторов. Но вопрос в том, что произойдет при нарушении утверждения в финальных (не отладочных) версиях? Что тогда? Мы склонились к мысли возвращать нулевое значение в надежде, что программа будет продолжать работать. Ведь если браузер падает, это действительно плохо, гораздо хуже, чем возврат к циклу ожидания, большие утечки памяти или что-то в этом роде, поскольку все это меньше расстраивает пользователей.

Многие программисты инстинктивно говорят: «Выдавайте сообщение об ошибке!» Нет, не нужно. Никого это не волнует. С такими проблемами гораздо легче справиться в языках, поддерживающих исключения, таких как Java. В таких языках просто перехватываешь все исключения на самом верхнем уровне и готово. И не нужно беспокоить пользователя сообщением о том, что какое-то значение равно нулю.

Сейбел: Вы когда-нибудь просто проходили программу пошагово — для отладки или, как некоторые советуют, для проверки написанного кода?

Завински: Нет, не совсем. Обычно я использую пошаговое выполнение для отладки. Пожалуй, иногда для проверки правильности написанного кода. Но не часто.

Сейбел: Так что же вы делаете при отладке?

Завински: Сначала пробегаю глазами код, читаю его, пока не подумаю: «Так, этого не может быть, все должно работать правильно». Тогда я добавляю некоторый код для проверки и разрешения этого противоречия. Либо если, читая код, я не вижу никаких проблем, то запускаю его на выполнение, останавливаю где-нибудь в середине и смотрю, что происходит. Сложно говорить об этом вообще. Ситуации бывают разные.

Сейбел: Что касается операторов утверждений — насколько формально вы к ним подходите? Кто-то использует стандартное утверждение: «Я считаю, что в этом месте кода некоторое условие должно быть истинным». А кто-то мыслит более формально: у функций есть предусловия, постусловия и есть глобальные инварианты. Какова ваша позиция?

Завински: Я точно не думаю об этом в контексте математического доказательства корректности. Скорее я за стандартные утверждения. Конечно же, всегда полезно, получив входные данные в функции, хотя бы приблизительно понимать, какие у них ограничения. Может ли это быть пустая строка? Что-то в таком духе.

Сейбел: Тестирование — тема, весьма близкая к отладке. В Netscape была специальная группа обеспечения качества или вы все тестировали сами?

Завински: И то и другое. Мы все время запускали свои программы — это лучший способ проверки качества на месте. Но была и группа обеспечения качества, у которой были формальные тесты. И каждый раз перед выпуском новой версии они все проверяли по списку. Перейти на такую-то страничку, щелкнуть там-то. Вы должны увидеть это. Или не должны увидеть.

Сейбел: А как насчет тестов на уровне разработчика, таких как модульные тесты?

Завински: Нет, у нас такого не было. Для некоторых вещей я делал нечто похожее. У синтаксического анализатора дат для почтовых заголовков был огромный набор сценариев тестирования. В те дни мало кто обращал внимание на стандартизацию, поэтому в заголовках могла приходить всякая ерунда. И что бы там ни было, пользователям не нравится, когда их почта сортируется неправильно. Поэтому я собрал целую кучу примеров, создал тесты и получил громадный список плоховато отформатированных дат и чисел, в которые, как я считал, эти даты должны преобразовываться. Каждый раз, внося изменения в код, я запускал тесты, и некоторые из них падали. Так должен я соглашаться с ними или нет?

Сейбел: Переросло ли это в какую-то форму автоматического тестирования?

Завински: Нет, когда я писал такие модульные тесты для своего кода, они запускались в основном лишь тогда, когда я сам запускал их. Потом мы немного занимались этим, когда работали над проектом Grendel, переписывая почтовый клиент на Java, поскольку там гораздо легче писать модульные тесты при разработке новых классов.

Сейбел: Оглядываясь назад, как вы считаете, ваша команда пострадала от этого или нет? Упростилась бы или ускорилась разработка, если бы вы были дисциплинированнее в вопросах тестирования?

Завински: Не думаю. Мне кажется, это бы только замедляло нас. Можно долго говорить о том, как все делать правильно с первого раза. Первоначально мы были зациклены на скорости. Нам нужно было выпустить продукт, пусть даже несовершенный. Мы могли бы выпустить его позже, и его качество было бы выше, но к тому времени нас мог бы кто-нибудь опередить.

Довольно часто говорят, что дело пойдет быстрее при наличии модульных тестов, меньших модулей и тому подобное. Все это хорошо звучит в теории. При неспешном темпе разработки это действительно отличный вариант. Но когда тебе говорят: «Нам нужно сделать это с нуля за шесть недель», — приходится чем-то жертвовать, иначе не справиться. И я выбрасываю то, что не является абсолютно критичным. Модульные тесты не критичны. Пользователь не будет жаловаться на то, что у вас нет модульных тестов. Это ваше личное дело.

Не хочу, чтобы все решили, будто я считаю тесты ерундой. Нет. Это всего лишь вопрос приоритетов. Вы пытаетесь написать хорошую программу или пытаетесь закончить к следующей неделе? Сделать то и другое одновременно не получится. У нас в Netscape была такая шутка: «Мы стопроцентно преданы качеству. Мы собираемся выпустить продукт самого высокого, насколько у нас получится, качества к 31 марта».

Сейбел: Отсюда другая тема — сопровождение программного обеспечения. Как вы разбираетесь в коде, который не сами писали?

Завински: Я просто беру его и читаю.

Сейбел: С чего вы начинаете? Читаете его последовательно, с первой страницы?

Завински: Когда как. Чаще всего приходится изучать, как использовать новую библиотеку или набор инструментов. Если повезет, будет даже какая-нибудь документация. Есть некий API. Разбираешься с отдельным фрагментом, чтобы понять, как он работает, или выясняешь, как что-то реализовано. Так и прокладываешь себе путь через все это. С такими инструментами, как Emacs, можно начать снизу. Из чего состоят списочные ячейки (cons cells)? Как это выглядит? От этого можно танцевать. Иногда знакомство с системой построения позволяет понять, как все это сочетается. Мне всегда казалось, что, для того чтобы погрузиться в кусок кода, нужно взять некоторую задачу и попытаться ее решить.

С такими инструментами, как Emacs, можно взять существующий модуль и распотрошить его. Так, вот кусок кода. Вычленяем часть, которая действительно что-то делает, и получаем шаблон. Теперь мы знаем, на что похож компонент этой системы, и можем вставлять туда свои куски кода. Это как разобрать его по косточкам.

Сейбел: В Emacs вы в конце концов переписали компилятор байт-кода и части байт-кода виртуальной машины. Мы уже говорили о том, что значительно приятнее что-то переписать заново, чем исправлять, но это не всегда подходит. Не понимаю, как вы перешли эту черту? Вы решили переписать компилятор целиком, потому что это проще, чем исправить только некоторые его части? Или просто подумали: «Ух ты! А здорово будет написать компилятор!»

Завински: Так уж вышло, что в результате компилятор был переписан полностью. Я начал с внесения исправлений и попыток оптимизации. Но в конце концов в нем не осталось ничего от первоначального варианта. Я использовал тот же API, пока в нем не отпала необходимость. По-моему, компилятор байт-кода вышел отлично, отчасти потому, что это был изолированный модуль с единственной «точкой входа»: скомпилировать и сохранить.

Конечно, многое из того, что я добавил в Lucid Emacs, было не столь полезным. На самом деле, многие мои действия объяснялись желанием приблизить все это к Лисп-машинам и к более привычным для меня версиям Emacs и средам разработки под Лисп. И я приложил много усилий, чтобы Лисп в Emacs был более совершенным: например, чтобы использовались объекты-события, а не списки чисел. Использовать списки чисел вместо объектов-событий — примитив и безвкусица. Теперь понятно, что эти изменения были одной из главных проблем, поскольку приводили к несовместимости с библиотеками сторонних разработчиков.

Сейбел: И вы, конечно, не знали о скором появлении двух разновидностей Emacs.

Завински: Разумеется. Но и без того уже были две версии Emacs — 18 и 19. Так или иначе, проблема совместимости все равно бы возникла. Оглядываясь назад, я понимаю, что если бы осознавал последствия внесенных мной изменений, то сделал бы все по-другому. Или потратил бы больше времени на то, чтобы старый вариант тоже работал. Как-то так.

Сейбел: Вы уже упоминали о написании легко читаемого кода, что непосредственно касается сопровождения. Так что же делает код легко читаемым?

Завински: Конечно же комментарии. Запись предположений и того, что код делает. Если речь идет о создании структуры данных, то описание ее устройства. Я много раз убеждался, что это полезно. Это особенно полезно при написании кода на Perl, где все обстоит примерно так: это хеш-таблица, а значения представляют собой ссылки на списки, поскольку структуры данных в Perl — такая вот ерунда. Нужно ли использовать стрелку вправо (->), чтобы добраться до этого? Думаю, такие примеры не помешают.

Я всегда советовал писать больше комментариев, но меня раздражает, когда комментарий представляет собой перефразированное имя функции. Функция называется pushstack (добавить элемент в стек), а комментарий — «добавление элемента в стек». Большое спасибо.

В комментарии можно сказать то, что неочевидно из кода. Иначе зачем он нужен? Это должно быть высокоуровневое или низкоуровневое описание в зависимости от того, что важнее. Иногда самое важное — для чего вообще предназначен данный элемент. Зачем я его использовал? А иногда самое важное — диапазон допустимых входных значений.

Длинные имена переменных. Я не сторонник венгерской нотации, но предпочитаю использовать для описаний реальные английские фразы (кроме переменных цикла, там и так все ясно). По возможности, чем больше в них слов, тем лучше.

Сейбел: А что насчет организации кода? В конце концов, организация кода является линейной, но программы по своей сути нелинейны. Вы пишете сверху вниз или снизу вверх?

Завински: Обычно я располагаю элементы нижнего уровня в верхней части файла и стараюсь придерживаться этого порядка. Также в самое начало файла я обычно помещаю то, что нужно для API: высокоуровневые точки входа этого файла, описание данного модуля и так далее. В объектных языках все это делает за вас язык программирования. А с Си приходится больше действовать самостоятельно. На Си я стараюсь, чтобы для каждого .c-файла был соответствующий .h-файл, который содержит все внешние объявления. Все, что не экспортируется из .h-файла, является статическим. Бывает, я возвращаюсь и думаю: «Стоп, мне надо вызвать вот это», — и вношу соответствующее изменение. Но это делается намеренно, а не просто случайно.

Сейбел: Вы помещаете элементы нижнего уровня в начало файла. А код пишете так же? Начиная снизу?

Завински: Не всегда. Иногда я начинаю сверху, иногда снизу, когда как. Иногда я знаю, какие строительные блоки мне понадобятся, и сначала собираю именно их. А иногда сначала вижу решение только в общих чертах и лишь потом начинаю углубляться в детали. Бывает и так, итак.

Сейбел: Предположим, чисто теоретически, что вы собираетесь вернуться к программированию и набираете команду разработчиков. Как вы организуете их работу?

Завински: Думаю, нужно разбить всех на группы, максимум по три-четыре человека, которые будут работать в тесном ежедневном сотрудничестве. Этот вариант отлично масштабируется. Допустим, есть проект, который можно разделить на двадцать пять реально изолированных модулей. Значит, у вас может быть двадцать пять небольших команд — хотя это уже многовато. Скажем, десять команд. Пока они могут координировать работу друг с другом, не думаю, что здесь так уж много ограничений для роста. Просто постепенно это начинает походить скорее на несколько проектов, чем на один.

Сейбел: Итак, у вас несколько команд максимум из четырех человек каждая. Как вы будете координировать их действия? С помощью главного архитектора, который будет управлять зависимостями и выступать посредником между этими командами?

Завински: Здесь требуется согласовать интерфейс между модулями. Для того чтобы такой модульный подход работал, интерфейс между модулями должен быть простым и понятным. Тогда есть надежда, что согласование интерфейса пройдет без лишних воплей и будет проще выполнять обязательства по модулям. Думаю, лучший способ добиться нормального взаимодействия между модулями — сделать это взаимодействие максимально простым. В этом случае будет меньше возможностей для ошибок.

А сам процесс разделения на модули целиком зависит от проекта. Для некоторых типов веб-приложений первая ваша команда будет работать над пользовательским интерфейсом, вторая — над базой данных, третья — над кодом, выполняемым на сервере, четвертая — над кодом, который выполняется на клиентской машине. То же самое для настольного приложения. Форматы файлов, графический интерфейс пользователя, базовая структура команд.

Сейбел: Как вы распознаете таланты?

Завински: Даже не знаю. Я никогда не был тем, кто принимает людей на работу. А если и участвовал в собеседованиях, то мне всегда казалось, что у меня нет никаких идей по этому поводу. После собеседования я мог сказать, смогу или нет работать с этим человеком, но сказать, хороший это работник или нет, всего лишь поговорив с ним, я не мог. Мне всегда казалось, что это трудно сделать.

Сейбел: А если работник плохой? Есть ли надежный способ определить это?

Завински: Когда как. Например, я всегда старался избегать ярых сторонников шаблонов C++. Возможно, зря. Может быть, в том контексте, где они использовались, это было хорошим решением. Что касается тех, с кем я работал, умение отстаивать свою позицию очень ценилось, потому что все мы были большими любителями поспорить. В той обстановке это сильно помогало. Разумеется, на способность программировать это никак не влияет. Все это из области межличностных отношений.

Сейбел: А в другой команде это умение может оказаться очень вредным.

Завински: Само собой.

Сейбел: Складывается впечатление, что в Netscape вы, ребята, разделили все так, что разные люди владели разными частями системы. Одни считают, что это очень важно. Другие полагают, что для команды предпочтительнее коллективно владеть кодом. Что вы об этом думаете?

Завински: Со мной бывало и так, и так. Оба подхода имеют свои достоинства. Не думаю, что идея коллективного владения кодом так уж практична, поскольку кода бывает слишком много. Людям нужна специализация, иногда необходимы эксперты в конкретных вопросах. Обычно так и получается. Всегда оказывается, что есть код, с которым ты знаком лучше других, так уж вышло, что ты работал над этим модулем больше, чем кто-либо еще. Или оказывается, что какие-то части системы дороги тебе больше всего. Конечно же, хорошо, когда кто-то еще знаком с твоим кодом, если только ты не собираешься поддерживать свою часть системы вечно. Так или иначе, приходится кому-то доверить свой код. Хорошо, когда знание распространяется. Но также хорошо, когда есть кого винить. Если за что-то отвечают сразу все, значит, ответственного нет.

Сейбел: Вы когда-либо были руководителем?

Завински: Не совсем. Когда я работал над Emacs в Lucid, в Lucid Emacs было много модулей, написанных другими ребятами. Формально они на меня не работали, но в каком-то смысле приходилось руководить. Многим из них явно не хватало опыта, они просто делали то, что хотели, а мои указания сводились к следующему: «Так, мне нужно вот это, но вначале мне нужно вот это и это и отсюда вот это».

Сейбел: И вы давали им свободу действий? Говорили им, что вам нужно А, Б и В, а они уже сами решали, как это сделать?

Завински: Да. Когда мне нужно решить, включать данный модуль в конечный продукт или нет, я формулирую требования к нему. Главное, чтобы эта чертова штука работала. И я мог дать им совет: «Думаю, у вас будет больше шансов, если вы поступите так, а не иначе». Но я хотел: 1) чтобы все работало и 2) без моего участия. Они могли применить какой-нибудь безумный способ, но если он сработал, меня это устраивало, поскольку выполнялся второй пункт: мне не нужно было писать это самому. Собственно, мои советы касались лишь того, будет ли это работать и насколько это разумно.

Сейбел: С другой стороны, когда вы были неопытным программистом, что полезного делали ваши наставники?

Завински: Думаю, важнее всего было то, что они понимали, когда мне пора переходить на следующий уровень. Когда я пришел на работу к Фальману, мне дали какую-то глупую несложную работу. Но постепенно задания становились все серьезнее, хотя на самом деле по-настоящему серьезными они не были.

Сейбел: Это вы о Скефе, который только нависал над вами и говорил: «Ошибка»? Наверное, его компенсировал кто-нибудь, кто относился к вам более заботливо?

Завински: Ну, он не был совсем уж троглодитом. Мог и что-то полезное рассказать. Я же читал много кода и задавал кучу вопросов. Думаю, очень важно не бояться собственного незнания. Если не понимаешь, как что-то работает, спроси у того, кто понимает. Многие боятся. А что тут такого? Ведь чего-то не знаешь не потому, что тупой, а просто пока не знаешь.

Сейбел: Вы читали код, потому что работали над ним или просто хотели понять, как он работает?

Завински: Мне всегда было интересно выяснить, как что-то работает. Именно со стремления вникнуть в детали для человека начинается путь в эту профессию.

Сейбел: Вы не из тех, кто в детстве курочил тостеры?

Завински: Да. Я сделал телефон и выяснил, как набирать номер телеграфным ключом, который сделал из консервной банки. В детстве у меня были эти старые книжки, с барахолки или еще откуда, вроде «Науки для мальчиков», издания 1930-х годов; помнится, они сильно меня раззадорили. В 1920-1930-х существовала настоящая «хакер-ская» культура: советы, как протянуть телеграф от дома к сараю, как изготовить лейденскую банку...

Сейбел: Тогда другой стандартный вопрос: как программист, вы считаете себя ученым, инженером, художником, ремесленником или кем-то еще?

Завински: Точно не ученым и не инженером, поскольку эти понятия имеют очень четкие определения. Я не занимаюсь математикой, не создаю проекты, не провожу доказательств. Скорее, что-то среднее между ремесленником и художником, зависит от проекта. Я часто пишу скринсейверы — это ближе к искусству, к созданию красивых картин. Что-то из той же области.

Сейбел: Как считаете, вы овладели компьютерной наукой или только программированием?

Завински: За годы я почерпнул многое из компьютерных наук. Но целью было научиться программировать, заставить машину что-то выполнять. Компьютерная наука была лишь инструментом для этого.

Сейбел: Вы когда-нибудь считали это упущением? Не было желания получить более систематическое образование?

Завински: Да, были времена, особенно в Lucid, когда я осознавал, что все, о чем говорят эти парни, покрыто для меня мраком, потому что это никогда мне не требовалось и прошло мимо. Потом я освоил терминологию, разобрался в общих чертах, о чем они говорят, и немного читал, когда что-то нужно было узнать. Конечно же, иногда, особенно в молодости, я говорил себе: «Господи, я же ничего не знаю». Просто минутная слабость, но был и испуг. Мальчишка среди всех этих парней с учеными степенями — «Ааааа, я ничего не знаю! Я идиот! Что я здесь делаю?»

Моя жизнь была бы иной, если бы я проучился подольше. Но в тот момент я мог поступить только так, как поступил.

Сейбел: А бывало наоборот — когда вы чувствовали, что в настоящем программировании понимаете гораздо лучше окружающих вас компьютерных ученых?

Завински: Да, причем довольно часто. Но без этих мыслей вроде «Вы ребята выбрали не тот путь» или «Нас просто интересуют разные вещи». Я не хочу быть математиком, но математиков критиковать не собираюсь.

Весьма странно, что люди часто путают эти профессии. Они думают, что разработчик с огромной теоретической базой размышляет точно так же, как разработчик настольных приложений. У них мало общего.

Сейбел: Вы по сути самоучка. Что вы можете посоветовать программистам-самоучкам?

Завински: Тут все не так просто, поскольку мир сильно изменился. Я всегда странно себя чувствую, когда заходит разговор на тему «Как это было у меня». Я не знаю, правильно ли я тогда поступил. А люди всегда воспринимают это в смысле «Делай, как я».

У меня это вышло случайно. Так получилось, вот и все. Я принял решения, которые привели к другим решениям, и вот результат.

Я то и дело получаю электронные письма примерно такого содержания: «Я хочу стать программистом, что мне делать?» Или: «Идти мне в колледж или нет?» Что я могу ответить? В 1986 году я бы дал однозначный ответ. Но сегодня никто не сможет пойти по моему пути, потому что его больше нет.

Десять лет назад я бы говорил, что перво-наперво следует изучить язык ассемблера. Нужно осознать, как работает компьютер. Так ли важно это сейчас? Не знаю. Может быть, да. А может, и нет. Может, через десять лет все программное обеспечение будет представлять собой веб-приложения или распределенный код, выполняемый на арендованных кластерах, части которого, находясь на десятке серверов Google, порождают собственные копии и воссоединяются после получения результатов. Нужно ли будет для этого знать ассемблер? Или все настолько абстрагируется, что это уже будет неважно? Я не знаю.

Я был поражен, когда узнал, что люди получают дипломы программистов, не написав ни строки на Си. Начав с Java, они там и остались. Это кажется неестественным и неправильным. Но откуда мне знать, правильно это или нет? Может, дико думать: «А мы в свое время программировали с помощью девятивольтовой батареи и твердой руки!»

Сейбел: А что скажете о книгах? Есть ли книги по компьютерным наукам или программированию, которые должен прочесть каждый?

Завински: Я читал их не так много. Я всегда рекомендую книгу «Structure and Interpretation of Computer Programs», которая многих пугает, потому что там много о Лиспе. Но я думаю, что она действительно учит программированию, а не конкретному языку. Мне кажется, что многие курсы для начинающих делают упор на синтаксис. Я видел это в старших классах и на вводных курсах, когда недолго учился в Карнеги-Меллоне.

Они обучают не программированию, а тому, куда поставить точку с запятой. Это отталкивает людей от программирования, потому что это не самая интересная его часть. Даже для тех, кто знает, что делает.

Была еще книга — как же она называлась? — про отладку, ее написал кто-то из Microsoft. О том, как эффективно использовать утверждения. Помню, мне она показалась стоящей, но не потому, что я узнал из нее много нового, а потому, что именно эту книгу хочется дать прочесть идиоту-коллеге.

Была и еще одна книга, которую все считали величайшим трудом своего времени: «Design Patterns». По-моему, отстой. Там учили программировать методом «вырезания и вставки». Вместо того чтобы подумать над своей задачей, берешь сборник рецептов, ищешь там что-то более-менее похожее и просто пытаешься это воспроизвести. Это не учебник программирования, а книжка-раскраска. Но, похоже, многим она нравилась. И при встрече они перекидывались словечками из этой книги — такой паттерн, сякой паттерн. А вы о чем — о цикле? Ясно.

Сейбел: Есть ли ключевые навыки, необходимые каждому программисту?

Завински: Любопытство, желание разобрать что-то по косточкам. Стремление узнать, что там внутри происходит на самом деле. Думаю, это основа программирования. Без этого далеко не пойдешь. Это основной "путь получения знаний. Чтобы научиться создавать что-то свое, нужно разобраться в чем-то уже готовом, посмотреть, как оно устроено. По крайней мере, для меня это так. Я очень мало читал компьютерной литературы. Я учился, копаясь в исходниках и читая документацию. У меня была цель, для достижения которой я должен был знать, что делает эта штука и вот эта. Я просто шел наугад, пока не понимал, куда мне нужно.

Сейбел: Вы читали «The Art of Computer Programming» Кнута?

Завински: Нет. Это одна из тех книг, которую действительно стоило бы прочесть. Но я этого так и не сделал.

Сейбел: Читать ее достаточно сложно. Для ее понимания требуется хорошая математическая подготовка.

Завински: А я совсем не математик.

Сейбел: Довольно интересно, что многие программисты выходят из математиков и компьтерная наука прочно опирается на математические теории. А вы являетесь живым доказательством того, что это не обязательно. Какой объем математических знаний необходим, чтобы стать хорошим программистом?

Завински: Это зависит от того, где провести границу, определяющую, что относится к математике, а что нет. Сопоставление с образцом (Pattern matching) — это математика или нет? Понимание порядка величин и основ комбинаторики должно быть на интуитивном уровне. Но я полностью уверен, что элементарный математический тест я бы провалил. Ведь я давно не занимался чем-то настолько формальным.

Разве что в старших классах на уроках математики. Алгебра, немного матанализа. У меня не очень-то хорошо получалось. Я осилил это, но по-настоящему своим так и не ощутил. В старших классах была физика и основы механики. На лабораторных работах мы двигали бруски по наждачной бумаге и все такое. На уроках физики я выглядел просто ужасно, чувствуя себя полным идиотом, а ведь мне все это нравилось. Лабораторные работы я делал отлично, у меня здорово получалось. После этого на математику меня просто не хватало.

Я нашел решение, которое, как я догадывался, было абсолютно неверным. Я сдал работу, так и не поняв, в чем ошибка. Я получил зачет, потому что данные были собраны правильно и кое-что я пересдал позже. Просто математика никогда не была моей сильной стороной.

Конечно, я не стану утверждать, что программисту это вообще не нужно. Есть разные виды программирования. Если бы все были такими, как я, никакого программирования вообще бы не было. Но лично мне кажется, что программирование ближе к литературе, чем к математике. Словно пишешь рассказ, пытаясь передать его смысл очень тупому парню с ограниченным словарем, то есть компьютеру. У тебя есть некоторая идея, которую нужно объяснить, и ограниченные средства для объяснения. Какие подберешь слова, как будет выглядеть введение, заключение? Что-то в этом роде.

Здесь важен еще и вкус. Можно описать что-нибудь правильно, а можно не только правильно, но и красиво. Так и с программированием. Можно просто решить какую-то задачу, а можно сделать это с умом и красиво.

Сейбел: Зачем это нужно? Для собственного удовольствия? Или красивый код имеет какие-то практические преимущества ?

Завински: По большому счету, понятия «красоты» и «простоты сопровождения» эквивалентны. Или, по крайней мере, тесно связаны. Одна из составляющих красивого кода — это легкая для понимания структура. Ключевая информация собрана в начале или она разбросана повсюду? Возвращаясь к параллели с литературой: можно ли найти какой-то эпизод, перелистывая роман? «Это где-то ближе к середине, потому что именно там об этом шла речь». Или об этом говорится по всей книге. С программированием во многом так же.

Сейбел: Считаете ли вы, что сегодня, для того чтобы стать успешным программистом, требуются другие навыки?

Завински: Разумеется, сегодня уже нельзя написать программу полностью с нуля без каких-либо внешних зависимостей. Из-за бурного роста инструментов, библиотек, фреймворков и тому подобного сегодня даже самая элементарная программа нуждается во всем этом. Все как-то разом изменилось. Сегодня все что угодно должно быть веб-приложением. В мое время этого не было.

Так что умение разобраться в чужом коде и понять, как им пользоваться, стало еще важнее. Поэтому подход, вроде «я не понимаю этого, так что напишу-ка это заново», остался в прошлом. Тогда ты мог сделать это, и неважно, была ли эта идея хороша или нет. Сейчас с этим намного сложнее.

Сейбел: А как насчет стремления разобрать все по косточкам и понять, как это устроено, — так ли важна его роль в наши дни? Если сегодня захочешь проанализировать каждый кусок кода, с которым работаешь, то увязнешь в этом навсегда. Видимо, сейчас надо занимать такую позицию: «В целом я понимаю, как это работает, и пусть пока так и будет, а если очень понадобится, разберусь в этом поподробнее».

Завински: Да. Когда появились такие тенденции, первая моя мысль была о том, что у нас вырастает поколение программистов, которые ничего не будут знать об эффективности и о том, куда расходуется память. Когда такой программист наконец заметит: «Ого, моя программа стала просто огромной», что он сможет с этим сделать? Он даже не сможет понять, с чего начать. Вот о чем я сразу подумал, но ведь я — пещерный человек. Может, это и неважно, ведь теперь достаточно просто добавить памяти и все в порядке.

Сейбел: А может, люди будут глубже изучать те или иные вещи. Например, неважно, выделили мы на это четыре байта или шесть, но важно, сможет ли эта штука выполняться на одном узле кластера или будет задействован также и второй.

Завински: Да, вы правы. В этом смысле программирование сильно изменилось. Раньше внимание уделялось другим вещам. Когда-то я считал каждый байт и задавался вопросами вроде: «Какого размера будут мои объекты? Может, сделать это как-то по-другому, а то этот заголовок массива уже можно просчитать». Что-то в таком духе. Теперь уже никто об этом не думает. Трюк с сохранением в одном слове двух указателей с помощью операции XOR стал для всех темным лесом. Зачем кому-то использовать что-то подобное? Это безумие. Сегодня на передний план выходят другие навыки. Сегодня очень важно уметь разбираться в API и понимать, что там нужно, а что нет.

Сейбел: Если бы вам было 13 лет, вы бы увлеклись программированием — тем, каким оно стало сегодня?

Завински: Трудно сказать. Я не знаю сегодняшних тринадцатилетних, не знаю, как для них выглядит этот мир. Во всем этом стало сложнее разбираться. Нынешний десятилетний мальчишка не станет курочить свой мобильник, чтобы понять устройство микрофона, как я ребенком делал это со своим телефоном. Сегодня уже ничего не починишь самостоятельно.

Думаю, я пришел к программированию благодаря исследованиям вроде этого: снять крышку магнитофона и посмотреть, как крутятся шестеренки. А сегодня есть только наборы LEGO для создания роботов. Пожалуй, этого мало, чтобы пройти подобный путь. Но, как уже сказал, возможно, я ошибаюсь, ведь я не знаю, чем живут сегодняшние тринадцатилетние. Я не знаю современных игрушек. Видеоигры, радиоуправляемые машинки... Конструкторов хороших я не видел. Грустно все это.

Сейбел: С другой стороны, программирование стало гораздо доступнее. Вам уже не нужно осваивать все премудрости ассемблера, прежде чем заставить компьютер делать что-то классное.

Завински: Да. Наверное, современные ребята, которые сегодня учатся программированию, начинают с создания веб-приложений, разработки плагинов для Facebook и тому подобного. Брэд Фицпатрик, создатель Живого Журнала (LiveJournal), — мой друг. LiveJournal родился, когда он просто валял дурака и написал скрипт на Perl, чтобы вместе с друзьями сообщать друг другу что-то вроде «Я собираюсь пообедать». Все началось с небольшого скрипта на Perl, который он затем поместил на веб-сервер. Вероятно, это направление будет развиваться и дальше.