Пять задач, которые приходится решать при трудоустройстве начинающим Java-разработчикам
https://t.me/linuxkalii - kali linux ос для пентестаЧего хочет работодатель
В процессе подбора кандидатов работодатель хочет понять, насколько ему подходит тот или иной соискатель — насколько он комфортен в общении и работе, обладает необходимым опытом и, что самое важное, техническими навыками для предстоящей работы. В этой статье я приведу примеры конкретных задач, которые могут давать на собеседованиях, и разберу, на что смотрит работодатель при их решении.
Примеры задач
Задача 1. Написать код, выполняющий какую-то несложную задачу. Здесь может быть, например, классический FizzBuzz, задача на сжатие или переворачивание строки. Работодателю здесь важно понять, как соискатель владеет основами синтаксиса языка и может ли писать код сразу чисто. Удивительно, но многие кандидаты испытывают значительные сложности при выполнении задач такого рода.
Одна из задач, которую мы даём соискателям: написать код, который выводит числа от 0 до 1000, которые делятся на 3, но не делятся на 5, и сумма цифр в которых меньше десяти. Задача часто вызывает совершенно немыслимые трудности у людей, утверждающих, что их уровень middle или даже senior. Вот несколько примеров решений такой задачи кандидатами на собеседованиях:
//Пример 1 public class TestClass { public static final int MAX_LIMIT = 1000; public static void main(String[] args) { for(int i = 0; i < MAX_LIMIT; i++) { boolean enabled = true; if (i % 3 != 0) { enabled = false; } if (i % 5 == 0) { enabled = false; } if (!testSum(i)) { enabled = false; } if (enabled == true) { System.out.println("Число: " + i); } } } public static boolean testSum(int in) { int res = 0; while (in > 0) { res += in % 10; in = in / 10; } return res < 10; } } //Пример 2 public class Test { public static void main(String[] args) { for (int i = 0; i<1000; i ++) { if ( i%3 == 0 && i%5!= 0) { } } } public int returnNumber( int i) { int t; if (i >0){ returnNumber(i/10); } } } //Пример 3 import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public class TestTask { public static List<Integer> getForNumber() { List<Integer> list = IntStream.range(0, 1000).boxed() .filter(n -> n % 3 == 0 && n % 5 != 0) .collect(Collectors.toList()); return list; } public static int sumOfNubers(List<Integer> list) { for (Integer n : list) { int summ; while(n>1) { summ += n % 10; n /= 10; } } return 0; } }
Напишите нам в комментариях, как вы оцениваете каждое из этих решений и почему. Какое из них считаете лучшим, а какое худшим. Сразу отмечу, что решение, которое мы в SymbioWay считаем идеальным, здесь не приводим. Можете также попробовать написать его в комментариях.
С помощью задач такого типа мы проверяем уровень соискателя: как много он писал код сам, а также косвенно — сталкивался ли с «грязным» кодом и рефакторил ли его. По такому заданию можно косвенно увидеть, как быстро и «чисто» (понятно и поддерживаемо) специалист будет писать собственный код.
Задача 2. Создать веб-приложение на фреймворке Spring, которое будет соответствовать определённой спецификации. Спецификация может быть дана в текстовом виде или в виде отдельного Swagger-файла. Например, реализовать backend для анонимного онлайн-чата со следующей спецификацией:
- GET /init — запрос инициализации, который по ID сессии отвечает, авторизован ли текущий пользователь или нет.
- Запрос без параметров
- Формат ответа:
{ "result": true }
- POST /auth — запрос, регистрирующий и авторизующий пользователя. Он добавляет пользователя в базу данных и привязывает к текущей сессии.
- Формат запроса:
- name — имя пользователя
- sex — пол пользователя, M или F
- Формат ответа:
{ "result": true }
- GET /users — запрос, возвращающий список пользователей в чате в порядке от самого свежего, который зарегистрировался недавно, до самого старого.
- Запрос без параметров
- Формат ответа:
{ "result": true, "data": [ { "id": 567, "name": "Alex Kurnikov", "male": "M" }, ... ] }
- GET /messages — запрос, возвращающий ленту сообщений чата от самого нового до самого старого с постраничной навигацией.
- Формат запроса:
- offset — сдвиг от самого последнего до самого раннего, от 0, по умолчанию равен 0
- limit — количество сообщений, которые нужно вывести, по умолчанию — 100
- Формат ответа:
{ "result": true, "count": 100, "data": [ { "id": 46273, "time": "18:30 30.01.2023", "authorId": 567, "message": "Some HTML text, may me <b>tagged</b>" }, ... ] }
- POST /messages — запрос, создающий новое сообщение от имени текущего пользователя. Форматы запроса и ответа спроектируйте самостоятельно на ваше усмотрение на основе имеющейся документации.
С помощью таких задач мы и работодатели проверяют сразу несколько навыков:
- умение правильно проектировать и создавать веб-приложения на фреймворке Spring в соответствии с принятой структурой;
- понимание принципов клиент-серверного взаимодействия (знание HTTP и стандарта REST);
- умение работать с ORM-системой (обычно Hibernate) и базой данной, умение проектировать структуру этой базы;
- умение писать код на Java и владение базовыми навыками при работе с этим языком программирования, в частности, знание ООП, умение работать со строками и коллекциями, лямбда-выражениями и Stream API, привычку их применять при необходимости.
Задача 3. Написать SQL-запрос. Например, задача может быть такой. У вас есть две таблицы:
employee — сотрудники компании
- id
- department_id
- work_start_date
- name
- salary
department — отделы, в которых работают сотрудники
- id
- name
- lead_id — ID руководителя отдела
Нужно написать такой SQL-запрос, который выведет всех сотрудников, работающих в компании с лета 2021 года, не привязанных к отделам и получающих зарплату меньше 100 000 рублей.
Верным ответом на такую задачу будет запрос:
SELECT e.id, e.name FROM employee e LEFT JOIN department d ON d.id = e.department_id WHERE e.work_start_date >= '2021-06-01' AND e.salary < 100000 AND d.id IS NULL
С помощью задач такого плана можно понять, насколько кандидат владеет языком запросов SQL, если это важно в данном проекте.
Вместо задач на написание SQL-запросов, могут предложить написать код с использованием Hibernate. Конечно, владение SQL — фундаментальный навык, который никогда не будет лишним. Но в некоторых проектах предпочитают писать не на чистом SQL.
Задача № 4. Решить заданную проблему устно. Например, рассказать, как предотвращать взаимные блокировки (deadlock) в многопоточных приложениях, или объяснить, как код, работающий с коллекцией, сделать потокобезопасным.
Здесь обычно требуется сначала рассказать о самой проблеме — в чём она состоит и почему её вообще следует решать, а затем объяснить, как именно это можно сделать. И чем понятнее будет ваш рассказ и чем логичнее будут ваши рассуждения, тем лучше.
При этом не обязательно решать задачу до конца идеально. Того, что вы думаете в правильном направлении, будет вполне достаточно для засчитывания ответа как верного. Ведь в реальности невозможно знать и помнить всё, гораздо важнее умение находить решения, понимать, куда «копать», и ставить эксперименты.
Задача № 5. Задача или серия вопросов на понимание принципов и паттернов ООП. Например, создать класс, объект которого может быть представлен только в единственном экземпляре (по сути, реализовать паттерн Singleton).
Тут могут не только попросить в итоге написать код для многопоточного режима работы, но и объяснить, зачем вообще такое может быть нужно, или рассказать, почему Singleton не используется во фреймворке Spring и чем он там фактически заменяется.
Мы сами сталкиваемся с тем, что на вопросы вроде «для чего в Java используется ключевое слово final» или «может ли статический метод переопределяться при наследовании» отвечают менее 20% кандидатов, по резюме имеющих уровень middle или выше.
Как интерпретируют результаты
Вы, возможно, будете удивлены, но во время решения практических задач работодатель не всегда ждёт полного и чёткого ответа по каждой из них. Он рассчитывает скорее на правильный вектор рассуждения и понимание той или иной темы.
Конечно, когда мы просим написать код, то кандидату лучше бы справиться с этой задачей. Так мы понимаем, что он действительно умеет писать код и делает это сразу чисто. Кроме того, здесь часто бывает важно ваше упорство: умение довести задачу до конца — важнейший навык, с которым у многих в наше время возникают проблемы.
Третье, что также важно увидеть в кандидате, — это понимание базовых, фундаментальных концепций. Если вы не знаете, что такое HTTP, как делать простейшие SQL-запросы, для чего вообще нужна многопоточность и что такое потокобезопасность, вам, скорее всего, откажут.
Когда мы подбираем специалистов уровня junior в нашу команду или кому-то из работодателей, мы проверяем три блока навыков:
- Понимание базовых концепций (синтаксис, коллекции, чистота кода, ООП, создание приложений на Spring, HTTP, REST и SQL).
- Умение быстро, самостоятельно и грамотно решать возникающие проблемы, в том числе находить нужную информацию.
- Уровень обучаемости — скорость и качество запоминания и дальнейшего внедрения в свою работу best practices и рекомендаций, которые мы даём новичку.
После приёма на работу начинающего специалиста важно не перегрузить его слишком сложными задачами. Если он хорошо выполняет свою работу и близок к тому, чтобы начать скучать, то постепенно ему доверяют всё более сложные и интересные проекты, которые обеспечивают дальнейший рост.