Сейбел: Теперь вы в потоке, и вас нельзя прерывать.
Армстронг: Да-да.
Сейбел: Как я понимаю, остается множество вещей, которые нужно разобрать на уровне кода. Вам нужно сосредоточиться.
Армстронг: Именно так. Но есть два типа сосредоточения. Вещи, которые требуют реального сосредоточения, не те, что можно сделать автоматически, — это вещи, которые надо обдумывать. Это своего рода хитрая сборка мусора, нужно понять, что именно и где разметить. Нужно крепко подумать. Ты знаешь, что решение найдется, потому что ты его уже ограничил со всех сторон. И знаешь, что оно в этом маленьком черном ящике.
Когда Микеланджело расписывал, к примеру, потолок Сикстинской капеллы, у него была команда помощников. Он сперва рисовал общий вид фрески — вот здесь все закрасить голубым, а здесь зеленым. Это напоминает создание программ. Сперва общий набросок, где все расставлено по местам. Некоторые области можно закрасить одним цветом и довольно быстро — это не требует размышления.
А вот рисовать глаза — хитрое дело. Знаешь, что можешь сделать это и что глаза на верном месте, потому что набросок правилен. Начинаешь прорисовывать глаза в деталях. Это не так-то просто, надо всерьез сосредоточиться. А если взять лоб или щеки, особого сосредоточения не нужно — это однородные области. Допустим, на щеках пробиваются волосы, но все равно можно сосредоточиться наполовину.
Затем все набираешь, исправляешь синтаксические ошибки, запускаешь несколько небольших тестов, чтобы проверить, как работает программа. Тут уже можно расслабиться. Увидел мелкую ошибку компиляции, исправил. Поднаторев в языке, можно даже не читать диагностику. Там все равно только номера строк. Ага, такая-то строка неправильная, нужно ее переписать.
Когда я читал курс лекций по Erlang в Чикаго, то бродил по классу и понимал: так, здесь что-то не то. Здесь пропущена запятая или программа даст сбой еще до такого-то события, а у вас нет связей. Моя жена — отличный корректор, сразу видит ошибки. Пропущенная запятая, орфографическая ошибка буквально бросаются ей в глаза. Мне бросаются в глаза ошибки в чужом коде. Это почти бессознательно: смотришь на экран — и бац! — видишь ошибку. Так что речь идет об исправлении несущественных погрешностей.
Сложнее найти небольшие ошибки в написании имен переменных. Чтобы избежать их, я специально подбираю для разных переменных очень непохожие имена. Например, легко спутать переменную person-Name и список имен personNames, поэтому переменную я называю person-Name, а список — listOf People. А вот пунктуацию я вижу хорошо — все, что касается запятых, скобок и так далее. Плюс к тому Emacs сам все раскрашивает, сам делает абзацные отступы, разные скобки выходят разного цвета. Работа сильно облегчается.
Сейбел: Когда вы переходите к написанию кода, то откуда начинаете — сверху, снизу, с середины?
Армстронг: Снизу. Я пишу небольшой фрагмент и тестирую его, потом еще один и так далее. Сейчас пишу сначала модульные тесты, а потом уже код. И твердо уверен в своем подходе.
Сейбел: Вернемся в прошлое. После Шведской космической корпорации вы работали в исследовательской лаборатории компании Ericsson?
Армстронг: Да. Это было счастливое время, на редкость счастливое — кажется, 1984 год. Я пришел в лабораторию года через два после ее создания, там царил оптимизм. Мы считали, что решим все задачи, убедим руководство запустить новые проекты, производительность компании взлетит. Эти взгляды не имели ни малейшего отношения к реальности. Мы полагали, что придумаем новые полезные программы, и мир встретит нас с распростертыми объятиями. Позже мы поняли, что открывать новые вещи не так-то легко. И невероятно трудно убедить людей пользоваться новыми, более совершенными вещами.
Сейбел: Erlang относился к этим новым, более совершенным вещам?
Армстронг: Да, разумеется. Вначале был Пролог. Я создал нечто вроде небольшого языка, люди стали им пользоваться. Роберт Вирдинг поглядел и сказал: «Прикольно», — а потом спросил, можно ли слегка изменить мой Пролог. Вообще, это довольно опасно — Роберт пишет в комментарии к программе: «Джо придумал, я кое-что изменил», — но на самом деле меняется все. Так что мы переписали код от и до и крепко спорили: «Не могу прочесть твой код, сплошные пробелы после запятых», — в таком духе.
Наконец мы обнаружили кое-кого в Ericsson, кому нужен был новый язык программирования — или, скорее, им нужен был более лучший подход в программировании телефонии. Мы встречались с ними раз в неделю, так продолжалось полгода, может быть, месяцев девять. Общая идея была такова, что они узнают от нас о программировании, а мы от них — о телефонии, о том, что тут за проблема. Это было очень трудно, но при этом стимулировало нас. Язык изменился, поскольку перед нами были живые люди, которые пользовались им, проводили исследования. По результатам они говорили: «Хорошо, но слишком медленно», — и указывали, что все должно работать в 70 раз быстрее. Итак, мы взялись выполнить их требования, заставить язык работать в 70 раз быстрее за два года или около того.
У нас было несколько фальстартов, были и тяжелые моменты. И была одна крупная ошибка. Никогда не обещайте людям, что все будет работать с такой-то скоростью, не осуществив реализации. Но наконец мы поняли, как это сделать. Я написал компилятор на Прологе, Роб занимался библиотеками и разными программами. Примерно после двух лет работы я подумал, что смогу реализовать эту абстрактную машину на Си, — так мне впервые довелось писать на Си. Майк Уильяме, случившийся рядом, посмотрел мой Си-код и сказал: «Это самый плохой Си-код, который я видел в жизни. Никуда не годится». Не думаю, что было настолько плохо, но Майку не нравилось. Поэтому Майк создал виртуальную машину на Си, а я — компилятор на Прологе. Затем компилятор скомпилировал сам себя, произвел байт-код, мы вставили его в машину, поменяли грамматику и синтаксис, скомпилировали компилятор в нем самом и получили нечто такое, что могло самозагружаться. Дело пошло. Это был уже не Пролог, а новый язык.
Сейбел: Было что-нибудь, что оказалось трудно встроить в Erlang?
Армстронг: Да. Мы полностью абстрагировались от памяти. Если вы переводите картинку из JPEG в двоичное изображение, а это очень сильно зависит от точного места размещения данных, получается так себе. Неважно получаются алгоритмы, работающие через деструктивное изменение состояния.
Сейбел: Если бы вы создавали большую программу для последовательной обработки изображений, то писали бы код для преобразования картинок на другом языке?
Армстронг: Да, на Си, или на ассемблере, или на чем-то еще. Или на диалекте Erlang с последующей кросс-компиляцией между Erlang и Си. Создать диалект — своего рода предметно-ориентированный язык[57]. Можно было бы также написать программы на Erlang, которые бы генерировали программы на Си, а не писать последние от руки. Но целевой язык — Си, или ассемблер, или что-то еще. Писать от руки или генерировать? Интересный вопрос. Я склоняюсь к генерированию — это проще.
Но я бы использовал структуру Erlang. У меня есть кое-что для создания семейного альбома и всего такого. Там я использую ImageMagik и несколько консольных скриптов, но управляю всем из Erlang. Я просто пишу обертки вокруг них, запускаю osxommand и потом команду в ImageMagik. Обертки — это удобно. Я бы не хотел обрабатывать картинки в Erlang, писать это на Erlang глупо. Си для этого подходит куда больше.
Сейбел: И, кроме того, уже написан ImageMagik.
Армстронг: Вот это меня совершенно не волнует. Если бы я писал это на OCaml, я бы взял и написал это, потому что в OCaml можно достичь эффективности такого рода, но Erlang делать этого не может. Будь я OCaml-программистом, что бы я сделал? Переписать ImageMagik? Поехали!
Сейбел: Просто потому, что написать свое увлекательнее?