В прошлом году я отметил юбилей: двадцать лет в профессии разработчика ПО. Я хотел написать по этому поводу пост, но тогда у меня не нашлось времени. На самом деле, разработкой ПО я занимаюсь чуть дольше двадцати лет. Хотя первый опыт программирования компьютеров я получил ещё в детстве, серьёзно разработкой я занялся только примерно 25 лет назад, когда поступил в университет. Поэтому начинать свои истории я буду именно от этого момента. Эти истории не столько о ПО, сколько о людях. В отличие от множества подобных постов, в нём не будет ни мудрости, ни уроков. Это просто коллекция историй. Надеюсь, вам понравятся хотя бы некоторые из них.
Просмотр исходников
Первая история произошла в 2001 году, вскоре после поступления в университет. Однажды вечером я пошёл в компьютерную лабораторию университета, чтобы полазить по вебу. Из любопытства я ввёл в адресную строку susam.com и оказался на главной странице сайта. Помню, что текст и баннер выглядели тогда гораздо больше. Разрешения дисплеев были меньше, поэтому текст и баннер закрывали почти половину экрана. Я очень мало знал об Интернете и пытался в нём разобраться. Помню, я задался вопросом: что нужно, чтобы создать собственный веб-сайт, может быть, на susam.com? В этот момент студент постарше, смотревший на мой экран из-за моего плеча, спросил меня, я ли создал этот веб-сайт. Я ответил, что понятия не имею, как их разрабатывать. Он попросил подвинуться, сел на мой стул и нажал View > Source в Internet Explorer. Потом он объяснил, что веб-сайты состоят из HTML-страниц, и что эти страницы — простые текстовые инструкции.
Потом он открыл «Блокнот» и написал простую HTML-страницу, которая выглядела примерно так:
<BODY><FONT COLOR="RED">HELLO</FONT></BODY>
Да, в те времена уже существовал тэг FONT и было распространённой практикой писать HTML-тэги в верхнем регистре. Затем он открыл страницу в веб-браузере и показал, как она отрендерилась. Он показал и другие возможности: изменение шрифта и его размера, центрирование текста и изменение цвета фона страницы. Хотя этот урок длился всего с десяток минут, благодаря ему World Wide Web стала для меня гораздо менее загадочной и намного более захватывающей.
Однако у этого студента были собственные мотивы. После проведённого урока он так и не освободил мне место, продолжив браузить Web и ожидая моего ухода. Я был слишком застенчив, чтобы просить освободить стул. Количество мест было ограниченным, поэтому я вернулся в общежитие, одновременно раздосадованный тем, что не получилось полазать по вебу подольше, и восхищённый тем, что благодаря новообретённым знаниям могу создавать веб-сайты. К сожалению, я так и не смог зарегистрировать на себя susam.com. Этот домен использовался какой-то компанией, продающей турецкую еду. Позже мне всё-таки удалось получить альтернативу: собственный домен .net. Благодаря одной кратковременной встрече в университетской лаборатории я вступил на долгий путь создания и поддержки персональных веб-сайтов.
Вектор сброса
Вторая история тоже произошла во время обучения в университете. Однажды я тусовался с моими друзьями в компьютерной лаборатории. Я сидел за машиной с MS-DOS и микропроцессором Intel 8086, на которой писал ассемблерную программу управления лифтом. В те времена считалось важным намеренно практиковаться в решении придуманных задач с целью совершенствования навыков программирования. В процессе работы над программой я внезапно вспомнил одну деталь о микропроцессоре 8086, о которой мы недавно узнали на лекции. Наш преподаватель рассказал, что при сбросе микропроцессора 8086 исполнение начинается с того, что в CS:IP записывается значение FFFF:0000. Я проговорил вслух: «Интересно, система перезагрузится, если я выполню переход к FFFF:0000?». Я открыл DEBUG.EXE и перешёл к этому адресу.
C:\>DEBUG -G =FFFF:0000
Машина сразу же перезапустилась. Один из моих друзей, становившийся лучшим студентом группы по учёбе в каждом семестре, наблюдал за этим из-за моего плеча. После перезапуска машины он воскликнул: «Как тебе это удалось?». Я объяснил, что вектор сброса расположен по физическому адресу FFFF0 и что значение CS:IP FFFF:0000 в реальном режиме сопоставляется с этим адресом. После этого я вернулся к работе над моей программой управления лифтом и больше особо не вспоминал об этом событии.
Спустя неделю тот же друг зашёл в мою комнату в общежитии. Выглядел он мрачным. «Как ты догадался это сделать? Почему ты решил перейти к вектору сброса?». Наверно, я ответил что-то типа: «Да просто в голову пришло. Я вспомнил эту информацию из лекции и решил попробовать.». Он сказал: «Хотел бы я мыслить так же. Я каждый семестр оказываюсь одним из лучших студентов, но мыслю совершенно иначе. Мне и голову бы не пришло протестировать такую тонкость». Я ответил, что мне просто было любопытно проверить, действительно ли изучаемое нами работает на практике. «Вот именно. Я бы никогда не додумался до чего-то подобного. Я разочарован тем, что лучший в группе, но не так любопытен, как ты. Я решил, что не больше не хочу быть лучшим в группе. Мне хочется просто исследовать и экспериментировать, как ты».
Потом он встал и вернулся к себе в комнату. Тогда я не воспринял это всерьёз. Я не мог представить, зачем ему намеренно отказываться от звания лучшего, которое он получал каждый год. Но он сдержал своё слово. Он больше никогда не становился лучшим в группе. Он всё равно оказывался в верхних строчках, иногда даже в десятке лучших, но не нарушал своего обещания и не становился лучшим. И по сей день, вспоминая этот эпизод, я ощущаю смесь неловкости и гордости. Сделав всего один переход к вектору сброса процессора, я каким-то образом вдохновил человека отказаться от стремления к академической успеваемости, чтобы получать больше удовольствия от учёбы. Разумеется, ничто не мешает получать и то, и другое. Но в конечном итоге, это было его решение, а не моё.
Man in the middle
На моей первой работе после университета я устроился в команду техподдержки, где одна из моих задач включала в себя запуск инсталлятора для установки компонента продукта для Интернет-банкинга у наших клиентов; в основном это были крупные банки. Освоив работу с инсталлятором, я осознал, насколько он нестабилен. Написанный на Python инсталлятор часто сбоил из-за некорректных допущений о целевом окружении, и для успешного выполнения почти всегда требовал ручного вмешательства. В течение первой работы на проекте я основную часть своего времени тратил на стабилизацию инсталлятора и написание пошагового руководства пользователя по его применению. Результат моей работы получил признание со стороны сеньор-разработчиков и руководства. К моему удивлению, руководство пользователя получило больше похвалы, чем улучшения, внесённые в сам инсталлятор. Хотя первые несколько недель были продуктивными, я вскоре осознал, что эта работа недолго будет приносить мне самоотдачу. Я несколько раз писал своему руководству с просьбой перевести меня в какую-нибудь команду, где можно будет работать над чем-то более существенным.
Поначалу мои письма сталкивались с сопротивлением. Однако после множества этапов обсуждений со мной связался человек, слышавший о моей ситуации; он предложил мне команду, менеджер которой, возможно, заинтересуется в собеседовании со мной. Команда находилась в другом городе, я был молод и готов переехать в любое место, где можно найти хорошую работу, поэтому сразу же согласился на собеседование.
Это было в 2006 году, когда ПО для видеоконференций ещё не получило широкого распространения. В день собеседования менеджер по найму позвонил мне по стационарному телефону в офисе. Он начал рассказывать о команде, которая называлась Archie (сокращённо от architecture). Команда разрабатывала и поддерживала веб-фреймворк и базовые архитектурные компоненты, на основе которых и создавался продукт для Интернет-банкинга. Продукт начали разрабатывать задолго до появления опенсорсных фрейворков наподобие Spring и Django, поэтому такие фичи, как маршрутизация API, слои аутентификации и авторизации, управление куки и так далее были реализованы внутри компании в виде Java-сервлетов и JavaServer Pages (JSP). Так как ПО использовалось в банковских средах, оно также должно было подвергаться тестированию безопасности и регулярным аудитам для минимизации риска серьёзных уязвимостей.
Собеседование началось хорошо. Менеджер задавал множество вопросов о безопасности ПО, например, о том, что такое SQL-инъекция и как спроектировать веб-фреймворк, защищённый от XSS-атак. Задавал он и вопросы о программировании, на большинство из которых я отвечал довольно неплохо. Однако ближе к концу он спросил, как предотвратить MITM-атаки. Я никогда не слышал этого термина, поэтому признался, что не знаю его значения. Тогда он уточнил: «Man in the middle», но я по-прежнему не понимал, что это и относится ли этот термин вообще к разработке ПО. Он ответил: «Изучите всё, что сможете, о PKI и MITM. Нам нужно реализовать цифровые подписи для одного из корпоративных банковских продуктов. Это первое, над чем мы будем работать».
В течение следующих нескольких недель я изучал RFC и документацию по инфраструктуре публичных ключей, стандартам криптографии с публичными ключами и близкие к этому темы. Поначалу материал казался пугающим, но после того, как я каждый вечер читал литературу, всё постепенно начинало становиться яснее. Концепции, которые поначалу казались сложными и утомительными, постепенно стали интуитивно понятными и изящными. Через несколько недель я переехал в новый город и спустя месяц в новой команде реализовал фичу с цифровыми подписями. Для её создания мы использовали опенсорсную библиотеку Bouncy Castle. После этого проекта я работал и над другими частями продукта. Самым приятным для меня было осознание того, что мой код становится частью большого продукта, используемого сотнями банков и миллионами пользователей. Особенное удовольствие я получал от того, что моя работа выдерживала тестирование безопасности и аудиты, после чего её утверждали для релиза.
Это была моя первая работа в сфере разработки. Мой менеджер оказался превосходным наставником. Работа с ним помогла мне развить новые навыки, а его поддержка придала мне уверенности, которой хватило на долгие годы. С тех пор прошло почти два десятка лет, но продукт по-прежнему используется и его продолжают активно развивать. На самом деле, на текущем этапе жизни я иногда сталкиваюсь с ним, как клиент. Время от времени я открываю инструменты разработчика в браузере, чтобы посмотреть на исходный код страницы, в котором всё ещё нахожу следы HTML, сгенерированного кодом, который �� написал почти двадцать лет назад.
Спагетти-код
Примерно в 2007 или 2008 году я начал работать над proof of concept разработки виджетов для телевизионной приставки OpenTV. Мне нужно было писать код на сильно урезанной версии C. Я уже проделал солидный объём работы над несколькими виджетами, но однажды заметил, что они время от времени вылетают произвольным образом. Я попытался отследить баги, но мне на удивление сложно было понимать собственный код. У меня получился настоящий спагетти-код, включающий в себя кучу сомнительных операций с указателями, которые почти наверняка были виновниками вылетов, но мне не удавалось найти, где же конкретно возникали ошибки.
Я работал в маленькой команде из четырёх человек, каждый из которых создавал отдельный независимый proof of concept. Самый опытный член команды был нашим техлидом и архитектором. В тот же день я показал ему свои достижения и объяснил, что мне не удаётся найти баги, вызывающие вылет виджетов. Он попросил показать ему код. Вкратце просмотрев его и, вероятно, поняв, что он очень запутанный, техлид попросил отправить ему код в виде tarball, что я сразу и сделал.
Потом он вернулся за свой стол и начал изучать код. Помню, я думал, что он ни за что не найдёт проблему быстро. Я занимался отладкой несколько часов, но всё равно едва понимал, что за код написал сам; это был худший случай спагетти-кода за всю мою карьеру. Почти не надеясь на быстрое решение, я вернулся к отладке.
Спустя всего примерно пять минут он вернулся к моему столу и попросил открыть один файл. Потом он показал, где конкретно прятался баг указателя. Ему понадобилось всего несколько минут не только на то, чтобы прочитать мой запутанный код, но и понять его достаточно хорошо для того, чтобы выявить причину сбоя. Как только я исправил эту строку, вылеты пропали. Я был искренне потрясён его умениями.
Мне всегда нравились компьютеры и программирование, поэтому я предполагал, что уже и так довольно хорош в этом. Однако это событие заставило меня осознать, какой путь ещё мне предстоит пройти прежде, чем я смогу считать себя хорошим разработчиком ПО. За последующие годы я существенно вырос, и сегодня гораздо лучше справляюсь с управлением сложностью ПО, чем в то время.
Анимированные телевизионные виджеты
В ещё одном проекте из того же периода мы работали над ещё одной платформой телевизионной приставки, которая поддерживала Java Micro Edition (Java ME) для разработки виджетов. Однажды тот же самый архитектор спросил меня, смогу ли я добавить в виджеты анимации. Я ответил, что возможно, но чтобы сказать наверняка, надо провести тесты. Прежде, чем продолжать историю, я должен объяснить, какой была структура руководства этим проектом.
Наша маленькая команда, по сути, играла роль поставщика ПО. Готовый продукт должен был выпускаться на рынок под брендом телекоммуникационной компании, предлагающей телевизионные услуги direct-to-home (DTH); приставка была одним из продуктов для пользователей. Приставки производила другая компания, поэтому проект был партнёрством трёх сторон: нашей компании (поставщик ПО), телекоммуникационной компании и производителя приставок. Телекоммуникационная компания спросила нас, можно ли анимировать виджеты, чтобы они появлялись на экране и исчезали плавно. Поэтому архитектор задал мне такой вопрос.
Я начал работать над анимированием виджетов. Тем временем, архитектор и несколько сеньоров посетили совещание с участием всех партнёров. Во время этого совещания он объяснил, что мы исследуем вопрос возможности поддержки анимаций виджетов. Производитель приставок сразу же заявил: «Это невозможно. Наша приставка не поддерживает анимации». Когда архитектор вернулся с совещания и рассказал об этом, я ответил: «Не понимаю. Если я могу нарисовать виджет, то могу и анимировать его. Для этого достаточно очищать экран и перерисовывать виджет в других координатах. У меня уже даже есть работающая версия». И я показал демо анимированных виджетов в эмуляторе.
На следующей неделе архитектор посетил ещё одно совещание партнёров, на котором рассказал новости о наших анимированных виджетах. Судя по его словам, представитель компании-производителя приставок был в гневе. По какой-то причине его расстроило, что при помощи API мы решили задачу, которую компания официально считала для своих приставок невозможной. Он потребовал, чтобы мы немедленно прекратили работу над анимациями, заявив, что наша работа не должна противоречить их официальной позиции. В этот момент вмешался представитель телекоммуникационной компании и попросил его заткнуться. «Вы сказали, что анимации реализовать нельзя, но эти люди показали, что это возможно! Вы производите приставки. Почему вы не знаете, на что они способны?».
Я же тем временем продолжал работу над proof of concept. Он хорошо работал в эмуляторе, но доступа к реальному оборудованию у меня пока не было. Устройство нам пока ещё не прислали, поэтому мои первые proof of concept запускались в эмуляторе. На следующей неделе архитектор планировал съездить в офис производителя, чтобы протестировать мои виджеты на приставке.
В этот момент я был горд тем, что продемонстрировал результаты, которые казались невозможными даже производителю оборудования. Когда же архитектор наконец-то поехал тестировать виджеты на устройстве, возникла проблема. Анимации, выглядевшие очень плавными в эмуляторе, в реальном телевизоре оказались дёрганными. В течение следующих нескольких недель я экспериментировал с частотой кадров, стратегиями буферизации и оптимизации вычислений, выполняемых в цикле рендеринга. Каждую неделю архитектор ездил на тестирование и возвращался с одним и тем же отчётом: анимация немного улучшилась, но всё равно выглядела дёрганной. Слабое встраиваемое оборудование попросту не могло справиться с необходимыми вычислениями и рендерингом. В конечном итоге, телекоммуникационная компания решила, что отсутствие анимации лучше, чем тормозная анимация, и полностью отказалась от этой идеи. То есть в результате всё-таки выяснилось, что разработчики приставок оказались правы.
Благословения
В 2009 году, проработав около года в RSA Security, я начал искать работу, которая показалась бы мне более стимулирующей интеллект, в частности, проекты, связанные с математикой и алгоритмами. Я обсудил это с несколькими сеньор-лидами, но не мог найти ничего подходящего. Но потом однажды старший исследователь RSA Laboratories Берт К��лиски предложил мне встретиться, чтобы обсудить мои карьерные устремления. Подробнее я писал об этом в отдельном посте: Good Blessings.
Мы встретились с доктором Калиски, и он предложил мне несколько вариантов команд, в которые я мог бы обратиться в поисках более интересной работы. Я последовал его совету и в конечном итоге устроился в команду, которая идеально мне подошла. Я проработал в этой команде шесть лет. В ней я писал генераторы парсеров, спецификацию и реализацию формального языка, а также движки индексации и запросов для базы данных петабайтных размеров. В течение этих шести лет я почти каждый день узнавал что-то новое. Этот период остаётся одним из самых интересных в моей карьере. Особенно тёплые воспоминания у меня сохранились от работы над генераторами парсеров вместе с очень опытными инженерами, у которых я многому научился.
Спустя годы я размышлял о том, как короткая встреча с доктором Калиски изменила траекторию моей карьеры. Мне показалось, что я не выразил должным образом мою благодарность за ту роль, которую он сыграл в формировании моего пути. Поэтому я написал письмо с благодарностью и объяснением того, насколько этот разговор повлиял на мою жизнь. Спустя несколько дней доктор Калиски ответил мне: он был рад узнать, что предпринятые мной после нашей беседы шаги оказались успешными. В конце письма он добавил трогательное примечание:
«Одна из моих целей заключается в моральной поддержке людей, делающих шаги в своей карьере; точно так же, как другие вкладывались в меня, передавая благословение от одного поколения к другому».
Таблица рекордов CTF
Эта история началась в 2019 году. В то время я уже был не двадцатилетним разработчиком, начинающим свою карьеру, а staff engineer средних лет с многолетним опытом в низкоуровневых сетевых системах и базах данных. В основном я писал на C и C++, приближаясь к новому этапу своей карьеры, где буду руководить разработкой микросервисов, написанных на Go и Python. Как и у многих людей в этой профессии, компьютеры уже давно были одним из моих любимых хобби. Поэтому хотя за прошедшее десятилетие я преимущественно зарабатывал кодом на C и C++, у меня было и много хобби-проектов на других языках, в том числе на Python и Go. Поэтому переход от системного программирования к разработке приложений оказался для меня достаточно плавным. Не могу даже сказать, что скучаю по работе на C и C++. В конце концов, кто может утверждать, что ему нравится тратить дни на вылавливание багов памяти в дампах ядра, когда можно создавать фичи и приносить реальную выгоду заказчикам?
В октябре 2019 года в рамках Cybersecurity Awareness Month в нашем офисе организовали мероприятие Capture the Flag (CTF). В этом соревновании были представлены всевозможные технические головоломки, от задач по SQL-инъекциям до проблем с небезопасной криптографией. В некоторых задачах нужно было выполнять реверс-инжиниринг двоичных файлов и эксплойтить проблемы переполнения стека.
Обычно меня сильно пугают такие соревнования. Я начинаю нервничать только о мысли о необходимости решать задачи, соревнуясь на время. Но мои коллеги убедили меня поучаствовать. И, к моему удивлению, я справился очень неплохо. За примерно восемь часов я решил где-то 90% задач, в результате оказавшись на первом месте.

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

