«За что бьют сисопа? За отсутствие бэкапа!» Корни этой мудрости потерялись в веках, а само слово «сисоп» уже подзабылось, но за отсутствие бэкапа по-прежнему кого-то бьют. Слабые тела админов и простых пользователей защищает не так уж много производителей ПО, и из них, пожалуй, лидирующим можно назвать Acronis — трудно найти в нашей стране пользователя, данные которого ни разу не были бы спасены программами Acronis от грандиозного факапа. Про админов и говорить нечего — решения этой компании всегда занимали достойное место на загрузочных дисках для оказания первой помощи. А как быть программистам, которые хотели бы в нее трудоустроиться? Когда-то я сам шарил по сайтам с вакансиями и, как сейчас помню, был вдохновлен зарплатой, которую в Acronis обещали программистам на приплюснутом си.

Сегодня мы поговорим с Евгением Панищевым, руководителем QA Cloud направления международной компании Acronis. Его отдел занимается тестированием всех облачных решений Acronis: от Acronis Backup Cloud до Acronis Disaster Recovery. Задача лично Евгения — следить за тем, чтобы специалисты отдела выполняли свою работу еще лучше и эффективнее.

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

Свой выбор задач Евгений объясняет так: «Первый тип задач позволяет проверить логические и аналитические способности кандидата, второй — понять, как именно он мыслит. На собеседовании важно и то и другое; иногда правильное живое мышление важнее верного ответа. Я знаю, что многие пренебрежительно относятся к задачам, предлагаемым на собеседовании, считая их пустой тратой времени, но это ошибка. Такие тесты позволяют за довольно короткое время понять, что за человек перед вами. Чем нестандартнее задачи, тем лучше понимание».

 

Примеры задач

 

Пример 1

Любимое задание Евгения — тестирование калькулятора: кандидату выдают обыкновенный настольный калькулятор и предлагают проверить его работу. Эта задача не имеет точного решения, зато позволяет выявить уровень человека как тестировщика. По тому, какие тест-кейсы он озвучивает, какие уточняющие вопросы задает, как выбирает ключевые параметры тестирования при наличии ограниченного числа тест-кейсов, можно понять, насколько человек разбирается в теме, готов ли учиться и воспринимать подсказки, умеет ли идти на компромисс и отстаивать свою точку зрения.


Если это задание кажется тебе слишком простым, попробуй ответить на вопрос: как именно должен вести себя калькулятор, если произвести на нем действие, результат которого выйдет за пределы разрешенного для экрана количества цифр? Почему ты считаешь, что он должен вести себя именно так?

«Для любого айтишника важно знание алгоритмов, оценка их сложности и умение с ними работать, — говорит Евгений. — Без приличного математического аппарата невозможно стать высококлассным специалистом: чем выше вы подниметесь в иерархии программистов, тем с более высоким уровнем абстракции вам придется иметь дело. Это практически не зависит от того направления, которое вы выберете: математика нужна везде».

 

Пример 2

Чтобы проверить, как кандидат ориентируется в высоких алгебраических сферах, Евгений использует, например, такую задачу: «Дан массив S из n действительных чисел, а также число x. Как за время O(nlogn) определить, можно ли представить х в виде суммы двух элементов из S?»

В целом, по мнению Евгения, теория алгоритмов — это область, которой часто пренебрегают в ходе обучения программированию. «Обычно ограничиваются некоторыми общими словами и примерами. Знание сортировки „пузырьком“ или быстрой сортировки само по себе недостаточно для понимания темы. Кроме теории алгоритмов, необходима логика, а также умение ее применять — желательно всегда и везде».

Чтобы понять, умеет ли кандидат делать правильные умозаключения независимо от внешней формулировки, в Acronis используют следующую забавную задачу:

 

Пример 3

«Если лягушонок зеленый, то он веселый. Если лягушонок не веселый, то он сидит на берегу. Все лягушата либо зеленые, либо пестренькие. Если лягушонок пестренький, то он плавает в воде.

Из этого следует (нужно выбрать правильный ответ или ответы):

  • (A) все лягушата — пестренькие;
  • (B) все лягушата плавают в воде;
  • (C) все лягушата — веселые;
  • (D) все лягушата — не веселые;
  • (E) все веселые лягушата — зеленые».

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

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

Еще одна классическая задача на логику от Acronis:

 

Пример 4

