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

Я сам опытный интервьювер и собеседовал сотни кандидатов. А так же достаточно часто собеседовался в поисках работы. Открою карты сразу и опишу свое отношение к тестовым заданиям и процессам интервью: обычно я стараюсь их избегать при прочих равных в выборе. Я не против оплачиваемых тестовых заданий, либо совместных кодинг сессий за компьютером с интервьювером. Считаю что задачка должна быть достаточно компактной и решение занимать не больше пары часов - с одной стороны так можно проверить навыки кодинга кандидата, а с другой стороны не забирать драгоценное время жизни на сферический код в вакууме. Ну и это должен быть диалог двух специалистов, а не выдача "на дом" того с чем кандидату могут помогать поисковая система и сокурсники из Мумбая.

Это только присказка-сказка впереди

Пару слов про процессы интервью. Работодатель может реально оценивать себя и то чего хочет достичь. Если нужен реальный инженер, который знает, умеет и имеет подтвержденный опыт в индустрии и компания не из FAANG: Google, Microsoft, Facebook, Amazon итп., то можете не придумывать свои мануалы для кандидатов про процессам длиной в жизнь с алгоритмическими задачами, поведенческими интервью, комитетами и прочей бюрократией. Сюда же и ожидания что инженер будет час расхваливать историю компании и цели при вопросе "Почему вы выбрали нашу компанию? Что вы знаете о ней?". IMHO человеку с опытом в индустрии разработки ПО достаточно просто не быть чудаком с буквы м, чтобы пройти отбор на софтскилы. Мы не говорим сейчас про менеджеров в управлении разработкой, там царят другие правила отбора.

С чем я столкнулся с октября при поиске работы, что рынок перевернулся с ног на голову - сейчас это не рынок кандидата на иностранные вакансии и работодатели снова диктуют условия на отбор. Опять же все это пока и ждем когда вернется дефицит, все циклично. Почему я не хочу работать на какого-либо ИП или российскую корпорацию оставим вне контекта этой публикации. Хотя... Последние 9 лет я работал в международных компаниях и привык к комфорту для психики, баланса личного времени и финансов в сравнении с тем что предлагал российский рынок. Также я проработал в другой стране с декабря 2021 в одном из крупнейших туристических агрегаторов на азиатском рынке, бигдатя бигдату. Только сейчас начал признаваться себе что где-то я погорячился с уходом с последнего места работы. Пусть сфера туризма еще полностью не отошла от пандемии, со всеми вытекающими для работника.

Из нескольких вариантов компаний что нашел месяц назад, я решил податься туда где процесс был более простой и реалистичный. Первый этап - созвон с HR специалистом и разговоры о жизни и мотивации. Второй этап - hackerrank тест на 45мин. Третьий - поведенческое интервью с техническим руководителем. Четвертый этап это тестовое задание на Java, по словам HR это где-то на 4-6 часов но строго с секундомером не следят за временем выполнения. После всех этих шагов может последовать оффер или еще один этап с CTO.

Типичные процессы интервью в последние 16 лет у меня были - общение с HR, техническое интервью иногда совмещенное с интервью с менеджером или техдиром и оффер следом иногда с проверкой службы безопасности до этого! Почувствуйте разницу.

Альтернативой в тот момент еще было общение с HR на вакансию Fivetran - я сразу же попрощался когда узнал какой у них длинный процесс с решением алгоритмических задач в виде онлайн кодинга. Да и "усталость" и тон разговора со мной кадрового специалиста насторожила с первых же минут видео созвона. Потом посмотрел что у них прилично разработчиков в офисе в Индии и сделал вывод "откуда у этого процесса растут ноги".

Пока опущу часть самопрезентации, чтобы не перегружать статью и сфокусироваться на главном!

Интервью

Итак возвращаемся к основной теме и потенциальному работодателю этой публикации. Первое - было удержать себя и не послать куда подальше при предложении пройти отсев через hackerrank, второе - через тестовое задание. Я конечно рассказывал кадровику о своем опыте, кидал ссылки в письме на open source проекты и доклады но это вызывало лишь покерфейс и бубнение что "мы верим в наши процессы отбора, они помогают нам найти лучших работников". Вы-то верите в это, а кандидату скорее показывает что нет никакой гибкости в процессе найма и вам лень тратить свое время на переход на мои PR Github одного из 10K* проекта разрабатывамого под крылом Apache Software Foundation. Ладно "запишем на карандаш" и перейдем к следующему шагу.

Hackerrank тесты были простые: 8 заданий, общие вопросы по микросервисам, разработке ПО и одна задачка на что-то там алгоритмическое с картриджами. Сделал за 43 минуты из выделенных 45, при этом первые 3 минуты боролся с отвращением и мотивировал себя пройти через это "унижение" для матерого специалиста. Камон ребята, я же не выпускник коледжа по разработке программ из Бангалора. Что только не разрабатывал за свою карьеру и тем более активно участвовал в open source проектах в свое свободное время.

Задачка про картриджи:

Решение выбрал для выполнения на привычной мне Java и реализация прошла все тесты:

Поведенческое интервью с техническим руководителем мне понравилось тем что тут уже все было как обычно - рассказать о своем опыте, спросить про их проект. Сначала представился потенциальный руководитель Александр, рассказал о своем опыте на проекте Technology Compatibility Kit (TCK) для JavaME. Потом описал себя как профессионала в трех прилагательных. Потом была моя очередь, распушил хвост и рассказал о своем опыте, лучших проектах, релевантном опыте, где и как я боролся со сложностями в реальных проектах и потом без подготовки тоже выдал какие-то три рандомных и позитивных прилагательных о себе. Этот этап прошел успешно, обещали подумать пару дней но ответ что я успешно прошел это интервью пришел уже через несколько часов.

И вот тут снова пришло письмо с предложением выслать мне неоплачиваемое тестовое задание, как буду готов к его реализации.

We all have really enjoyed our conversations with you so far.

 You've
done great during the interviews, so we would like to move to the final
phase of the interview process with you — which is a Test Task.

This
is a technical task that could take about 4-6 hours to complete, this
estimation may vary depending on the candidate's availability and
skills. We have decided that it would be the best to confirm when you
are ready to start working on a project like that and send it by that
time, so we can expect to receive the results back in 1-3 days after we
send the task. Could you please let us know when would it be convenient
for you to receive the task from us?

I've also cc'ed Alexander in case you will have any technical questions when you receive the task.

Thanks for taking the time to go through our process, we're looking forward to hearing from you!

