Software Engineering Manager Вільям Вен, який вже 13 років працює у Google, провів понад 200 співбесід для компанії та оцінив понад 50 пакетів найму
Зрозуміло, що співбесіда — стресова подія і для інтерв’юера, і для кандидата. Щоб оцінити одне одного у нас є менше години. І не дивно, що інколи ми помиляємось.
Тому протягом багатьох років я ставлю одне запитання з кодингу, яке мені дуже подобається. Воно виглядає простим, але насправді це не так.
У рішенні не більше 30 рядків коду, але вони дають мені можливість правильно оцінити кандидата на будь-яку посаду — від стажера до сеньйора.
Як саме? Це я поясню нижче.
Коли я був джуніор-інженером, я регулярно читав joelonsoftware.com. На мене дуже вплинула одна стаття, де автор сайту розповідав, як проводить інтерв’ю.
Потрібно ухвалити рішення, наймати людину чи ні: а для цього ви маєте зрозуміти, чи вона кмітлива та чи здатна добре виконувати завдання. Чи зможете ви зрозуміти це за менше ніж годину часу?
Особисто я маю освіту в області електротехніки. Я відвідав курс структур даних і написав програму проходження лабіринту для нашого проєкту Micromouse. У мене немає формального досвіду CS, і, хоча програмне забезпечення працювало добре, я б не зміг сказати вам, який алгоритм використовував. Тому я не ставлю запитань, що перевіряють, чи ви проходили певні курси CS.
В Google є жарт. Під час співбесіди кандидату пропонують створити компілятор. Коли він виконає завдання, просять змінити колір кнопки та перемістити її на два пікселі ліворуч.
З мого досвіду роботи над фронтенд-програмами, значна частина роботи FE/BE полягає в читанні/записі зі сховища даних або gRPC, перетворенні даних з одного Protocol Buffer в інший та надсиланні їх клієнту для відтворення.
Не зрозумійте мене неправильно, у нас є багато людей, які працюють над інфраструктурою, інструментами кодування, сховищами, ШІ та пошуком, але я зазвичай проводив співбесіди для інженерів програмного забезпечення загалом, інженерів інтерфейсу або оцінював кодування PM та менеджерів.
За допомогою співбесіди з кодингу я намагався оцінити, як людина буде працювати з моєю командою інженерів, виконуючи щоденні завдання з тестування, кодування та налагодження коду. І підхід до вирішення проблеми був для мене важливіший за диплом.
Given a positive sorted array a = [ 3, 4, 6, 9, 10, 12, 14, 15, 17, 19, 21 ]; Define a function f(a, x) that returns x, the next smallest number, or -1 for errors. i.e. f(a, 12) = 12 f(a, 13) = 12
По-перше, це питання легко зрозуміти, якщо ви вже програмували. Немає різниці, чи мали ви справу з CS та чи є у вас докторський ступінь. Це важливо тому, що мені не потрібно витрачати час на пояснення запитання на співбесіді.
Цей відсортований масив обрано не випадково:
Я починаю з того, що запитую кандидата про тестові випадки, як ті, які я надав для x = 12 і x = 13.
Це здається недоречним у запитанні з кодування, але так я отримую уявлення, наскільки кандидат має досвід у розробці через тестування і межових умовах. Також можна зрозуміти, як ми будемо налагоджувати та перевіряти код.
Як правило, після деяких підказок, ми отримуємо такий список:
f(a, 12) = 12 // number found f(a, 13) = 12 // smaller number found f(a, 2) = -1 // out of bounds too small f(a, 22) = 21 // out of bounds too large f(a, 3) = 3 // exact left boundary f(a, 21) = 21 // exact right boundary f([], x) = -1 // empty array f(null, x) = -1 // invalid input
Ви можете не повірити, але більшість розробників не можуть скласти повний список. Дехто забуває точні граничні випадки 3 і 21 або занадто великі/малі випадки. Дехто — неприпустимі вхідні дані. Дехто використовує метод перебору f(a, x)
, де x = Int.MIN
до Int.MAX
.
А хтось навіть не розуміє, про що я прошу. Кожна помилка розповідає мені, який у вас досвід кодингу.
Далі поговоримо про алгоритм. Так, ми можемо використати метод перебору і задати цикл for
на O(n)
.
Така відповідь прийнятна для наймолодших інтернів. Я брав співбесіди в HBCUfor
та вміння дебажити тестові приклади означало для них найм.
Для всіх інших — переходимо до рішення двійкового пошуку, яке є O(log n)
. Я дозволю обговорити кандидату алгоритм, переконаюся, що він на правильному шляху, а потім попрошу код.
Спробуйте і ви зараз виконати це завдання.
if
/else
? Не хвилюйтеся, мені теж було важко під час першої спроби.
Багато років тому я прочитав книгу «Становлення шеф-кухаря». Там розповідалось про про три різні способи стати кухарем:
Я завжди вважав, що між кухарями та програмістами є схожість. Є ознаки досвідченого кухаря. Те, як вони готують, як тримають ніж і ріжуть овочі. Дуже мало зайвих рухів, і в результаті виходить чудова страва.
У фільмі «Прянощі та пристрасті» головного героя Хасана Кадама попросили приготувати омлет. Так мадам Меллорі змогла вирішити, чи варто їй наймати його.
Моє запитання на співбесіді — це майже те саме, що й цей омлет. Я аналізую, чи досвідчений ви програміст, дивлячись, як ви намагаєтесь вирішити цю добре відому проблему.
Є багато можливих рішень, але найпростіше ітераційне рішення має виглядати так:
function f(a, x) { if (a == null || a.length == 0) return -1; var answer = -1; var low = 0; var high = a.length - 1; while(low <= high) { var mid = Math.floor((low + high) / 2); if (a[mid] == x) { return x; } else if (a[mid] < x) { answer = a[mid]; low = mid + 1; } else { high = mid - 1; } } return answer; }
Бінарний пошук є переважно while(low <= high)
, і ділиться навпіл, доки не буде знайдено елемент. Параметр =
насправді важливий, тому що масив чисел зрештою зменшується до розміру 1
, і вміст циклу while
має виконуватися. Збільшення та зменшення середини на 1
також важливо: це дозволяє уникнути нескінченних циклів.
Знаходження наступного найменшого числа робить це питання трохи складнішим. Логічно об’єднати лінійний пошук з бінарним пошуком, коли ви ініціалізуєте відповідь значенням -1
, а потім оновлюєте відповідь кожного разу, коли значення a[mid]
менше за x
. Якщо x
не знайдено, відповіддю буде наступне найменше значення, коли ви виходите з циклу.
Ті, хто має більше досвіду, можуть додати перевірку попередніх умов, щоб чітко описати граничні випадки:
// Precondition checks // f(null, x), f([], x) if (a == null || a.length == 0) return -1; // f(a, 2) if (x < a[0]) return -1; // f(a, 3) if (x == a[0]) return a[0]; // f(a, 21), f(a, 22) if (x >= a[a.length - 1]) return a[a.length - 1];
Двійковий пошук є однією з найскладніших «простих» проблем кодування. Алгоритм виглядає тривіально, але реалізувати його дуже складно. Джон Бентлі, колишній професор CMU, написав у своїй книзі «Перлини програмування», що лише 10% професійних програмістів (включно з аспірантами) здатні правильно реалізувати його:
«Я був вражений: незважаючи на те, що вони мали достатньо часу, лише близько 10% професійних програмістів змогли правильно розробити цю маленьку програму».
У своїй книзі він написав, що програмістам знадобилося 16 років, щоб написати алгоритм без будь-яких помилок!
«… в історії в розділі 6.2.1 книги Sorting and Searching Кнут вказує, що перший двійковий пошук був опублікований у 1946 році, але перший опублікований двійковий пошук без помилок з’явився лише в 1962 році»
Джон Бентлі, «Перли програмування» (1-е видання), стор.35,36
Але зачекайте, у наведеному вище рішенні все ще є помилка. Помітили?
У 2006 році Джошуа Блох, головний архітектор Google Java, автор Effective Java, виявив, що реалізація Java містила приховану помилку протягом дев’яти років! Розрахунок середньої точки викликав помилки цілих чисел поза діапазоном для сучасних наборів даних великого розміру:
var mid = Math.floor(low + high) / 2); // bad var mid = low + Math.floor((high - low) / 2); // good
Реалізація базового бінарного пошуку напрочуд складна. Додавання повороту наступного найменшого числа дещо посилює труднощі. У випадку пошуку 13
, коли ви налагоджуєте два або три рівні бінарного пошуку, нелегко пам’ятати також про низькі, високі, середні значення та стек.
Будь-яке робоче рішення має містити приблизно 30-40 рядків коду, цього достатньо для одногодинного інтерв’ю, і його легко транскрибувати та робити нотатки. Це питання охоплює повний життєвий цикл тестових випадків від кодування до налагодження. Комісії з найму легко зрозуміти рівень кандидата та мої висновки.
Зауважте, що в комітеті Google із найму на роботу ви маєте 24 години: ви маєте пеглянути чотири пакети співбесід із п’ятьма співбесідами в кожному. Отже, загалом 20 інтерв’ю. І в цей же час ви виконуєте і основні робочі завдання, і маєте встигати відпочити.
Немає ідеального способу оцінити кандидата. Я впевнений, що бував занадто суворим або надто поблажливим до кандидатів.
Подібно до наведеної вище аналогії з шеф-кухарем, я аналізую, чи є у кандидата необхідні мені навички.
Я зверну увагу на:
Find_X_Or_Next_Smallest_Impl_Factory_Builder_Singleton(…)
while
, if
, else
тощо, залишається достатньо місця для заповнення коду, що лишився.0
до length-1
.==
в операторах if
, а не тільки =
. Дужки відкриваються і закриваються.if (a[mid] < x)
чи if (x > a[mid])
? А ще я братиму до уваги таке:
Якщо інтерв’ю відбувається з кмітливим стажером чи джуніором, я б очікував, що вони завершать двійковий пошук за годину. Я б дещо підказував, особливо щодо тестових випадків та налагодження, але очікував би від них значного прогресу та мінімальних синтаксичних помилок.
Інженери середнього рівня мають визначити більшість тестових випадків, реалізувати робоче рішення двійкового пошуку з незначними помилками та налагодити код з моєю мінімальною допомогою. Якщо кандидат достатньо досвідчений, він, швидше за все, завершить це завдання до закінчення співбесіди і у нас буде час і для другого запитання.
Що стосується сеньйора, він мусить встигнути відповісти на це запитання, щоб ще залишився час. Він, швидше за все, використовуватиме попередні умови та знатиме про помилку середньої точки переповнення. Цей кандидат може допускати незначні помилки, але має швидко виправляти їх.
Якщо це співбесіда з PM чи Engineering-менеджером, я б дещо коригував свої очікування, в залежності від їх рівня. Ці люди повинні розуміти, як кодувати, але не мають робити це ідеально.
По суті, я завжди оцінюю, чи взяв би цю людину на роботу в свою команду чи ні, і на кого з товаришів по команді він/вона найбільше схожі? Чи їхній код і поведінка свідчать про те, що вони кмітливі та можуть виконувати завдання?
Найкраща характеристика, яку я можу прочитати або написати в пакеті найму, це те, що співбесіда була схожа на обговорення дизайну з колегою-інженером з Google.
Моя мета — не похвалитись, яке чудове запитання я вигадав для співбесід. Я хочу підкреслити, що вам не потрібне надскладне запитання, щоб ухвалити рішення. Дивіться не лише на код, який пише кандидат, а й на те, як він його пише, як шукає помилки.
Наскільки мені відомо, один із моїх старих товаришів по команді все ще використовує це запитання. Тож успіхів йому і вам також, якщо ви проходите співбесіду в Google.
Текст адаптувала Євгенія Козловська
Читайте також: «Він, напевне, вважає мене ідіотом»: як ChatGPT проходив співбесіду в Google та відповідав на підступні питання
Резиденти Дія.City сплатили до бюджету понад 8 млрд грн податків в І кварталі 2025 року.…
У Китаї закликають офісних працівників не працювати надто багато — держава сподівається, що вільний час…
Експерти звертають увагу на тривожну тенденцію: люди все частіше використовують ChatGPT, щоб визначити місцезнаходження, зображене…
Компанія JetBrains випустила нову версію мультимовного середовища розробки IntelliJ IDEA 2025.1. Оновлена IDE отримала численні…
Платформа обміну миттєвими повідомленнями Discord впроваджує функцію перевірки віку за допомогою сканування обличчя. Зараз вона…
Wikipedia намагається захистити себе від тисяч різноманітних ботів-скрейперів, які сканують дані цієї платформи для навчання…