Кодеры за работой. Размышления о ремесле программиста
Шрифт:
К остальным я в конце концов нашел подход и выяснил, что их мотивирует. У одного отлично получалось делать “заплатки” и создавать прототипы. Он писал на Perl как сисадмин. Он мог соединять различные вещи, писать скрипты командной оболочки, писать действительно ужасный код на Perl и на Си, но почему-то все это у него работало. Мы поражались: “Черт возьми, как ты умудрился изучить все это и как тебе удалось увязать все эти компоненты друг с другом?”
Мы устанавливали голосовой сервис для Живого Журнала: записываешь что-то и постишь в Живой Журнал. Было очень много динамичного. Адская работа. А ему нравилось. Он разобрался со всем и заставил это работать.
Сейбел: Вы нанимали людей для своей компании. Предполагаю, что и в Google вам тоже приходится этим заниматься. Как вы распознаете в человеке отличного программиста?
Фицпатрик: Обычно я ищу тех, кто много чего написал по собственной инициативе, а не потому, что ему сказали это сделать. Я не имею в виду учебные задания и проекты от предыдущего работодателя. Я о тех, кто чем-то увлечен, кто выполнял сторонние проекты. Как он их сопровождал и насколько серьезно к ним подходил? Вдруг клепал что-то на скорую руку и забывал о проекте?
Сейбел: У вас есть любимые вопросы на собеседовании?
Фицпатрик: Один из вопросов, который я задавал несколько раз, - это вопрос из моего теста на школьном факультативном курсе по программированию: даны два десятичных числа в виде строки произвольной длины, нужно их перемножить. Есть много способов решения этой задачи. Если человек силен в математике - в отличие от меня, - он может найти какой-нибудь изящный и эффективный способ решения. В худшем случае можно создать класс, который выполняет серию сложений.
Я говорю им с самого начала: “Не волнуйтесь. Вам не нужно сделать это предельно эффективно. Сделайте хотя бы как-нибудь”. Некоторые нервничают, не зная с чего начать. Это плохой признак. В худшем случае можно реализовать алгоритм, который применялся в начальной школе.
Я действительно в начальной школе написал программу, чтобы она выполняла за меня деление и умножение в столбик, показывая свою работу. Включая все шаги и зачеркивание. Потом мы взяли задачи, примерно по десять на страницу, я вбил их все в компьютер, а затем переписал решения от руки. То же самое я проделал на химии для нахождения орбиталей электронов. Я тогда кое-что понял: даже при написании такой жульнической программы учишься, потому что для этого нужно действительно глубоко понять задачу.
Сейбел: Думаете, это годится для всех? То есть вместо того чтобы обучать детей делению в столбик, будем учить их программированию: “А теперь напишите программу для деления в столбик”. И написав эту программу, они заодно освоят деление. Или это сработает, только если есть природная склонность к этому?
Фицпатрик: Для меня это сработало. Часто бывает, что кто-то учит тебя чему-то, и ты говоришь: “Да-да, понятно”. И обманываешь себя. Но как только придется заняться этим на практике, понять все граничные случаи, придется на самом деле освоить этот предмет. Но я не знаю, подходит ли это всем.
Сейбел: Говорят, в Google, как и в Microsoft, на собеседованиях задаются вопросы в виде головоломок.
Фицпатрик: Кажется, такие вопросы запрещены или, по крайней мере, не приветствуются. Может, кто-то и задает их, но, скорее всего, в общем случае они не приветствуются.
Сейбел: А вас о чем спрашивали на
Фицпатрик: Например, был вопрос: представьте, что у вас есть несколько компьютеров, подключенных через коммутатор, которые занимают целую стойку. Напишите алгоритм, чтобы каждая машина в стойке знала статус любой другой машины - включена та или нет. То есть задача в целом сводилась к определению присутствия. Это было серьезным ограничением. В основном они описали схему работы сети Ethernet: вы можете послать широковещательное сообщение всем или посылать сообщение по конкретному МАС-адресу. Надо было проанализировать множество различных стратегий для минимизации полосы пропускания и времени определения того, что один из компьютеров вырубился. Это была интересная задача.
Сейбел: Какую из найденных вами ошибкок вы считаете самой серьезной?
Фицпатрик: Я стараюсь их не запоминать. Ненавижу, когда предположения столь сильно расходятся с реальностью. Недавно (это явно не пример самой плохой ошибки в моей жизни) я потратил полтора часа на отладку, потому что писал в один файл, а читал другой - с таким же точно именем, только путь к нему был на один элемент короче. Я продолжал перезапускать этот огромный MapReduce, наблюдая за выходными данными, и наконец запустил GDB для пошаговой отладки. “Какого хрена?
– говорил я себе.
– Ничего не меняется!” В конце концов я глянул на пути и воскликнул: “Бог ты мой!”, - не знаю, как я мог потратить на это полтора часа. Я был так одержим, что даже не вернулся, чтобы проверить корректность командной строки.
И так бывает нередко. Мы постоянно сталкиваемся с подобными вещами в Perl, например, когда переменная $_ не определена в лексической области видимости. Возишься с $_ в сортировке, а на самом деле используешь значение, определенное где-то очень далеко. Эта ошибка доставала нас постоянно, создавая немало проблем. Когда мы наконец выяснили в чем дело, я провел аудит всего нашего кода, и мы ввели правило “никогда не делай этого”.
Сейбел: Какие инструменты вы используете для отладки? Отладчики? Операторы print In? Еще что-то?
Фицпатрик: Я использую операторы print In, если среда позволяет это. Если в среде есть хорошие отладчики, использую отладчик. GDB хорошо поддерживается в Google и порой просто незаменим. Стараюсь использовать его пореже. Я в нем не такой уж большой специалист, но могу осмотреться и представить положение вещей в целом. Если приходится забираться в дебри, то я всегда могу как-нибудь выпутаться. Я люблю утилиту strace, просто не представляю жизни без нее. Если я не знаю, что делает моя или чья-то программа, то запускаю ее под strace и вижу, что конкретно в ней происходит. Если бы мне пришлось выбрать только одну утилиту, я бы выбрал именно ее. Все инструменты, вроде Valgrind и Callgrind, очень хороши.
Но в последнее время, если происходит что-то странное, я поступаю так: “Хорошо, вот эта функция слишком велика; давайте разобьем ее на части поменьше и напишем модульные тесты, чтобы проверить работоспособность каждой части независимо и найти место, в котором мои предположения оказались ошибочными, а не втыкать операторы print In где попало”.
Бывает позже, в процессе рефакторинга, я начинаю думать о коде больше, и проблема становится очевидной. Тогда я могу вернуться к той огромной уродливой функции и исправить ее, но половину исправлений я уже внес; я могу продолжить, чтобы облегчить работу того, кто будет поддерживать код после меня.