Предположим, что фраза «Завтра будет лучше, чем вчера» верна каждый день. Какое из утверждений может тогда быть неверным?

  • (A) Послезавтра будет лучше, чем сегодня.
  • (B) Сегодня будет лучше, чем позавчера.
  • (C) Послезавтра будет лучше, чем позавчера.
  • (D) Завтра будет лучше, чем позавчера.
  • (E) В 2006 году 1 апреля будет лучше, чем позавчера.

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

Чтобы понять, насколько свободно человек владеет кодом, в Acronis используют задачи наподобие этих:

 

Пример 5

Объясните, что делает этот код:

((n & (n - 1) ) == 0)
 

Пример 6

Найдите ошибку в следующем коде:

unsigned int i;
for (i = 100; i >= 0; --i)
  printf("%d\n", i);
 

Пример 7

Дан текстовый файл размером 32 Гбайт. На тестовой машине установлены Windows и питон. Нужно найти последнее вхождение слова ERROR и вывести десять строчек до и десять после. Как изменится решение, если исходный файл разбит на куски размером 2 Гбайт?

Наконец, есть еще один неочевидный параметр, по которому обычно оценивают кандидата. «Его называют по-разному, но мне больше нравится термин „толковость“. Это некая смесь „соображалки“, умения находить нестандартный подход и вообще работать с новыми и необычными задачами. Задачи для проверки этого качества вызывают самые большие споры. Практически все уже знают вопросы о том, почему крышка у канализационного люка круглая и сколько шариков может поместиться в автобусе. Такие вопросы можно считать дурацкими, но их нужно задавать, чтобы понять, как человек способен справиться с нестандартной ситуацией. Решения может не быть: это в данном случае не главное».

 

Пример 8

В Москве есть служба промышленных альпинистов, которые приводят в порядок внешнюю часть зданий и моют окна с наружной стороны. Оцените, сколько таких альпинистов работает в Москве.

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

Но разумеется, есть и задачи с конкретным решением. Две из них Евгений предлагает вниманию читателей «Хакера». Те, кто первыми пришлют правильные ответы (обязательно с обоснованием), получат в качестве приза от компании Acronis ключи от кварти… нет, стоп, не то письмо. Победитель получит ключ для Acronis True Image 2015 — уникального ПО для резервного копирования в безлимитное облако на один год.

 

Задачи от Acronis

Куда слать правильные ответы?

Правильные ответы принимает Диана Круглова, Diana.Kruglova@acronis.com.
Спеши выиграть ключ Acronis True Image 2015 — уникальный софт для резервного копирования своего PC или Mac в безлимитное облако на один год!

 

Задача 1

Представьте, что у вас есть обыкновенные часы. Они идут точно, без сбоев. В этих часах меняют местами минутную и часовую стрелки. Сколько раз в сутки такие часы будут показывать правильное время?

 

Задача 2

Нужно написать на листе бумаги число 10 000 и обвести его в круг, не отрывая ручку от этого листа бумаги; при этом цифры не должны соединяться друг с другом.

 

Решение задач от компании Custis

 

Задача для разработчиков Oracle

Разработчик баз данных в свой первый рабочий день в компании Custis обнаружил, что в его проекте используется всего одна табличка с данными по отгруженным товарам (Т). В ней собираются данные по дате отгрузки (d), идентификационному номеру клиента (c) и количеству отгруженного товара (s). Разработчик проверил и убедился, что никаких ключей в таблице нет и по одному клиенту может быть сколько угодно фактов отгрузки в один день.

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

select * from V where c = ?

возвращал отчет по указанному клиенту, причем в результате будут отражены все дни текущего года. Аналитик проекта сказал, что пользователи не любят пустых граф в отчетах, так что все отсутствующие отгрузки придется формировать как нулевые.

Как вы думаете, какой view в результате получился у нашего разработчика?

 

Ответ (приведенное решение нестандартное и требует владения особой уличной магией Oracle, но есть и другие варианты)

create view V as
select p.d, T.c, nvl(sum(T.s),0) s
from (
  select
     trunc(sysdate, 'Y')+level-1 d
     from dual
     connect by trunc(sysdate, 'Y')+level-1<trunc(sysdate+366, 'Y')
) p
left join T partition by (T.c) on T.d = p.d
group by p.d, T.c
 

Задача для разработчиков C#

За день до релиза отдел тестирования обнаружил, что отчет об остатках товара формируется около часа. Вам была поручена задача оптимизировать процесс создания отчета. Профилировщик показал, что в коде