Я конечно попытался напомнить о том, что я уже говорил на HR интервью, чтобы избежать бесплатного программирования без какого-либо практического смысла для себя:

Thank you for good news. I'll have some time to implement Test Task tomorrow after 19:00 PM Maldivian time (GMT +5) but not with pleasure as from my point of view it looks like exercise for student without real experience and hiring process is not flexible enough... I have open for anyone strong proof of my work experience in top rated open source projects like Apache Arrow, Spring Framework/Boot, SchemaSpy, H2 etc

The most fresh example my Apache Arrow 10.0.0 (26 October 2022) contributions: 

https://github.com/apache/arrow/pulls?q=is%3Apr+author%3Aigor-suhorukov+is%3Aclosed

and in  https://arrow.apache.org/release/10.0.0.html

This technology using under the hood in many cutting edge Big Data frameworks and databases as Apache Spark and PySpark, Dremio, ClickHouse DB...

I hope that your company also shares common agile software methodology value "Individuals and interactions over processes and tools"

  Regards,

      Igor

На что был ответ:

Hi Igor, Hope your weekend was great.Yes, we do understand your point, but at the same time we need to evaluate all the candidates in the process fairly to each other and we need to compare the results with the same type of the task. Sure, I will send you the task by the time you.  Thank you and have a great rest of the day!

Тестовое задание

После того как я получил по почте следующий текст и тестовые данные в zip архиве, я засучил рукава и начал работать.

# Project:
It’s known that emails can have attachments, some even have other emails as attachments. This
allows them to have attachments at any level of nesting. Emails can be stored in so called
Internet Message Format, files in this format usually have .eml extension.

Let’s assume that someone could execute the following operations for arbitrary number of times
in a random order:
- Attach EML or ZIP file to the email
- Archive list of emails to the root folder of ZIP archive

So the sequence of operations is a storing format for the original set of files. For example ZIP
archive can contain emails with ZIP archive as attachment and the last one ZIP archives contain
emails with email as attachment (see samples provided).
  
# Requirements:
You need to write a CLI program that extracts files from the provided file based on the provided
format. See sample output for the sample above.
You must not guess input file format and the program should allow the user to specify input
format in some way, as a command line argument for example. Program should raise an error if
an input file cannot be converted based on the provided format.
For EML files handling it is highly recommended to use Java Mail library
( https://javaee.github.io/javamail ), MimeMessage, Multipart,BodyPart classes in particular.
For ZIP files handling it is recommended to use java.util.zip package from Java SE.
Solution should have quite good quality, which means it should be covered by tests, be able to
work with real-life emails (as this one) and quite large ZIP archives.

Код моего решения я выдал за 4.5 часа сразу же. Это при том что я еще задал пару вопросов по почте в самом начале после ознакомления с заданием, но из-за лимита времени приступил к следующим подзадачам:

  • Уговорить себя не отказаться сразу, а сделать неоплачиваемый тест. Почти час я боролся с собой и смог сфокусироваться только на задаче.

  • Разобраться с парсингом MIME формата сообщений и как сделать рекурсивную распаковку содержимого в ZIP.

Первым делом я добавил в проект тестовые данные из письма с заданием, потом начал искать зависимости на mvnrepository.com

Мое решение со всеми артефактами доступно на github. Основная логика задачи:

package com.github.isuhorukov.email;

import com.beust.jcommander.JCommander;
import org.apache.commons.io.IOUtils;

import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * My email attachment example for IoT system https://github.com/igor-suhorukov/alarm-system
 * also referenced from https://camel.apache.org/community/articles/
 */
public class EmailProcessor {

    public static final String CONTENT_TYPE = "Content-Type";
    public static final String MULTIPART_MIXED = "multipart/mixed";
    public static final String APPLICATION_X_ZIP_COMPRESSED = "application/x-zip-compressed";
    public static final String MESSAGE_RFC_822 = "message/rfc822";

    private final Session session = Session.getInstance(System.getProperties(), null);
    private final AtomicLong fileNameIncremental = new AtomicLong();

    public static void main(String[] args) throws Exception{
        final CLIParameters parameters = new CLIParameters();
        JCommander jCommander = JCommander.newBuilder().addObject(parameters).build();
        jCommander.parse(args);

        EmailProcessor emailProcessor = new EmailProcessor();
        emailProcessor.process(parameters);
    }

    void process(CLIParameters parameters) throws IOException, MessagingException {
        Objects.requireNonNull(parameters.getType(), "Expected source file type parameter");
        File sourceFile = FileUtils.getSourceFile(parameters);
        File outputDirectory = FileUtils.getOutputDirectory(parameters);
        switch (parameters.getType()){
            case ZIP:
                processZipArchive(sourceFile, outputDirectory);
                break;
            case EML:
                processMimeMessage(sourceFile, outputDirectory);
                break;
            default:
                throw new UnsupportedOperationException();
        }
    }

    void processZipArchive(File zipFile, File outputDirectory) throws IOException, MessagingException {
        if(!isZipStream(zipFile)){
            throw new IllegalArgumentException("ZIP stream magic sequence is not found");
        }
        try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFile))){
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if(zipEntry.isDirectory()){
                    throw new IllegalArgumentException("Only root files in zip archive supported");
                }
                File payload = File.createTempFile("payload", "eml");
                try (FileOutputStream payloadStream = new FileOutputStream(payload)){
                    IOUtils.copy(zipInputStream, payloadStream);
                    processMimeMessage(payload, outputDirectory);
                } finally {
                    if(payload.exists() && !payload.delete()){
                        throw new RuntimeException("It is not possible to delete temporary entry copy from zip");
                    }
                }
                zipInputStream.closeEntry();
            }
        }
    }

    void processMimeMessage(File payload, File outputDirectory) throws IOException, MessagingException {
        if(isZipStream(payload)){
            throw new IllegalArgumentException("Expected text content but found ZIP stream magic sequence");
        }
        try (FileInputStream mimeStream = new FileInputStream(payload)){
            MimeMessage message = new MimeMessage(session, mimeStream);
            if(message.isMimeType(MULTIPART_MIXED)) {
                MimeMultipart content = (MimeMultipart) message.getContent();
                int contentCount = content.getCount();
                for(int contentIndex = 0; contentIndex < contentCount; contentIndex++){
                    BodyPart bodyPart = content.getBodyPart(contentIndex);
                    if(bodyPart.getSize()>0){
                        String[] contentType = bodyPart.getHeader(CONTENT_TYPE);
                        if(contentType.length>0 && contentType[0].contains(APPLICATION_X_ZIP_COMPRESSED)){
                            File zipPayload = File.createTempFile("payload", "zip");
                            try (InputStream attachmentInStream = bodyPart.getInputStream();
                                 FileOutputStream zipOutStream = new FileOutputStream(zipPayload)){
                                IOUtils.copy(attachmentInStream, zipOutStream);
                                processZipArchive(zipPayload, outputDirectory);
                            } finally {
                                if(zipPayload.exists() && !zipPayload.delete()){
                                    throw new RuntimeException("It is not possible to delete temporary zip file");
                                }
                            }
                        } else if(contentType.length>0 && contentType[0].contains(MESSAGE_RFC_822)){
                            String[] contentTypeParts = contentType[0].split("\\n");
                            String resultFileName = FileUtils.getResultFileName(contentTypeParts, fileNameIncremental);
                            File outputFile = new File(outputDirectory, resultFileName);
                            if(outputFile.exists()){
                                do{
                                    outputFile = new File(outputDirectory, FileUtils.getSyntheticIncrementalName(fileNameIncremental.getAndIncrement()));
                                } while (outputFile.exists());
                                //throw new IllegalArgumentException("File already exists "+outputFile.getAbsolutePath());
                            }
                            MimeMessage mimeMessage = (MimeMessage) bodyPart.getContent();
                            try (FileOutputStream emlOutputStream = new FileOutputStream(outputFile)){
                                mimeMessage.writeTo(emlOutputStream);
                            }
                        }
                    }
                }
            }
        }
    }

    boolean isZipStream(File payload) throws IOException {
        try (FileInputStream fileInputStream = new FileInputStream(payload)){
            byte[] magicBytes = IOUtils.toByteArray(fileInputStream, 4);
            return Arrays.equals(magicBytes, new byte[]{80, 75, 3, 4});
        }
    }
}

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

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

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

