Хабрахабр

[Перевод] Самые позорные ошибки в моей карьере программиста (на текущий момент)

Как говорится, если тебе не стыдно за свой старый код, значит, ты не растешь как программист — и я согласна с таким мнением. Я начала программировать для развлечения более 40 лет назад, а 30 лет назад и профессионально, так что ошибок у меня набралось очень много. Будучи профессором информатики, я учу своих студентов извлекать уроки из ошибок — своих, моих, чужих. Думаю, пришло время рассказать о моих ошибках, чтобы не растерять скромность. Надеюсь, кому-то они окажутся полезны.
Мой школьный учитель считал, что «Ромео и Джульетту» нельзя считать трагедией, потому что у героев не было трагической вины — просто они вели себя глупо, как и положено подросткам. Тогда я с ним не согласилась, но сейчас вижу в его мнении рациональное зерно — особенно в связи с программированием.

Летом я проходила практику в Microsoft, в команде компилятора C. К моменту окончания второго курса MIT я была молода и неопытна, как в жизни, так и в программировании. В частности, я должна была улучшить код x86 для операторов ветвления. Поначалу я занималась рутиной вроде поддержки профилирования, а потом мне доверили работу над самой веселой (как я считала) частью компилятора — оптимизацией бэкенда.

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

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

Вынесенный урок

Как пишут Дэвид Паттерсон и Джон Хеннесси в книге «Архитектура компьютера и проектирование компьютерных систем», один из главных принципов архитектуры и разработки в том, чтобы в общих случаях все работало как можно быстрее.

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

В свою защиту могу сказать, что я пыталась разобраться, как выглядели операторы ветвления на практике (например, сколько существовало веток и как были распределены константы), но в 1988 году эта информация была недоступна. Тем не менее, мне не стоило добавлять специальные случаи всякий раз, когда действующий компилятор не мог сгенерировать оптимальный код для придуманного мной искусственного примера.

Я написала бы меньше кода, но это даже хорошо. Мне нужно было позвать опытного разработчика и вместе с ним подумать, какие были общие случаи, и разобраться конкретно с ними. Как писал основатель Stack Overflow Джефф Этвуд, злейший враг программиста — сам программист:

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

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

Когда я работала в Google над рекламой для соцсетей (помните Myspace?), я написала на C++ что-то вроде этого:

for (int i = 0; i < user->interests->length(); i++)
}

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

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

Вынесенный урок

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

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

Вот что рассказывают о Томасе Уотсоне, легендарном главе IBM:

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

Уотсон спросил, что пошло не так.

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

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

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

Чем хуже, тем лучше

Я читала эссе Ричарда Гэбриела об этом подходе в девяностые, будучи аспирантом, и оно мне так нравится, что я задаю его своим студентам. Если вы плохо его помните, освежите память, оно небольшое. В этом эссе желание «сделать как надо» и подход «чем хуже, тем лучше» противопоставляются по многим параметрам, включая простоту.

Простота интерфейса важнее простоты реализации. Как надо: дизайн должен быть простым в реализации и интерфейсе.

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

Забудем об этом на минутку. К сожалению, я забыла об этом на долгие годы.

App Inventor

Работая в Google, я входила в команду App Inventor, онлайновой среды разработки с поддержкой перетаскивания объектов для начинающих Android-разработчиков. Шел 2009 год, и мы спешили вовремя выпустить альфа-версию, чтобы летом провести мастер-классы для учителей, которые могли бы пользоваться средой при обучении уже осенью. Я вызвалась реализовать спрайты, ностальгируя по тому, как в свое время я писала игры на TI-99/4. Для тех, кто не в курсе: спрайт — это двумерный графический объект, который может перемещаться и взаимодействовать с другими программными элементами. Примеры спрайтов — космические корабли, астероиды, шарики и ракетки.

Поскольку шарики и спрайты ведут себя очень похоже, я создала абстрактный sprite-класс со свойствами (полями) X, Y, Speed (скорость) и Heading (направление). Мы реализовали объектно-ориентированный App Inventor в Java, так что там просто куча объектов. Они обладали одними и теми же методами выявления столкновений, отскока от границы экрана и т.д.

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

Когда спрайты заработали, я решила, что можно реализовать объекты-шарики очень небольшим количеством кода. Проблема была лишь в том, что я пошла самым простым путем (с точки зрения реализатора), указав x- и y-координаты верхнего левого угла контура, обрамляющего шар.

На самом деле нужно было указать x- и y-координаты центра круга, как этому учит любой учебник математики и любой другой источник, упоминающий круги.

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

«Запатчила», а не «исправила», ведь как говорит Джошуа Блох, API вечны. Я наконец-то запатчила это ошибку лишь недавно, десять лет спустя. Пользователи могут задать закономерный вопрос, кому вообще пришло в голову расположить точку отсчета где-то, кроме центра. Не имея возможности внести изменения, которые повлияли бы на существующие программы, мы добавили свойство OriginAtCenter со значением false в старых программах и true во всех будущих. Одному программисту, который десять лет назад поленился создать нормальный API. Кому?

Вынесенные уроки

Работая над API (что иногда приходится делать почти каждому программисту), вам стоит следовать лучшим советам, изложенным в видео Джошуа Блоха «Как создать хороший API и почему он так важен» или в этом кратком списке:

  • API может принести вам как огромную пользу, так и огромный вред. Хороший API создает постоянных клиентов. Плохой становится вашим вечным кошмаром.
  • Общедоступные API, как и бриллианты, вечны. Выложитесь на все сто: другого шанса сделать все, как надо, больше не представится.
  • Наметки для API должны быть краткими — одна страница с сигнатурами классов и методов и описаниями, занимающими не больше строчки. Это позволит вам легко реструктуризировать API, если с первого раза он выйдет не идеальным.
  • Распишите сценарии использования, прежде чем реализовывать API и даже работать над его спецификацией. Таким образом вы избежите реализации и спецификации полностью нефункционального API.

Если бы я написала хотя бы небольшой конспект с искусственным сценарием, скорее всего, я бы выявила ошибку и исправила бы ее. Если и нет, то это точно бы сделал кто-то из моих коллег. Любое решение, которое имеет далеко идущие последствия, необходимо обдумывать хотя бы день (это касается не только программирования).

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

Заключение

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

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

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Проверьте также

Закрыть
Кнопка «Наверх»
Закрыть