Игорь Савчук - Отъявленный программист: лайфхакинг из первых рук
Большинство программистов считают, что это относительно простое задание, поэтому охотно берутся за решение и получают быстрый ответ, но мало кто решает его правильно. После математического подсчета интервьюеры часто просят также смоделировать эту задачу в программном виде (конечно, результаты комбинаторного прогона по конкретным значениям должны совпасть с математической формулой первого ответа).
Должен откровенно признаться, что лично я испытывал серьезные затруднения в связи с внезапным обнаружением непредвиденных трудностей по написанию программ на небольших цветных бумажках уже в процессе прохождения интервью. На своей работе мы предоставляем работодателю уже готовый отлаженный и заранее продуманный код, но задумывались ли вы, сколько исправлений и модификаций кода отделяет его первоначальные схематичные наброски от финальной версии? На интервью такого уровня просто не будет времени и возможности набросать черновой вариант и постепенно его доработать под отладчиком — здесь вы пишете код на лету и сразу поясняете алгоритм. Это и станет вашей окончательной версией решения, которую будут оценивать без всякого снисхождения на полевые условия.
Подобный режим — это когнитивный диссонанс по отношению к стандартному и неспешному офисному программированию, где мы обычно тщательно продумываем и оптимизируем каждый элемент своего решения в тиши кабинета, пребывая в спокойном сосредоточении тет-а-тет с кодом, так любезно подсвеченным в любимой IDE. Также обращаю внимание: как утверждает статистика, при подобном «спортивном программировании» наиболее распространенный тип ошибки — off-by-one error (OBOE). [1 Распространенный тип логической ошибки в программировании, который чаще всего сводится к недостаточному тестированию граничных условий (значений) программы или функции.]
В написании кода важно, чтобы кандидат заметил и исправил свои ошибки самостоятельно. Ошибки, вероятно, будут, но сразу после написания кода его нужно протестировать (в уме) и исправить, этот навык значительно понижает тяжесть вашей вины в глазах ведущего. Это должно стать привычкой и рутинно завершать решение каждой задачи.
В связи с упомянутым джетлагом мой вам совет: если место собеседования территориально далеко от вас, лучше прилететь на пару дней раньше, чтобы успеть с дороги выспаться и акклиматизироваться (хотя в этом случае вам, скорее всего, придется оплачивать это дополнительное пребывание из собственного кармана). Впереди предстоит несколько дней интеллектуального марафона и естественная усталость от долгой дороги — не лучший фон для демонстрации ваших пиковых результатов.
Второй аспект частых ошибок — лингвистический.
Убедитесь в своем произношении. Поверьте, факт того, что вы понимаете, что говорит ваш собеседник, вовсе не означает автоматически, что вас так же хорошо понимают, что ваш акцент не является препятствием для общения. Специфика подобных международных интервью имеет то свойство, что многие участники не являются носителями английского языка, и часто фокусируя все время и силы на технической и содержательной частях интервью, порой игнорируют языковую составляющую. В связи с этим плохое понимание вашей речи может стать вероятной причиной отказа, не забывайте про четвертую компоненту оценки. Попробуйте заранее проверить правильность произношения основной технической терминологии на английском языке.
Например, как правильно произносится слово «procedure»? Обратите внимание на правильность ударения. Очень часто обсуждается тема сложности алгоритма, его асимптотическая оценка и нотация «большое-О», в связи с этим как бы вы произнесли вслух формулу O(log(n))?
Следующий важный момент из частых завалов — активное использование адаптивных методик рекрутерами. В самом простом случае это значит, что чем лучше вы будете отвечать, тем более сложные вопросы будете получать в продолжение интервью. Отчасти поэтому непримечательным середнячкам так часто везет в этом увлекательном забеге. Стремление казаться самым крутым не всегда оправданно, если в реальности вы не соответствуете этому уровню. В любом случае очень важны равномерность и последовательность знаний — это не лотерея, здесь не может быть «любимых вопросов», благодаря которым вы рассчитываете блеснуть. Если вы ответили на какой-то вопрос очень сильно, планка сразу поднимается, и дальше вы должны защищать уровень уже более высокого балла.
Не стоит писать в своем резюме амбициозных фактов, доказать которые впоследствии вы будете не в состоянии. Повторяю еще раз: гораздо выгоднее произвести впечатление крепкого середнячка, чем неведомого никому гения, который не способен отвечать за свои слова.
Покончив с наиболее типичными ошибками, хочется уточнить еще один паттерн. Я слышал, как вы обсуждали со своими курсантами составной допрос — что это значит?
Это еще один распространенный паттерн собеседования. Я называю его «составной допрос» (это когда некий теоретический вводный вопрос красиво компонуется с продолжением — практической задачей на его основе). Например, начав обсуждать теорию «Big O notation», после плавно съезжают к обсуждению алгоритма TLS Handshake, который имеет, мягко говоря, много предварительных вычислений. Для интервьюера этот прием — хорошая возможность оценить, насколько у вас большой зазор в понимании между сухой академической теорией и конкретными реализациями на ее основе. Большая проблема и одновременно узкое место нашего современного образования — то, что эти две важные составляющие подчас никак не связаны между собой.
Чтобы как-то суммировать этот большой объем информации, давайте перечислим наиболее частые и общие темы на подобных собеседованиях, которыми нужно владеть в обязательном порядке.
Нужно хорошо знать хеши, устройство деревьев и графов, главные алгоритмы поиска и сортировок, стандартные структуры данных, основы математики (особенно системы счислений, теорию чисел, основы теории вероятностей и комбинаторику). Кроме того, спецификации основных сетевых протоколов и RFC, работу процессора и памяти, детали TCP/IP и все уровни модели OSI.
Для программистов дополнительно — принципы ООП и основные паттерны, теорию работы компиляторов, а также базовые вещи. Пример последнего — очень частый вопрос о расчете времени и эффективности выполнения (Big O notation).
Для администраторов — основные API-вызовы операционных систем, то есть вызовы типа fork(), иметь хорошее практическое знание Perl. Кроме того, нужно иметь хотя бы один любимый язык, которым вы владеете очень сильно, вместо десяти языков, на которых решили пару стандартных задач в свободное от работы время (и на основании этого самодовольно поставили птичку в своем резюме напротив их наименований).
Как бы ни страшно звучало все перечисленное, требуется знать лишь основы, но знать их нужно уверенно. [1 Проецируя это на действительность бывшего СССР, необходимые знания математики примерно соответствуют уровню 1–2 курса физмата.] Также я хочу коснуться важного момента: требуется понимать то, что было прочитано в различных книгах и интернет-источниках, а не просто механически повторять ранее выученное. К примеру, вот проверочный вопрос из реальной практики собеседований на тему паттернов программирования, который поставил в тупик моего подопечного.
Давайте поговорим подробнее об одиночке (singleton). Является ли одиночка паттерном или антипаттерном? Классическая реализация одиночки приводит к невозможности использования модульного тестирования, почему вы тогда относите его к паттернам?
Подловить новичка на бездумном повторении книжных истин — это сам по себе «паттерн собеседований» в Google, который без должного уровня осмысления, произносимого порой, ставит кандидата в весьма сложные и неожиданные ситуации.
Приведу еще три вопроса-примера в этом же стиле для самоконтроля. Каков физический размер этой Си-структуры в памяти на 32-битовой системе? На 64-битовой? От чего зависит ее размер?
struct foo {
char a;
char* b;
};
Следующий пример — объясните, почему работает такой код:
#include <cstdlib>
#include <iostream>
using namespace std;
int main (int argc, char** argv)
{
cout << argv[argc-1] << endl << argc[argv-1] << endl;
return EXIT_SUCCESS;
}
Третий типичный вопрос на общую сообразительность а-ля Google: Может ли функция возвращать итоговое значение чаще, чем была вызвана?
Хорошо, предположим, мы прошли все испытания и собеседования, отмеренные нам судьбой, и вот мы в ожидании окончательного вердикта. Я знаю, иногда вместо «апрува» присылают некий «Request for evidence». Что это такое и как это влияет на вероятность одобрения?