В один прекрасный день я увидел у них позицию Staff Software Engineer в Оттаве, и памятуя, что ребята работают, в том числе и с большими данными, а соответственно и машинным обучением, по которому я, откровенно говоря, скучаю после работы в IBM, я подался на эту позицию.
Интервью достаточно стандартное — сначала 15 минутный звонок от рекрутера удостовериться живой я или нет, потом часовой рассказ «за жизнь» с другим рекрутером и потом краткая задача минут на 20, которая является своеобразным барьером, отсеивающих ну уж совсем неразумных наверное.
К слову сказать, ровно год назад, в мае 2019 года, я также интервьюировался у них, прошел все вышеуказанные этапы, но получил более вкусный оффер от другой компании, которая находится в 5 километрах от дома, в то время как в офис Shopify надо было ехать в даунтаун, а это около часа, да и парковки там не их дешевых. И именно потому, что в прошлом году мне понравился как процесс, так и адекватность сотрудников — я решил податься снова.
Но в какой-то момент что-то пошло не так.
Началось все с того, что задача, которую мне предложили решить, звучала следующим образом:
Покупатель приходит в магазин чтобы купить продукты. У него есть корзина, куда он может что-то положить, а магазин хочет дополнительно простимулировать покупателя тем, что предоставляет ему дополнительные скидки на товар:
1. Если покупатель купит больше одного яблока, то он получит скидку 20% на все яблоки в корзине;
2. Если покупатель купит пакет винограда, то второй пакет он получит бесплатно.
Итог: посчитать стоимость корзины покупателя при выходе из магазина, при то, что данные даны в следующем виде:
[["grapes", 1],["apples", 0],["peaches", 1]] => 12 [["grapes", 1],["apples", 1],["peaches", 1]] => 15 [["grapes", 1],["apples", 2],["peaches", 1]] => 16.8 ... [["grapes", 3],["apples", 1],["peaches", 1]] => 20
где первый элемент вложенного массива — это наименование продукта, а второй элемент — это количество продукта данного типа в корзине.
Цены на продукты следующие:
— яблоко ($3)
— виноград ($5)
— персики ($7 )
Я сказал ОК, интервьюер спросил какой язык я предпочту, на что я ответил «Java» и начал оценивать задачу.
Мой первый вопрос звучал невинно:
Какую структуру данных мне ожидать в качестве входа?
Ответ был еще более простым:
Arrays (массивы). Создай дополнительный метод и опиши там данные вручную.
Хорошо, подумал я, раз мы не ищем легких путей, а также учитывая, что интервью все-таки на позицию Staff Engineer, то от меня скорее всего хотят увидеть реализацию с использованием абстракции и дженериков, что-то вроде этого:
class Values<T> {
T data;
Values() {}
Values(T data) {this.setData(data);}
public void setData(T data) {this.data = data;}
public T getData() {return this.data;}
}
и их использования:
public class Main {
public static void main(String[] args) {
Values[][] item = new Values[3][2];
item[0][0] = new Values("grapes");
item[0][1] = new Values(1);
item[1][0] = new Values("apples");
item[1][1] = new Values(1);
item[2][0] = new Values("peaches");
item[2][1] = new Values(1);
}
}
а поскольку мы находились на расшаренном ресурсе, то я задал невинный вопрос, а как создать дополнительный класс, поскольку использовать Static сильно не хотелось, да и вроде как в данном случае не полезно.
Я немного удивился, когда услышал ответ навроде — «А зачем? Просто используй массивы и все, зачем все усложнять?». Я специально еще раз переспросил насчет массивов — точно массивы? Ответ был неизменным.
Хорошо, массивы, так массивы, пусть и со статическими классами тогда уж, поскольку начался азарт — задачка оказалась не такая уж и простая, как казалась на первый взгляд.
Второй вопрос, собственно говоря, проистекал из первого:
Каков ожидаемый размер данных?
Держитесь дамы и господа, ибо ответ был классный:
Размер может варьироваться, но не меньше 3 элементов.
Простите? Я конечно могу создать массив с данными динамически, где в качестве длины массива будет параметризированная переменная, но я же должен знать сколько объектов я должен буду вставить в массив — ведь единожды создав массив, я не могу изменить его длину. Поэтому тут уж мне пришлось буквально объяснить интервьюеру, как создаются массивы внутри JVM, почему их размер фиксирован, и почему их длину невозможно переопределить после создания — только создание нового и копирование данных.
В этот момент, когда я объяснял основы «массивостроения», я упомянул List интерфейс и сказал, что вот например ArrayList, как одна из имплементаций интерфейса, хоть и основана на массивах внутри, но позволяет иметь динамический размер.
Интервьюер немного призадумался и сказал — «Отлично, тогда используй ArrayList и вставляй туда данные». К слову сказать, прошло около 15 минут, пока мы все это выясняли и я объяснял ему про массивы (всего давался час). Я спросил как вставлять-то, дженерики используем уже или нет — пока еще ничего не написано, но если и дальше будем идти такими темпами — то можно и не успеть.
Интервьюер выдал очередной перл, после которого я понял, что дело труба. Он просто написал на общей доске следующее:
«grapes» => 1st element
1 => 2nd element
Наверное мой стон было даже слышно, но мне пришлось ему задать вопрос — дорогой мой человек, как же я смогу вставить разнотипные данные в ArrayList без использования абстракции и дженериков? Я ведь обязан объявить тип данных при создании структуры. Ну неужели ты хочешь чтобы я использовал Object и дальше везде занимался приведением типов в зависимости от позиции элемента?
Его наивность меня поразила — «А разве нельзя вставить строковые и числовые данные в лист?». Я говорю, да можно конечно, но либо с абстракцией и дженериками, либо Object и приведение типов, либо не в Java, а например в JavaScript. Потом я уже сам не вытерпел и предложил ну давай мы хотя бы цифры в строковые переменные преобразуем — все меньше работы, уж если ты настаиваешь на ArrayList, но продолжаю дальше — может все-таки можно использовать интерфейс Map?
Интервьюер, хотя и не сразу (не стал я выяснять причины, честно сказать — времени оставалось около 25 минут), согласился и сказал — давай на Map. Я потратил минут 10, чтобы накидать скелет кода, проверил граничные условия и сказал что закончил.
Оказалось не тут-то было и все самое интересное было впереди. Помните скидки? Процитирую условие еще раз:
If customer buys one grapes he gets another one for free. (Если покупатель купит один пакет винограда, то второй он получит бесплатно).
В данном случае можно предположить, что имея данные в формате:
["grapes", 2]
в количестве данного продукта могут быть учтены и бесплатные пакеты винограда. Тогда картина должна быть следующей:
1. Покупатель купил 1 пакет винограда и получил 1 бесплатно. Итог — в корзине 2 пакета.
2. Покупатель купил 2 пакета винограда и получил 2 бесплатно. Итог — в корзине 4 пакета.
3. Покупатель купил 3 пакета винограда и получил 3 бесплатно. Итог — в корзине 6 пакетов.
Заметили паттерн? В корзине винограда должно быть всегда только четное количество. Однако исходя из начальных данных, в корзине также бывает и нечетное количество виограда:
[["grapes", 1],["apples", 0],["peaches", 1]] => 12
[["grapes", 1],["apples", 1],["peaches", 1]] => 15
[["grapes", 1],["apples", 2],["peaches", 1]] => 16.8
...
[["grapes", 3],["apples", 1],["peaches", 1]] => 20
В таком случае давайте будем исходить от противного — раз может быть нечетное количество винограда, тогда в корзине учитывается только тот виноград, который покупатель оплатил. Логично? Вроде да. Варианты когда покупатель просто не взял бесплатный виноград — не рассматриваются.
А теперь внимание — правильный ответ!
1 оплаченный пакет + 1 бесплатный + 1 оплаченный
Это феерично! Как? Ну как же так может быть? Да, я не знаю все, да у меня могут быть пробелы, но объясните же мне — как такое может быть, исходя из условия задачи!? Я попытался ему что-то объяснить, но честно — просто видел пустоту непонимания того, о чем я говорю в глазах собеседника.
Все просто — перед ним цифры, которые он придумал и посчитал с одной стороны, с другой стороны — то что дал я. Мои отличаются, значит какой ответ? Мои неправильные — он же интервьюер и его решение вроде как должно быть правильным. В общем плюнул я на это дело, уже злой был от самой ситуации, так как ожидал чего-то более интеллектуального (именно поэтому и смотрю по сторонам в поисках позиции, где будут более интересные задачи), а оказалось… то что оказалось. Я решил отказаться от этой позиции, но пока писал свой фидбэк, мне пришел отказ из Shopify.
Свой фидбэк я им все-таки отправил с комментариями, что ребята, спасибо что отказали, я боюсь, что все таки бы не смог с вами сработаться и описал ситуацию на интервью, порекомендовав все таки лучше готовиться к интервью даже на простых задачах, которые, как известно, простыми не бывают.
Вот и вся история. Берегите себя и всего вам хорошего.
sam_satan
Все именно так и работает, если в магазине есть акция 2 по цене 1, а вы на кассе предъявили 3 продукта, вы оплатите три.
capjdcoder Автор
Боюсь, что это несколько самоуверенное заявление, поскольку следуя вашей логике об оплате 3 товаров — я должен либо получить 6 товаров, либо акция не работает, поскольку я плачу полную цену за любую единицу товара, но при этом получаю еще одну бесплатно.
Понимаете, в условии задачи не стоит критерий изменения стоимости винограда в зависимости от количества купленного. Поэтому не важно сколько покупатель купит — он всегда будет покупать за полную стоимость, просто вдобавок ему будут навешивать ещё один бесплатно, за каждую оплаченную единицу товара.
Смотрите так — если бы в условии было сказано, что при покупке двух пакетов, цена на оба будет как за один — тогда вы правы, налицо изменение цены. Но когда сказано, купив один, вы получаете второй бесплатно, как подарок, отсюда следует, что изменения стоимости за оплаченный пакет не происходит, но второй ему дарят.
Alexufo
А это зависит от технической реализации акции на кассе. Называться она может как "второй бесплатно" или два по цене одной, а технически выглядеть или как два товара по 50% если их два либо второй товар 100% скидка.
capjdcoder Автор
Может мы просто буквально истолкуем условие?
При покупке одного — второй бесплатно.
Сказано про изменение цены? Нет. Оплачивается полная цена? Да. Сказано про технические детали на кассе? Нет.
Коллеги — проблема интервью в том, что вопросы должны быть максимально четкие, чтобы и оценить ответы также можно было однозначно. Когда возникают ситуации, особенно в режиме временнОго цейтнота, где как вы говорите, зависит от технической реализации на кассе — простите, это выше моего понимания.
Как-то так.