var atlasClient = new AtlasClient();
var allProducts = Session
    .Query<Product>()
    .Select(p => new
    {
        Product = p,
        Rests = atlasClient.GetRests(p.Id)
    });

var fewProducts = allProducts.Where(i => i.Rests > 0 && i.Rests < 10).Select(i => i.Product);
var someProducts = allProducts.Where(i => i.Rests >= 10 && i.Rests < 100).Select(i => i.Product);
var manyProducts = allProducts.Where(i => i.Rests >= 100).Select(i => i.Product);

PrintFewProducts(fewProducts);
PrintSomeProducts(someProducts);
PrintManyProducts(manyProducts);

метод atlasClient.GetRests занимает около 98% общего времени построения отчета.

Предложите вариант оптимизации построения отчета. Почему ваш вариант работает быстрее? Сколько времени занимает построение отчета после вашей оптимизации?

 

Ответ (один из вариантов)

  • Используя ToArray() или аналоги, вычислить последовательность allProducts до ее использования при получении fewProducts, someProducts, manyProducts.
  • AllProducts является отложенным Linq-запросом, и его использование в трех выражениях приводит к многократному вычислению элементов последовательности. Вычислив последовательность один раз, мы сэкономим два «дорогих» вызова atlasClient.GetRests на каждый элемент последовательности, но нам потребуется дополнительный объем памяти для хранения результата. Из-за этого при больших объемах данных такое решение «в лоб» не всегда может быть применимо.
  • Такой вариант построения отчета будет занимать около двадцати минут.
 

Задача для разработчиков Java

Разработчик C# решил попробовать себя на поприще Java и перешел в Java-проект. Одно из первых заданий, которое он получил, — сделать таблицу с информацией о проданных товарах. В постановке задачи было написано, что нужны следующие столбцы: имя клиента, код клиента, название товара и стоимость товара. Посмотрев на реализацию такого рода таблиц в проекте, он понял, что при настройке таблицы придется написать что-то вроде

table.add( "customer.name" );
table.add( "customer.code" );
table.add( "subject.name" );
table.add( "summ" );

Прямо скажем, по сравнению с тем, как он делал это на родном dotNet, это выглядело совсем ненадежно — никаких проверок уровня компиляции, очень легко допустить ошибку. Хочется написать

table.add( customer.name );

Или хотя бы

table.add( {} -> customer.name );

А тут такое... Код получается небезопасный, IDE никак не подсказывает, что писать, и вообще... Решив не сдаваться и привнести свет истины в захолустное царство Java, он объяснил проблемы такой настройки таблиц другим Java-разработчикам. Ему отвечали, что проект ведется на Java 7, лямбд нет, а с анонимными классами для каждого поля настройка будет выглядеть жутко, поэтому «пишем, как можем». Однако, найдя единомышленников в стане Java, он смог реализовать движок, который позволял настраивать столбцы вот так:

Payment root = root( Payment.class );
table.add($( root.getCustomer().getName() ));
…

Причем интерфейс настройки таблиц менять не пришлось, то есть на вход table.add приходит все та же строка customer.name. Не пришлось менять и модельные сущности («покупатель», «товар», «покупка» и другие), и даже не понадобилось никаких автогенерированных классов. Этот инструмент начали использовать везде, где нужно было сослаться на цепочку свойств.

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

 

Ответ (описание подхода)

  • root — статический метод, на лету создающий особый прокси-объект вокруг модельной сущности. Все get-методы в этом объекте записывают свои вызовы в глобальную переменную (например, ThreadLocal);
  • $ — статический метод, который из данной глобальной переменной получает полный путь к полю в виде строки.

IT-компании, шлите нам свои задачки!

Миссия этой мини-рубрики — образовательная, поэтому мы бесплатно публикуем качественные задачки, которые различные компании предлагают соискателям. Вы шлете задачки на lozovsky@glc.ru — мы их публикуем. Никаких актов, договоров, экспертиз и отчетностей. Читателям — задачки, решателям — подарки, вам — респект от нашей многосоттысячной аудитории, пиарщикам — строчки отчетности по публикациям в топовом компьютерном журнале.

6 комментариев

Подпишитесь на ][, чтобы участвовать в обсуждении

Обсуждение этой статьи доступно только нашим подписчикам. Вы можете войти в свой аккаунт или зарегистрироваться и оплатить подписку, чтобы свободно участвовать в обсуждении.

Check Also

Брут на GPU. Запрягаем видеокарту перебирать пароли

Современные видеокарты похожи на компактные суперкомпьютеры c производительностью в нескол…