EmailProcessorTest.java
package com.github.isuhorukov.email;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.util.Arrays;

import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class EmailProcessorTest {

    @Test
    void testMimeEmail1(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        emailProcessor.processMimeMessage(new File(requireNonNull(EmailProcessor.class.
                getResource("/input/Email1.eml")).getFile()), tempDir);
        File[] files = tempDir.listFiles();
        assertThat(files.length).isEqualTo(1);
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
    }

    @Test
    void testMimeEmail2(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        emailProcessor.processMimeMessage(new File(requireNonNull(EmailProcessor.class.
                getResource("/input/Email2.eml")).getFile()), tempDir);
        File[] files = tempDir.listFiles();
        Arrays.sort(files);
        assertThat(files.length).isEqualTo(2);
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test1.eml")).getFile()));
        assertThat(files[1]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test3.eml")).getFile()));
    }

    @Test
    void testNameCollisionSaveAll(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        emailProcessor.processMimeMessage(new File(requireNonNull(EmailProcessor.class.
                getResource("/input/EmailDuplicate.eml")).getFile()), tempDir);
        File[] files = tempDir.listFiles();
        Arrays.sort(files);
        assertThat(files.length).isEqualTo(3);
        assertThat(files[0].getName()).isEqualTo("Test 2.eml");
        assertThat(files[1].getName()).isEqualTo("filename_collision_0.eml");
        assertThat(files[2].getName()).isEqualTo("filename_collision_1.eml");
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
        assertThat(files[1]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
    }

    @Test
    void testZipFile(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        emailProcessor.processZipArchive(new File(requireNonNull(EmailProcessor.class.
                getResource("/input/archive.zip")).getFile()), tempDir);
        File[] files = tempDir.listFiles();
        Arrays.sort(files);
        assertThat(files.length).isEqualTo(3);
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test1.eml")).getFile()));
        assertThat(files[1]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
        assertThat(files[2]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test3.eml")).getFile()));
    }

    @Test
    void testProcessor(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        CLIParameters parameters = new CLIParameters();
        parameters.setSourcePath(requireNonNull(EmailProcessor.class.
                                    getResource("/input/archive.zip")).getFile());
        parameters.setOutputDir(tempDir.getAbsolutePath());
        parameters.setType(FileType.ZIP);

        emailProcessor.process(parameters);

        File[] files = tempDir.listFiles();
        Arrays.sort(files);
        assertThat(files.length).isEqualTo(3);
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test1.eml")).getFile()));
        assertThat(files[1]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
        assertThat(files[2]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test3.eml")).getFile()));
    }

    @Test
    void testProcessorNonValidTypeEml(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        CLIParameters parameters = new CLIParameters();
        parameters.setSourcePath(requireNonNull(EmailProcessor.class.
                                    getResource("/input/archive.zip")).getFile());
        parameters.setOutputDir(tempDir.getAbsolutePath());
        parameters.setType(FileType.EML);

        assertThrows(IllegalArgumentException.class, ()->emailProcessor.process(parameters));

    }

    @Test
    void testProcessorNonValidTypeZip(@TempDir File tempDir) throws Exception {
        EmailProcessor emailProcessor = new EmailProcessor();
        CLIParameters parameters = new CLIParameters();
        parameters.setSourcePath(requireNonNull(EmailProcessor.class.
                                    getResource("/input/Email1.eml")).getFile());
        parameters.setOutputDir(tempDir.getAbsolutePath());
        parameters.setType(FileType.ZIP);

        assertThrows(IllegalArgumentException.class, ()->emailProcessor.process(parameters));
    }

    @Test
    void testProcessorCliRun(@TempDir File tempDir) throws Exception {
        EmailProcessor.main(new String[]{"--source",requireNonNull(EmailProcessor.class.
                getResource("/input/archive.zip")).getFile(), "--output",tempDir.getAbsolutePath(), "--type", FileType.ZIP.toString()});

        File[] files = tempDir.listFiles();
        Arrays.sort(files);
        assertThat(files.length).isEqualTo(3);
        assertThat(files[0]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test1.eml")).getFile()));
        assertThat(files[1]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test2.eml")).getFile()));
        assertThat(files[2]).hasSameTextualContentAs(new File(requireNonNull(EmailProcessorTest.class.
                getResource("/output/test3.eml")).getFile()));
    }
}

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

Could you please make call with me to discuss what do you means as "Storing format is a sequence of operations". I asked about this points from first questions for this test task. Now for me it looks like not well defined requirements for 4-6h test exercise.

As I am invested my unpayable time for software development I expect detailed review why this solutions is not fit and what are you expect as a result

   Regards,

         Igor

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

Результат

Вчера мы созвонились и то что выяснил в диалоге, с моей точки зрения сильно выходит за 4-6 часов на задачу, с учетом покрытия тестами запрашиваемой реализации и ее сложности. Я вообще считаю что фактор стресса из-за ограниченности по времени решения, непонятности деталей задачи могут понизить производительность, как и ежедневный отдых и дайвинг с 19 сентября у океана. Эта ситуация отдаленно мне напомнила кадры из фильма Password Swordfish когда Джон Траволта тестирует профпригодность и стрессоустойчивость Хью Майкла Джекмана. Но что точно могу сказать что хорошо что когда-то давно я уже сталкивался с MIME форматом и мне не пришлось погружаться в его детали впервые. Так что IMHO в оценках времени на задачу компания слукавила.

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

Кому интересны детали для понимания уточнений по заданию. Вдруг будет полезно

9 ноября 2022, 2:34

Hello Igor,

Thanks again you for your efforts to complete the test task.

Several team members on our end have reviewed it and compared your solution to the other submissions we received, so we are coming back to you with the decision. Unfortunately, we have decided to move forward with another candidate at this time.

You have delivered an appropriate solution to our test task, but there is one essential drawback from our point of view - task solves slightly a different problem than was asked - it recursively extracts files based on the file type instead of extracting files based on the storing format. Storing format is a sequence of operations so it cannot be represented by just two options.

We enjoyed collaboration with you through the process and would be happy to keep in touch for the future opportunities.

Thanks again, have a nice day!

3 ноября 2022, 12:42

Hi Alexander,

Thank you for details. Please find updated code in attachment as I am understood tool behavior from your email.

Regards,
Igor

3 ноября 2022, 16:39

Hi Igor,

lets consider I've a message "Fwd Test 2.eml" and I zipped it (both attached).
I'd like to receive Fwd Test 2.eml with attachment in one run and Test 2.eml
in another run by passing the same ZIP archive and different formats.

As it's written in task you must not guess input file format and format is a sequence of operations but not file type.

Thanks,
Alexander

3 ноября 2022, 00:19

Hi Alexander,

Sorry, still don't understand your point. Could you please provide examples/test data for this cases or provide format parameter examples for CLI. Is it something like script with ordinal number of MIME section & corresponding action or something like xPath expression to select nested nodes?

I'll be verify appreciated for more input data and expected results for it. Need more clarification before I'll start

Regards, Igor

3 ноября 2022, 05:19
Hi Igor,

I've started looking into the code and found out it's not possible to provide storing format of the input file but just type of the file.
Format is a sequence of operations but not file type. Currently it's not possible to distinguish ordinal email with rfc822 attachment
and email whose attachment should be unpacked.

Will you be able to fix the solution?

Thanks,
Alexander

2 ноября 2022, 09:39

Hello Igor,

thanks for submitting, will get back to you in couple of days

Thanks,
Alexander

2 ноября 2022, 00:08

Good morning Alexander,

Now I implement sequential file naming and add unit test for it.

Regards,
Igor

1 ноября 2022, 21:08
Hi Igor,

any file name collision resolution is accepted, the only requirement do not lose files.

Thanks,
Alexander

1 ноября 2022, 12:29

Ok, got it! Thanks.
How are you expect result message file naming:
synthetic file name from increasing counter or file name from Content-type. In case of second options how to handle possible file naming collision?

Regards,
Igor

1 ноября 2022, 19:07
Hi Igor,

the idea that format could be arbitrary. Not just attachments in mails in ZIP archive but
could be as simple as single email. You don't need to make any conversion in this case.
So one of the task for you to design format's specification, it could be passed through
command line or any other convenient way.

Thanks,
Alexander

1 ноября 2022, 10:38

Hi Alexander,

What do you means:
You must not guess input file format and the program should allow the user to specify input
format in some way, as a command line argument for example

Could you please provide examples of command line for this program?

Is the final goal to extract all nested messages from each ZIP attachment recursively?

Regards,
Igor

Хоть я и не прошел тестовое задание в эту компанию и инвестировал суммарно день своей жизни на все процессы интервью, я рад что все так как произошло. Конечно, успешное выполнение задания больше подняло мою самооценку чем итоговый отказ, но точно создало бы дилемму. Были у меня сомнения что бизнес компании не очень этичный с моей точки зрения и что я торгуюсь со своей совестью и переступаю через себя в доказательствах что я опытный специалист с подтверждаемым и доступным для ознакомления опытом в open source проектах. Но если же кто нибудь пойдет этому же пути, у вас будет больше информации для прохождения процесса интервью и принятия окончательного решения.

Поиск работы последние полтора месяца для меня показал что:

  • Похоже hh.ru уже в запустении по вакансиям и компаниям, кто готов оплачивать поиск на этом ресурсе.

  • Мой LinkedIn профиль с февраля этого года в затишье. Раньше он был постоянным фоновым источником вакансий и информации о состоянии рынка разработки ПО.

  • По позициям синьорных разработчиков и тимлидов теперь отсев по leetcode, hackerrank и много где решение алгоритмических задач.

Пишите в комментариях ваши предположения о том что в моем варианте выполнения задания нужно было сделать иначе и чего там не хватает. Интересно как другие разработчики интерпретируют то же описание и достаточно ли в нем информации для решения. Ответы Александра и дополнительные примеры в почте не прояснили для меня а что же такое "sequence of operations is a storing format" Вы так же можете сделать PR на github решения тестового задания чтобы исправить его так, как ожидалось. Этим вы можете лучше любых слов помочь кому-либо пройти это же задание в будущем или же лучше подготовиться к интервью!

Upd: 17.11.22 22:26

Сегодня на закате пошел ливень и у меня появилось время чтобы завершить это тестовое задание. Тогда по общению с Александром голосом понял, что нужна какая-то конфигурация через которую бы указывалось программе какие именно вложенные письма сохранить. Я предложил аналогию xPath выражений, что так же должно работать. Теперь при запуске с параметром --opsequence unzip/0/1/unzip/0/1,unzip/1/1/unzip/0/1,unzip/1/1/unzip/1/1 программа позволяет извлечь и сохранить три письма по указанным путям(попутно распаковывая вложения как и корневой архив), так же как и в случае если что-то из конфигурации не нашлось - бросить ошибку и указать какие пути не обнаружены.

Обновленный код и тесты в том же репозитарии. На это я потратил еще 4.5 часа. Итого 9 часов на весь кодинг. В репозитарии еще есть что шлифовать с точки зрения тестов(95% методов, 87% строчек уже покрыты тестами) и качества кода. Это все не укладывается в заявленные 4-6 часа неоплачиваемого тестового задания по сложности реализации. Надеюсь, что кому-нибудь это все же пригодиться в прохождении...

Комментарии (62)


  1. excoder
    16.11.2022 22:11

    А всё же был Александр, или Alexander, Alex?


    1. igor_suhorukov Автор
      17.11.2022 12:08

      Александр. Техническое интервью было на русском, HR и все остальное на английском


  1. s_f1
    16.11.2022 22:39
    +1

    Не спец по Джава, ногдепробелы? Так и должно быть?


  1. MaryRabinovich
    16.11.2022 22:51
    -6

    Вопрос, а можно ли вот так выкладывать тексты тестовых. Я обычно спрашиваю "можно ли ваше тестовое выложить". И да, бывает, отказывают. Хотя юридической стороны дела не знаю.

    У вас сразу две картинки с тестом про картриджи, и текст про zip-архив, да ещё с решением.


    1. MaryRabinovich
      17.11.2022 10:35

      Замечу для минусующих, что речь о компании, за внятное упоминание себя способной при случае начать преследование. Об этом в статье написано.

      Говоря шире, просто западная компания, которой есть дело до репутации.

      Вопрос, почему вы (как минимум, 8 людей, уже поставивших минусы под моим каментом) уверены, что раскрытие их интеллектуальной собственности (а тесты для новичков составили сотрудники этой компании в своё рабочее, т.е., платное время) - это ок?


      1. domix32
        17.11.2022 13:39
        +6

        Есть подписанный NDA - вопросов нет. В противном случае вы им особо ничем не обязаны.


  1. eltardowut
    16.11.2022 23:58
    +8

    Так а что они хотели в итоге?


    1. igor_suhorukov Автор
      17.11.2022 12:09
      -1

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


    1. igor_suhorukov Автор
      17.11.2022 22:31

      Добавил в самом конце публикации


  1. sunnybear
    16.11.2022 23:59
    +4

    Почтовый клиент хотели? На практике, наличие результата тестового задания - это лишь врашумительный повод отказать непонравившемуся кандидату


    1. igor_suhorukov Автор
      17.11.2022 12:10

      Скорее задача подразумевает некий анализатор email.


  1. dyadyaSerezha
    17.11.2022 00:05
    +11

    1. Пришлось раза 3 перечитать задание и описание решения, чтобы понять, что же надо сделать. Не показан пример распаковки. Может, требовалось создавать директории для каждого уровня вложенности?

    2. Английский язык у составителя задания конкретно хромает. У автора статьи он хромает совсем сильно.

    3. Из статьи неясно, что же именно не понравилось Александру.

    4. Живя за рубежом, ежедневно получаю кучу имейлов с вакансиями с сайтов по работам. Некоторые пишут лично (насчёт ситуации в РФ не в курсе).


    1. kenoma
      17.11.2022 00:16
      +3

      Ну рад за вас, но у меня ситуация аналогичная описанной автором.


    1. p07a1330
      17.11.2022 00:17
      +6

      1. У автора статьи он хромает совсем сильно.

      Однако понять мысль и того, и другого труда не составило. Огрехи есть, но с учетом того, что язык не родной, я автом не метит в копирайтеры - не могу сказать, что полагаю это критичный. Путсть и неприятно


      1. dyadyaSerezha
        17.11.2022 06:27
        -1

        Зависит от читающего. Если не нейтив спикер, то пойдёт. А если нейтив, то может и отфутболить.

        Насчёт понять, еще раз мне пришлось перечитать задание 3 раза, чтобы понять.


    1. hullaballoo
      17.11.2022 07:13
      +1

      Касательно #4

      Я смежник (ИБ с уклоном в бумажную её часть). Вакансии на линкедине действительно стали приходить заметно реже, но стоило открыть резюме на hh и обозначить как «рассматриваю входящие предложения» и за неделю пассивного висения там с тремя ручными апами пришло четверо работодателей (ритейл, банк, производство, производство), ещё один позвонил лично.

      Последний из производственников пришёл через линкедин (что странно - вакансия эта висит на hh и зачем они пошли длинной дорогой мне не ясно).

      Из радостного, процесс сейчас: 5 минут с HR, дальше руководитель, руководитель руководителя, оффер. Тот же найм год, три и 6 лет назад состоял и семи этапов и растягивался на месяцы.


      1. dyadyaSerezha
        17.11.2022 07:50
        +1

        Из радостного, процесс сейчас: 5 минут с HR, дальше руководитель, руководитель руководителя, оффер. Тот же найм год, три и 6 лет назад состоял и семи этапов и растягивался на месяцы.

        Это в РФ? Ну хоть что-то приятное за последнее время.


        1. hullaballoo
          17.11.2022 08:26
          +1

          Да, Москва.


      1. Didimus
        17.11.2022 22:07

        Хх, наверное, денег много хочет за контакт, вот и оптимизировали через л'д'ин


    1. XeL077
      18.11.2022 15:10

      У меня ни одного предложения в LinkedIn с 24 февраля, на hh вяло, раз в три-четыре меяца набегает 3-4 входящих сообщения и затухает.


      1. Tresimeno
        18.11.2022 15:46

        А до 24.02 были прям офферы или просто скриптовые первоны приглашали на контакт ?


        1. XeL077
          18.11.2022 16:04

          Были скриптовые, были просто добавления или предложения, были оферы


    1. ivymike
      19.11.2022 02:08

      Так его же не берут писать очерки в newyorktimes в стихотворной форме, а написать public static void main и с таким уровнем можно


  1. Cheater
    17.11.2022 02:41
    +7

    Тоже сел решать задачу (на C, за незнанием Java), но у меня почему-то другая формула в решении:

    return cartridges - ceil(double(cartridges * perksCost - dollars) / (recycleReward + perksCost));
    

    По теме тестового про разбор мейла, "сказав А, говори Б", раз вы уж высказались против бесплатного тестового, то и слали бы их подальше с дальнейшим разговором на эту тему. Очень уж специфичное задание, в других условиях я бы сказал, что вы для них похоже что делали реальную таску под видом тестового.


    1. code_panik
      17.11.2022 21:52
      +2

      но у меня почему-то другая формула в решении

      У меня получилась такая же. Если по заданию для каждого перка надо по картриджу, то число перков ограничено сверху числом картриджей. У автора в решении в числителе доллары со знаком +, и ответ потенциально не ограничен.


    1. Rsa97
      19.11.2022 18:05
      +1

      Формально, выражения эквивалентны:

      cartridges - (cartridges * perksCost - dollars) / (recycleReward + perksCost) = 
      = (cartridges * (recycleReward + perksCost) - cartridges * perksCost + dollars) / (recycleReward + perksCost) = 
      = (cartridges * recycleReward + cartridges * perksCost - cartridges * perksCost + dollars) / (recycleReward + perksCost) = 
      = (cartridges * recycleReward + dollars) / (recycleReward + perksCost)


  1. Gabiani
    17.11.2022 03:55
    +1

    Джекмен - он Хью.


  1. lil_Toady
    17.11.2022 04:27
    +23

    Я не программирую на Java, но если отойти от условий задачи, мне ваш код кажется не очень удачным даже по структуре и компановке. Тем не менее, давайте пройдемся по условиям задачи, как я их понял, и почему я считаю что вы им неудовлетворили.

    1.

    You need to write a CLI program that extracts files from the provided file based on the provided format. See sample output for the sample above. You must not guess input file format and the program should allow the user to specify input format in some way, as a command line argument for example.

    На вход подается eml или zip файл, требуется распаковать вложенные в него файлы. Мне недоступен упомянутый пример, поэтому не знаю хотят ли они сразу распаковать все файлы рекурсивно, или только те что непосредственно вложены в указанный файл. Но не имея вводных, придерживаюсь правила: если что-то не обговорено в условиях задачи, то оно реализуется на усмотрение разработчика. Чтобы снизить уровень неопределенности тут, я бы ввел параметр -R,--recursive. Но вне зависимости от этого,
    мы имеем дело, по сути, с древом архивов. Мне кажется логичным распаковать его в древо папок, чтобы как минимум можно было собрать все обратно без потерь, но это так же не обговорено, поэтому пусть еще будет параметр --flat, при указании которого все распаковывается в одну папку (теоретически они могли и собирать все из одной папки).

    Вы решили всегда все распаковывать в одну папку, при этом:

    • Вы распаковываете только eml файлы вложенные в eml файлы;

    • Файлы вложенные в zip вы всегда пишете во временный payload.eml. Zip файлы вложенные в eml вы всегда пишете во временный payload.zip, при чем учитывая что вы идете рекурсивно сразу на максимальную глубину вложенности, вы рано или поздно начнете перезаписывать временный файл, для которого уже открыт FileInputStream выше по рекурсии, и вы не закончили - фатальная логическая ошибка.

    • Если eml вложенный в eml не имеет имени, то будет назван filename_collision_{N}.eml, не смотря на то что коллизии нет.

    • Если eml вложенный в eml имеет имя, но файл с ним уже есть, то тоже filename_collision_{N}.eml - теряем исходное имя.

    2.

    Let’s assume that someone could execute the following operations for arbitrary number of times in a random order:

    - Attach EML or ZIP file to the email

    - Archive list of emails to the root folder of ZIP archive So the sequence of operations is a storing format for the original set of files.

    So the sequence of operations is a storing format for the original set of files.

    Они говорят указали что конечный файл формируется двумя операциями выполненными в произвольной последовательности и произвольном количестве:

    • Добавить .eml или .zip в .eml;

    • Архивировать список .eml в корневую папку .zip;

    соответственно формат файла отражает последовательность действий пользователя, (что не совсем правда) но как минимум это намекает на то что сначала нужно распаковать все файлы из .zip, и уже потом углубляться дальше в eml. Идти по уровням вложенности в принципе эффективнее, чем рекурсия до максимальной вложенности и обратно (у вас и это не работает), потому что так мы потенциально могли бы распараллелить обработку файлов. Если организовать распаковку файлов как список задач, расширяемый на каждом последующем уровне вложенности (если --recursive), то в минимальной реализации мы можем их обрабатывать последовательно, но у нас уже есть задел как для последующего распараллеливания, так и для возможности диалога с пользователем для каждого из файлов, например если надо перезаписать.

    3.

    Solution should have quite good quality, ... be able to work with real-life emails (as this one) and quite large ZIP archives.

    Программа должна быть качественной и готовой к использованию (large files - это всегда про потоковую обработку, тут у вас проблемы нет). В моем понимании это значит что обработаны основные логические ошибки, но ваша кидает исключения на каждый чих. При чем, половина вашего кода - это попытка избежать логических исключений типа FileNotFoundException кидая вместо них критические, неловимые. Чаще всего IllegalArgumentException, который по вашему коду может означать и что на вход некорректный файл подали, и что на каком-то уровне вложенности файл некорректный. К примеру, вы проверяете является ли файл zip архивом или нет, и потом (в зависимости от функции) кидаете InvalidArgumentException - зачем? Если формат неверный, вызовы конструкторов FileInputStream, ZipInputStream, и MimeMessage выкинули бы как минимум более разборчивые исключения, которые можно было обработать выше. А в идеале обработать и их внутри метода, обернув в ваши логические исключения, по которым вы будете строить обработку ошибок выше.
    Ощущение что вы воспринимаете нотацию исключений в Java скорее как раздражитель, и боретесь с ним.

    4.

    it should be covered by tests

    От вас просили покрытый тестами код, но тесты ваши я даже смотреть не стал, так как сам код изначально непригоден для юнит тестов. У вас практически каждый метод работает с файлами, а единственная выведенная в программе абстрактция, - CLIParameters, почему-то прокинута везде где только можно. Даже если отбросить то что методы FileUtils.getOutputDirectory и FileUtils.getSourceFile вовсе не нужны, зачем требовать всю сущность CLIParameters на вход, вы же работаете с единственным параметром, его и требуйте - вам же еще тесты писать, если успеете.


    1. SimSonic
      17.11.2022 04:47

      Абстракций, имхо, действительно не хватает, а в методе processMimeMessage слишком много уровней вложенности, дядюшка Боб вряд ли был бы доволен. Мне кажется, код можно было сперва написать и так, но запастись минутами 15-30 и перед отправкой порефакторить.


    1. sshikov
      17.11.2022 22:37
      +1

      >сначала нужно распаковать все файлы из .zip, и уже потом углубляться дальше в eml.
      Склонен согласиться со многими вашими выводами, код не идеален — но вот эти выводы не очевидны. И да, код плохо тестируется. Но я три раза писал на практике ровно такой код, и сказал бы, что эта задача не на 4.5 часа, а на 4.5 дня, если вас особо никто не гонит. Это тестовое задание, в нормальной работе после такого проводим ревью, и уже там кандидат вполне может сам рассказать, что ему в коде не нравится, и что он будет улучшать. И вот это вот ревью мне, если я нанимаю, даже интереснее кода, написанного в стрессовой ситуации. А его не было. Так что я бы оценил результат как положительный, и не знаю, чего работодатель тут выпендривается.


  1. i86com
    17.11.2022 06:45
    +11

    По-моему, тут сама методика тестовых заданий применена при найме неверно.

    Конечно, из статьи и в самом деле не понято, что именно их не устроило в тестовом задании, явно не процитированы несколько сообщений из переписки, но это ещё понятно.

    Интересно другое — почему выполенное «не так, как ожидалось» задание считается достаточной причиной для мгновенного отказа и прекращения разговора?

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

    То есть вполне нормально, когда разработчику пишут примерное ТЗ (полстраницы, а не три тома выдуманной документации), разработчик выполняет примерное решение, а дальше уже по сделанному обоим будет легко и просто обсудить, что нужно, чтобы доделать работу.

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

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


    1. igor_suhorukov Автор
      17.11.2022 12:18

      И я как интервьювер с отпытом на это реагировал как "кандидат отреагирует на запросы о правках" и что упражнение про работу стребованиями "читать между строк и сам додумывать недосказанное".

      Но такие вещи я обычно устно проговаривал с кандидатами на модельной задаче в вакууме и слушал какие вопросы он задает, как рассуждает. Тут не бывает идеальных случаев, смотришь как рассуждает: garbage in -> garbage out или уточнения.

      У нас этот диалог был осложнен тем, что это была переписка в почте а не чате и не личное общение. И разница в часовых поясах в 10 часов, он в GMT-5 я в GMT+5. К тому же он отвечал с приличной задержкой - работал видимо в это время.


    1. igor_suhorukov Автор
      17.11.2022 12:46
      +1

      Кстати, про что и речь, что в Apache Arrow код ревью серьезное и иногда изначальный пул реквест в итоге может измениться до неузнаваемости из за решения более общей задачи или не так как планировал сначала. По мне так мои PR в Spring framework/Boot, SchemaSpy, H2, Apache Arrow и т.п. хорошо это показывают. Навскидку как пример или этот


  1. lamerok
    17.11.2022 07:38
    -3

    Мне кажется (обход всех элементов разных, но четко определенных типов) можно сделать с помощью шаблона Visitor, тогда код убудет намного лаконичнее. Такой код, на мой взгляд был бы неподдерживаемым. Как то нужно было сделать все локаничнее, ввести абстракции, разделить отвественности на интерфейсы. Но решение для такого задания, даже если оно специфическое и они его куда-то там хотят себе прикрутить, я бы никуда не прикручивал.


  1. codecity
    17.11.2022 09:35
    +4

    По-моему с тестовыми заданиями все просто - выполнять за деньги. В чем проблема тогда? Выполнили - получили приятный бонус. И работодатель не будет относиться халатно к этому и жлобов отсеете сразу. Если просто отказываетесь - то почему? Боитесь прослыть мелочным? Но день потратить - это не мелочь, лучше провести с семьей или заняться любимым делом.

    Притом серьезнее отнесется к оценке. Можно договориться сразу - если решение не устроит - то 50% от стоимости + обоснование.

    Вам предлагают тестовое - вы ОК, но это платно. Вы не хотите платить? Почему? Я ценю свой труд.


    1. svartberg
      17.11.2022 13:47
      +1

      Имхо для европейского рынка: в данный момент не такое время, когда можно просить деньги за решение тестовых. Просто возьмут другого хорошего кандидата. Их на рынке достаточно много. Месяца 2 назад у нас был поиск staff'a и за месяц было около 80 резюме. Это больше чем достаточно. И это всё люди с очень большим опытом и очень хорошими резюме. (у нас конечно нет тестовых, но в текущих условиях ни кто бы не стал у нас платить за их выполнение, если бы были)


      1. codecity
        17.11.2022 15:05

        Месяца 2 назад у нас был поиск staff'a и за месяц было около 80 резюме.

        А качество кандидатов и реальная способность выполнять работу, а не скиллы по прохождению собеседования?

        Сейчас вот какое время - модные курсы наплодили тьму желающих легких денег и прокачанных в плане прохождения собеседования. КПД у них отрицательный, т.е. работу делать не смогут - только будете их обучать.

        Цените себя. На самом деле хорошего спеца по прежнему найти не так просто.

        Ситуация примерно как с юристами в начале 00-х. Мамы поняли что это престижно и дорого, начали всеми правдами-неправдами отдавать своих чад. Наплодили кучу юристов, однако же спецы цениться не перестали, просто более обдуманно начали подходить к системе оценки квалификации - просто диплом не показатель.


  1. oleg_shamshura
    17.11.2022 11:13
    +1

    Мне в одной сильно международной конторе предложили пройти предварительный IQ-тест.

    На английском языке. Две попытки и какие-то считанные минуты.

    Там, где выпадали всякие дебильные картинки, дело двигалось бодро, но когда повалили задания в духе "подставь правильное слово в цитату Джона Голсуорси", я начал лихорадочно хвататься за переводчик на смартфоне, чтобы распознавать значения совершенно замороченных слов.

    После двух отчаянных попыток система выдала вердикт:

    "IQ=50. Для должности программиста C++ этого недостаточно.
    Больше не подавайте заявку на эту вакансию, она не будет рассмотрена.
    Но вы можете попробовать подать на другую, у нас их большой выбор."

    С тех пор гадаю, программисту на каком языке достаточно IQ=50...


    1. domix32
      17.11.2022 13:43
      +4

      Какой-то странный у них IQ тест с цитатами


      1. oleg_shamshura
        17.11.2022 15:45

        Я утрировал. Цитат, конечно, там не было, -- были задания со словами и фразами, требовалось быстро сообразить, какое слово лишнее в данном контексте, какое подходящее и пр. Проблема в том, что слова -- далеко не из "базового словаря". Рискну предположить, что и для "нейтива" эти задачки нетривиальны, это, как ни крути, все же тест на умственные способности.


        1. domix32
          17.11.2022 22:10
          +1

          Менее странным его это не делает. Обычно задачи на неполную информацию состоят или из фигур с несколькими характеристиками, либо из чисел. То бишь чтобы было абстрактно и универсально. Лишние слова иногда бывают в психологических тестах дабы проверить какую-нибудь диссоциацию или деменцию/шизофрению, но врядли работодатель занимается таким.


    1. rdp
      17.11.2022 15:26

      Результат IQ-теста на неродном языке будет заведомо хуже. Разве что из любопытства делать.


      1. oleg_shamshura
        17.11.2022 15:54

        Увы, жизнь заставила. Когда внезапно вытурили с работы, в связи с расформированием команды, отобрав резидентство, которое отменяется вместе с контрактом, и вместо него в загранпаспорт шлепнули "выездной штамп" на 1 месяц, а жилье проплачено на год вперед (с чувствительным депозитом), ребенок учится в местной школе -- и тоже оплачено авансом, кругом ковидные [лок]дауны, самолеты не летают, то любопытство разгорается с адской силой.


        1. Tresimeno
          17.11.2022 17:09

          Это в какой стране произошло?


          1. oleg_shamshura
            17.11.2022 17:58

            Вьетнам. Меня за три года уже четвертый раз так "сокращают" -- чтобы с приключениями нанять обратно. Сейчас, правда, чуть поумнели -- сразу рассылают резюме по другим подразделениям, а раньше -- пнем под зад и без рассуждений.


    1. Lamaster
      17.11.2022 20:24

      Тест от платформы Indeed.com? Тоже приходил мне. Я даже не уверен, это работодатель его послал или сама платформа решила меня протестировать.

      Задания там типа Найдите повторения и Сколько отдельных ингредиентов будет использовано для списка продуктов, где каждому дан рецепт

      Тоже офигевал от этого. Вот пример вопроса.


      1. oleg_shamshura
        18.11.2022 08:09

        Не запоминал, что это был за сервис, но раскладка страницы похожа.

        Нет, ну удобно же!

        На Хабре всё никак не придумают способ "интервьюировать правильно".
        Скорей перенимайте опыт: отсев лузеров в автоматическом режиме!

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


  1. karakka
    17.11.2022 12:04

    Джекман - Хью, а не Майкл.


  1. superangrypinguinus
    17.11.2022 12:04

    Относительно моего опыта по активности рекрутинга.

    3 года опыта. Добавил недавно теги в резюме на HH (ну, изучил же я что-то за год, надо обновить резюме). Больше ничего не делал. За неделю 4 предложения пройти собес.

    По ощущениям, было +- так же.


  1. anone9466
    17.11.2022 12:05

    Жалко что автор не указал желаемую зп, или хотя бы её уровень- выше рынка, или рыночную. Потому что я бы мог понять такие тестовые при зп выше рынка, когда ищут суперзвезду. И когда соискатель хочет нормально заработать. Но когда надо гонять жсоны на обычном ентерпрайзе, такое вызывает недоумение.

    Или я уже от жизни совсем отстал, и сейчас везде так, на любую позицию, на любой уровень зп?


    1. igor_suhorukov Автор
      17.11.2022 12:21

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


  1. ivanovdev
    17.11.2022 12:42
    +1

    От метода processMimeMessage у меня глаза слезиться начали. Не надо так.


    1. igor_suhorukov Автор
      17.11.2022 12:48

      Не плачьте! Для 4х часового тестового задания можно сделать скидку на декомпозицию кода и размер метода


      1. Fulborg
        17.11.2022 15:37

        извините конечно, но во сколько бы вы оценили «полноценную» реализацию такого рекурсивного распаковщика?


  1. denim
    17.11.2022 16:09

    какое-то нытье сплошное, я такой зайка а они не оценили. Вы решаете куда пойти работать, компания решает как организовать интервью процесс, силой никто не заставляет. Как хайринг менеджер добавлю из собственного опыта - в одной локации давали литкод, в другой тэйк хоум. Перформанс и качество кода у ребят кто прошел через литкод в разы выше, выборка порядка 100 человек, есть с чем сравнивать


    1. valery1707
      17.11.2022 17:15
      +2

      Задачки на литкоде и аналогах заточены в том числе и на анализ производительности - так что может этому научить (скорее "заставить").
      А вот "качество" кода там никак не отслеживается и научиться хорошему через них не выйдет.
      Скорее всего дело не в том что "разработчик после литкода становится лучше", а в том что "литкодом готовы заниматься более хорошие разработчики" - "после не значит в следствии".


      1. denim
        17.11.2022 19:23

        все верно, полностью согласен


    1. tommyangelo27
      17.11.2022 20:21
      +1

      Я тоже склонен поддержать. Проработал 8 лет в компании, где процесс интервью при найме был похож на экзамены. Да, многим кандидатам он не нравился. Да, мне самому он тоже казался не очень удачным, хотя лично принимал участие в его создании и калибровке.
      У нас там были разные условия, непрозрачные для кандидата — определённый список тем, шкала баллов, коэффициэнты разные, обязательность присутствия людей из других офисов (у нас были офисы в 4 локациях).

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

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


  1. anonym0use
    17.11.2022 19:53
    +3

    Прочитав очередной раз убедился что российский рынок вполне себе лайтов и адекватен по сравнению с вот этим вот всем.

    У нас как стандарт при поиске — созвон с hr на 10-15 мин., затем тех интервью на 1-1.5 часа и если не совсем имбецил, то оффер на ±$5к в кармане в зависимости от того как пройдешь и сколько попросишь.

    «мы верим в наши процессы отбора.. .» — видимо кандидатов слишком много, иначе эта необоснованная вера быстро бы закончилась, поток индусов неиссякаем пока.

    Если не секрет сколько по деньгам то можно было ожидать в случае успеха?


  1. Lamaster
    17.11.2022 20:28

    Тоже последнее время искал работу и сейчас витает вопрос в воздухе: Имеется N кандидатов и M вакансий. Это создаёт квадратичную сложность. Как можно её уменьшить?

    Ещё бы предложил, чтобы и кандидат, и ревьюер задавали задачки друг другу, не более, чем на час. Если кандидат решает задачу первым, то можно брать. Но кто на такое согласится...


    1. Lamaster
      17.11.2022 20:34

      Кстати, на том же Linkedin есть беджи по хард-скиллам. Каждый из 15 вопросов. Свои профессиональные я получил, но, вот, например Python после прохождения Яндех.Практикума получить не удалось. Результат 9/10, но там есть определённый процент для прохождения. Думаю этого должно быть достаточно для уверенности интервьюера в заннии языка кандидатом.


      1. sshikov
        17.11.2022 22:29

        Хм. Я недавно решил сделать тест по скале. Вошел в top 15% из тех примерно 95 тыс, кто проходил этот тест. Как по мне, я скалу вообще не знаю. И на месте интервьюера я бы не был в этом уверен. При этом я практически на ней пишу, не испытывая в процессе проблем.