Норвиг: Это так. И я наблюдаю это у молодых программистов. Еще одна разница между "тогда" и "сейчас": программирование больше похоже на сборку из готовых модулей, чем на создание чего-то с нуля. Сейчас, делая домашнее задание - скажем, сайт, - школьник возьмет для одной части Ruby on Rails, для другой - Drupal, для третьей - скрипт на Python, а потом скачает статистическую программу. И все это связывается между собой с помощью скриптов, а не пишется с нуля. Сегодня важнее понимать интерфейсы и уметь их соединять, чем знать в деталях, что делается внутри ПО.
Сейбел: Значит ли это, что успешный программист сегодня - человек другого склада?
Норвиг: Успешные люди, по-моему, не изменились, насколько я вижу. Но в целом - да, в наши дни лучше уметь быстро понять, что тебе нужно, чем досконально знать все процессы. Тут, конечно, есть этакая бравада: "Я просто беру и делаю это". Человек смело признается: "Я не понимаю, что тут внутри, но я залез в документацию и нашел там эти три штуки. Попробовал - работает. Значит, вперед".
Да, такой подход приносит свои плоды, но мне кажется, только за счет этого не станешь хорошим программистом. Надо знать немного больше. Безопасно ли то, что я делаю? В каких случаях это сломается? Попробовал один раз, работает - хорошо, но это должно работать всегда. Как написать тесты, чтобы проверить программу и самому лучше разобраться в ней? А когда они написаны, не взять ли мне то, что я сделал, и не опубликовать ли новый инструмент, чтобы другие им тоже пользовались?
Сейбел: Какие у вас были предпочтения в плане командной работы? Взять задачу и разделить ее между программистами? Или везде применять парное программирование с коллективным владением кодом?
Норвиг: Скорее первое. Стив Йегг написал статью "Good Agile, Bad Agile" (Agile-проектирование: хорошее и плохое), и думаю, в ней он прав. Десять процентов времени имеет смысл уделять коллективной работе, поскольку программисту необходимы понимающие слушатели. Больше - вряд ли стоит.
Двум хорошим программистам лучше работать отдельно, отлаживая затем сделанное друг другом, чем согласиться на 50% падения производительности только ради лишней пары глаз.
Иногда полезно собираться вместе для мозгового штурма, когда надо определить и задачу, и средства ее решения. Вы даже не знаете, что за продукт вам нужен, и об этом стоит подумать совместно. Затем вы определяетесь с задачей, и надо решить, как разбить ее на части. Но вот после этого, когда идея пришла, лучше работать по отдельности. Нужна обратная связь, нужен другой человек, который внимательно просмотрит ваш код, - но только не в режиме реального времени, не в процессе написания.
Помнится, у IBM была модель "программиста-мастера" - глупее никто еще ничего не придумал. Кто захочет быть на побегушках у опытного программиста?
Сейбел: Удивительно, что вы считаете эту идею настолько глупой. В своей статье "Teach Yourself Programming in Ten Years" (Как самому научиться программировать за десять лет) вы утверждаете, что программирование - навык, который, как и многие другие, требует десятилетнего оттачивания, чтобы человек стал мастером. Во многих ремеслах работает модель мастер/подмастерье/ученик. Может, никому не нравится быть учеником, но что ужасного в том, что человек с десятилетним опытом будет выполнять другую работу, нежели желторотый новичок?
Норвиг: Лучшее в такой модели - возможность для ученика наблюдать за работой мастера. Вот таких возможностей должно быть больше. Это вариант парного программирования. Особенно полезно для начинающего наблюдать за тем, чему особо не учат, например за отладкой. Можно заучить алгоритмы, но так не научишься отладке. А вот смотреть, как опытный программист делает что-то, о чем ты даже не подозревал, очень полезно.
Но мне кажется, эта модель раньше была популярна из-за нехватки материалов. Допустим, у ювелира есть строго определенное количество золота. Или, скажем, когда идет операция на сердце, оно всего одно - нужен лучший специалист, остальные будут на подхвате. С программированием все иначе. Есть множество компьютеров, клавиатур, не надо распределять ресурсы.
Сейбел: К вопросу о том, чему особо не учат: вы занимались наукой, теперь работаете в индустрии. Как вы считаете, компьютерные науки и промышленное программирование правильно взаимодействуют между собой?
Норвиг: Сложный вопрос. Я не думаю, что заниматься наукой - большая потеря времени: есть шанс узнать много нужного. Но вы не узнаете всего, что вам требуется для разработки или производства ПО. Мне кажется, программы в высшей школе медленно адаптируются к реальности. Кое-где есть подвижки, но в целом работать в команде учат мало. Да и этому подходу со сборкой из готовых кусков тоже не особо учат. Однако ребята как-то набираются всего этого, так что в общем дело обстоит неплохо. У нас в Google много масштабных облачных вычислений, параллельного программирования и тому подобного. Индустрия во всем этом заинтересована, однако учат этому редко. Так что высшая школа немного запаздывает, но все равно остается полезной.
Сейбел: Есть ли области, где ученые находятся на переднем крае, где программная индустрия еще не подобралась к новейшим методам?
Норвиг: Отчасти да, есть. Лучший, наверное, пример - проверка моделей, которой Intel не уделила достаточно внимания, и на отзыве ПО из-за найденной ошибки в умножении они потеряли много денег. Тогда они всполошились и пошли на поклон к ученым. Теперь проверка моделей обязательно входит во все их программы. Другой пример, пожалуй, чуть менее яркий - языки программирования. В этой сфере идет напряженная работа, но она мало отражается на новых языках. Операционные системы, в какой-то мере. Мы финансируем лабораторию RAD в Беркли с Дэйвом Паттерсоном и другими. У них есть хорошие идеи относительно надежности систем. Но это тот случай, когда у индустрии есть куда более серьезные проблемы. Не каждую из них удается решить, но поиски здесь идут более интенсивно, чем в университетах.
Сейбел: Значит, вы не считаете, что часть хороших идей, порожденных учеными, не используются просто из-за нежелания перемен? Ведь множество доморощенных PHP-программистов никогда не заинтересуются языком Haskell, пусть даже он будет удобнее?
Норвиг: Тут я настроен скептически. Будь у этого языка серьезные преимущества, его бы уже активно использовали. Не думаю, что у нас идеальный рынок информации, где все тут же бросаются применять новое оптимальное решение, но мы близки к этому. Ученые могут не видеть всю проблему, стоящую перед индустрией, и часть ее - проблема обучения. При множестве программистов, не знающих, что такое монада, не слушавших курса теории категорий, наступает разрыв.
Отчасти причина - в наследии прежних систем, которое нельзя просто так взять и отбросить, - необходим переход. Уверен, есть много областей, где промышленникам следовало бы смотреть дальше: если мы не можем осуществить переход сейчас, давайте хотя бы задумаемся, где мы будем через десять лет, в каком направлении нам двигаться.
Но мы хотим улучшений в тех областях, где это будет иметь большой резонанс. Во многих случаях языки нацелены на слишком низкий уровень, чтобы иметь тот эффект, на который рассчитывают их создатели. Человек говорит: "С моим новым прекрасным языком вот эти шесть строк кода заменяются двумя". Да, это неплохо: язык станет более эффективным, легче будет поддаваться отладке и обслуживанию. Но, возможно, ваш код - всего лишь часть большой системы. Настоящая головная боль начинается, когда надо ежедневно обновлять данные, рыться в Сети, добывать данные, переводить их в нужный формат. Нужно помнить, что вы решаете лишь небольшой подраздел громадной задачи, поэтому вам нужно преодолеть большой барьер, чтобы сделать переход на новый язык оправданным.
Сейбел: Оставляя в стороне исследования в области языков, как вы считаете - мы далеко продвинулись с тех пор, как компьютерные науки ограничивались постижением продуктов IBM?
Норвиг: Да. Сейчас она на хорошем уровне, и жаль, что ее выбирают так мало студентов - все меньше и меньше. Конечно, есть те, кто любит компьютеры и проектирование программ настолько, что в любом случае пойдут туда. Они - наша надежда. Но есть блестящие умы, которые предпочитают физику, или биологию, или еще какую-нибудь из актуальных дисциплин. А кто-то говорит: "Я вроде как люблю компьютеры, но здесь никаких перспектив - все программы пишутся в Индии. Пойду-ка лучше в юристы". Это очень обидно. Мне кажется, людей сбивают с толку.
Сейбел: Обидно потому, что иначе они получали бы удовольствие от программирования? Или потому, что эти мозги нужны отрасли?
Норвиг: И то и другое. Можно получать удовольствие от нескольких вещей сразу, в таком случае не обязательно идти в компьютерные науки. Но мне кажется, здесь просто есть некая недоработка. Нам нужны толковые люди, способные изменить мир. И если это действительно то, чего они хотят добиться, то в компьютерные науки должно идти больше студентов, чем сейчас.
Сейбел: В одной из статей Дейкстра утверждает, что компьютерные науки - это раздел математики. Поэтому те, кто их изучает, вначале - первые сколько-то лет - вообще не должны прикасаться к компьютеру, а вместо этого осваивать обращение с системами формальных символов. Как по-вашему, сколько математики нужно грамотному программисту?
Норвиг: Ну, я не считаю, что надо учиться до уровня, о котором говорит Дейкстра. Кроме того, он сосредотачивает внимание на определенной области математики - дискретные, логические доказательства. Я пришел из сферы, где это не так важно, где все в большей мере основано на вероятности. Мне редко попадаются программы, которые можно проверить формально.
Код Google - он правилен или нет? Введя в Google этот запрос, вы получите десять страниц. Если поисковик даст сбой, код неправилен. А если он даст вот эти десять ссылок вместо вон тех десяти - правилен или нет? Можно говорить о том, что вам больше нравится, но дальше этого вы не пойдете. Это немного не то, о чем мы привыкли думать. Как только сталкиваешься с задачами такого рода или задачами вроде передвижения роботизированного автомобиля по улицам города, чтобы он никого не сбил, логические доказательства отбрасываются очень быстро.
Сейбел: Есть ли базовые навыки, необходимые хорошему программисту? В разных сферах, конечно, разные требования, но есть ли нечто общее в написании кода независимо от сферы деятельности?
Норвиг: Нужно уметь двигаться вперед и улучшать сделанное. Это все, что необходимо в жизни. Нужно порождать идеи, претворять их в жизнь, а потом совершенствовать сделанное. Совершенствовать можно по-разному. Можно сказать себе: "Я сделал это не совсем правильно, некоторые случаи не охвачены". А можно сказать себе так: "Теперь я понимаю это лучше, я создам более абстрактные инструменты, и в следующий раз мне будет легче создать такую систему". "В каком направлении я иду?", "Как я сделал это?", "Можно ли сделать это лучше?" - вот какие вопросы нужно перед собой ставить.
Сейбел: Считаете ли вы, что этот навык - по сути, сделал, отладил, повторил - стоит усвоить многим, и не только программистам? Если бы составляли программу для школы или колледжа, вы бы внесли в нее обязательное программирование для всех? Или это требует особых навыков?
Норвиг: Да, это требует особых навыков. Можно привести и другие примеры для этого типа мышления. Возьмем чисто механическую задачу: есть несколько деталей, и надо сделать так, чтобы вода в конце концов попадала вот в эту чашку. Речь не обязательно о программах - речь о том, чтобы соединять разрозненные элементы и проверять, как они работают в сборе.
Сейбел: Как глубоко нужно изучать программирование? В статье "Как самому научиться программировать за десять лет" вы говорите о том, сколько времени занимает выполнение инструкции по сравнению с чтением с диска, и так далее. Нужно ли программистам, как раньше, знать язык ассемблера?
Норвиг: Не знаю. Кнут советует делать все на языке ассемблера, поскольку Си слишком неэффективен. Я с ним не согласен. Нужно знать кое-что насчет эффективности и неэффективности инструкций, но это больше не относится к каждой конкретной инструкции. Теперь это не о том, исполняется последовательность из трех или из двух инструкций, а о том, случился ли у вас сбой по странице памяти или вы не попали в кэш. Мне кажется, знать язык ассемблера уже необязательно. Нужно понимать архитектуру. Нужно понимать, что такое язык ассемблера, понимать, что есть иерархия памяти и что сбой в переходе с одного уровня на другой сильно отражается на работе программы. Но это понимание может быть и на абстрактном уровне.
Сейбел: Есть ли, по-вашему, книги, которые должен прочесть каждый программист?
Норвиг: Выбор велик, тут можно пойти разными путями. Надо прочесть что-нибудь про алгоритмы - программист не должен становиться только склейщиком программ. Можно взять Кнута, а можно Кормена, Лейзерсона и Ривеста. Есть и другие авторы, например Салли Голдман. В ее последней книге алгоритмы рассматриваются с практической стороны. Довольно интересно написано. Кроме того, что-нибудь про идеи абстракции. Мне нравится труд Абельсона и Сассмана, но он не единственный.
Надо досконально знать свой язык. Читайте справочники. Читайте книги, где объясняется механика языка и одновременно способы отладки и тестирования, - "Beautiful Code" или что-нибудь подобное. Но я бы не стал советовать читать исключительно это, а не что-нибудь другое.
Сейбел: Сейчас вы не так много программируете по работе, но пишете небольшие программы для статей, которые появляются на вашем сайте. Каков ваш сегодняшний подход к программированию?
Норвиг: По-моему, крайне важно умение держать все в голове. Тогда намного больше шансов на успех, легче написать маленькую программку. Для больших программ придется использовать дополнительные инструменты.
Еще очень важно понимать, что делаешь. Когда я писал программу для решения судоку, некоторые блогеры комментировали ее в таком духе: "Сравните, вот это написал Норвиг, а это другой парень, один из гуру разработки через тестирование (забыл, как его зовут). Он сказал, что сначала напишет несколько тестов". Но у него ничего не вышло. Он вывесил пять постов в своем блоге, там было много тестов, но ничего для решения задачи. Он не знал, как ее решать.
А я был знаком со сферой искусственного интеллекта, где есть то же самое распространение ограничивающих условий. Я знаю, как это работает. Рекурсивный поиск - я знаю, как это работает. И я с самого начала видел, как объединить их для решения судоку. А тот парень блуждал в потемках, даже если благодаря своим тестам и создал "работающий" код.
Блогеры начали оживленно обсуждать, что это значит. По-моему, ничего не значит. Разработка через тестирование - отличная вещь, я сейчас применяю ее намного чаще, чем раньше. Но можно тестировать что угодно и при этом не знать, как подойти к решению задачи.
Сейбел: А что нужно, чтобы знать это? Защитить диссертацию и поработать с искусственным интеллектом? Невозможно ведь знать все алгоритмы. Сегодня у вас есть Google, но найти правильный подход к задаче - не то же самое, что найти веб-фреймворк.
Норвиг: Как узнать, чего именно не знаешь?
Сейбел: Вот именно.
Норвиг: Думаю, ответ состоит из двух частей. Первая - признать, что задача, возможно, уже решена. Можно думать, что, конечно же, никто в принципе не знает, как ее решать, поэтому действовать наудачу - метод не хуже любого другого. А можно предположить, что решение где-то есть, и нужно просто найти слова, которыми оно может быть описано. Это отчасти вопрос интуиции - нужно догадаться, что искать следует, скажем, в области искусственного интеллекта. Потом уже ищешь конкретные методы. Может быть, тот парень, поискав по слову "судоку", нашел бы верный ответ. А может, он считал это жульничеством. Не знаю.
Сейбел: Предположим, что это так. Пусть вы были бы первым, кто пытался решить судоку. Методы, которыми вы в итоге воспользовались, все так же существовали бы и ждали своего применения.
Норвиг: Допустим, я решаю некую задачу в области биологии. Я не знаю, какие алгоритмы применяются при генетическом секвенирова-нии, но знаю, что они есть. И я оглядываюсь вокруг. На другом уровне некоторые из таких вещей довольно фундаментальны - если вы не знаете, что такое динамическое программирование, это большой минус для вас. И это будет постоянно проявляться, если у вас нет представления об этой общей модели поиска - сделать выбор и вернуться, когда надобность отпадет. Это идеи родом из 1960-х. Люди открыли это, когда занимались программированием всего несколько лет. Это то, о чем каждый обязан иметь представление. А идеи годовой давности, конечно, известны не каждому.
Сейбел: Значит, надо рыться в старых статьях?
Норвиг: Нет. Было много тупиковых направлений. Потом обнаружилось, что некоторые области, развивавшие каждая свою технологию и терминологию, на самом деле были очень близки друг другу. Лучше бросить взгляд на прошлое из современности, чем заново повторять все шаги. Но взглянуть туда все равно необходимо. Не знаю даже, какие книги посоветовать, - я осваивал все это по частям.
Сейбел: Вернемся к проектированию программ. Если вы работаете над большой программой и не можете вспомнить, как соединяются все фрагменты кода, то что тогда делаете?
Норвиг: Нужна хорошая документация на уровне системы в целом: что она должна делать, как этого добиться. Документировать каждую функцию обычно слишком утомительно. Большей частью лишь повторяется то, что и так можно понять из имени и параметров функции. Но общая документация очень важна, ее следует готовить в первую очередь. Она должна быть понятной всем и предлагать верные решения. Для успешного проекта нужны опытные люди, предлагающие верное решение. Кроме того, когда вы делаете что-то совсем для себя новое и не знаете, как к этому подступиться, лучше всего проявлять гибкость - настолько, чтобы неверное решение можно было пересмотреть.
Сейбел: Создавая что-то совсем новое для вас, как долго вы можете сидеть и обдумывать задачу? Или для лучшего понимания вам нужно начать писать код?
Норвиг: Иногда для осмысления задачи надо вернуться назад. Вы хотите получить на выходе что-то работающее - для некоторых задач есть только один путь к этому. Для других задач есть много равнозначных путей. Все зависит от вида задачи.