timurnav
21 уровень

Тестовое задание на трудоустройство, давайте разберемся..

Пост из группы Архив info.javarush.ru
3786 участников
Друзья, всем привет. хочу поделиться с вами опытом решения тестового задания на позицию java developer'а российской компании. Сразу скажу, реализовать основной функционал задания не представляет особой сложности, но как всегда важны детали и мелочи, которые помешали мне сдать его в срок, по заданию мне так ничего и не ответили - вакансия у них уже закрыта была когда я высылал им. Предлагаю разобраться с заданием всё ли я сделал что от меня требовалось. А тем кто понятия не имеет, как его сделать, я добавлю много воды, о том как я с ним разделывался. Если это вдруг кому интересно - добро пожаловать под кат. Сразу скажу, что тут всё решение я выкладывать не буду, но за-то будет много объяснений для начинающих, если кому не интересно читать мои изливания, вот вам проект на github Начну с самого текста задания.
Тестовое задание №1
Описание: Сервер API (JSON HTTP API) Средства разработки: Java Framework: Play Framework 2.4 (или выше) или Spring boot 1.2.3 (или выше) База данных: MySQL Протокол: HTTP, порт 80 Функционал (запросы):
  1. Загрузчик.
    • Передаем на сервер файл (картинка аватара JPG).
    • Сохраняем картинку в каталоге на сервере.
    • Ответ сервера - внутренний URI картинки.
  2. Добавление нового пользователя.
    • Передаем на сервер персональные данные пользователя (URI картинки, имя пользователя, email и т.д.).
    • Сохраняем информацию в базе данных.
    • Ответ сервера - уникальный ID нового пользователя.
  3. Получение информации о пользователе.
    • Передаем на сервер уникальный ID пользователя.
    • Читаем информацию из базы данных.
    • Ответ сервера - персональные данные пользователя (см. выше).
  4. Изменение статуса пользователя (Online, Offline).
    • Передаем на сервер уникальный ID пользователя и новый статус (Online, Offline).
    • Изменяем статус пользователя.
    • Ответ сервера - уникальный ID пользователя, новый и предыдущий статус.
    Примечание: на сервере выполняется запрос к внешнему API/базе данных. Так как это упрощенное тестовое задание необходимо реализовать "заглушку” с имитацией обращения и задержкой по времени 5-10 сек.
  5. Статистика сервера.
    • Передаем параметры на сервер: 1. статус клиентов (Online, Offline или отсутствует), 2. уникальный ID (timestamp) запроса (может отсутствовать)
    • Ответ сервера - список пользователей со статусами и URI картинки, а также уникальный ID (timestamp) запроса.
    Примечание: Если в запросе есть параметры, то сервер должен фильтровать по ним свой ответ. Если в запросе есть уникальный ID (timestamp) запроса (полученный ранее), то сервер должен вернуть только пользователей, у которых изменились статусы после (по времени)этого уникального ID (timestamp).
Обязательные требования:
- RESTful. - Все данные в формате JSON. - Сервер API должен быть спроектирован с учетом того, что запросы 3 и 5 имеет высший приоритет (по отношению к запросам 1, 2, 4) и должны быть выполнены максимально быстро. - Обработка ошибок.
Необязательные требования (желательно):
- Документирование кода. - Архитектура Сервера API должна быть рассчитана на высокую нагрузку и масштабирование. - Тесты.
Результат тестового задания:
- Результат тестового задания должен быть предоставлен в архиве и с подробной инструкцией по его развертыванию. Желательно приложить Dockerfile для сборки Docker контейнера для тестового задания. Можно загрузить на github.com. - Должен содержать краткую документацию созданного API (список запросов, параметры запросов, форматы запросов, форматы ответов и т.д.). - Информация о времени потраченном на тестовое задание в разрезе: проектирование, программирование, документация и т.д. Обращаем внимание, что это тестовое задание предназначено только для оценки знаний и умений, а не ставит целью создание законченного продукта (сервера API), поэтому допускаются упрощения с объяснением и указанием причин.
внимательные и опытные программисты могут пропустить следующий раздел, тут я буду разбираться с самим текстом задания. "Шапка" задания не вызывает никаких сложностей с восприятием, поэтому просто скажу что мой выбор пал на Spring Boot, но не потому что я уже когда-то что-то на нем делал, а потому что я уже прошел реальный проект с использованием Spring (но Boot'а там не было, как я понимаю из-за его простоты). По функционалу сервера: 1) Загрузчик файлов. Тут принципиально ничего сложного нет, мне нужно было просто разобраться как картинки вообще хранятся на сервере, оказалось, что наиболее удобным способом является простое размещение их в какой-нибудь специально отведенной для этого директории. Конкретную реализацию разберем ниже. 2) Добавление нового пользователя, простая операция, если вы делали когда-нибудь CRUD приложения, то он поддержит меня, если нет - всё увидите ниже. 3)Получение информации о пользователе. нет вопросов - всё ясно. 4)Изменение статуса пользователя. первые два пункта задания ясны как день, а что там с внешним запросом??? тут без 100гр не разобраться, я даже сейчас на 100% не уверен правильно ли я понял. Детали ниже. 5)Статистика сервера. Тут тоже интересно. первым пунктом предлагается реализовать метод с различными вариантами параметров, пока не понятно как это делать учитывая что это должен быть метод контроллера. вторым пунктом спрашивают всех юзеров, у кого изменился статус после момента времени вроде понятно, но есть тонкости.
Getting Started
ох, сколько раз я читал эту фразу, пока разбирался с этим заданием! Если вы пробовали когда нибудь разбираться в настройке проекта на Spring, но при этом по какой-то причине так ни разу и не попробовали Spring Boot, поздравляю вас, вы испытаете просто восторг от того, что я напишу ниже. Я где-то вычитал, что раньше программисты очень большое количество кода раньше переносили из проекта в проект, это шаблонный код - настройки подключения к базам данных, маппинг сервлетов и прочее-прочее, так вот чтобы, например, уменьшить объем шаблонного кода для работы с базами данных мы используем JPA/Hibernate, они скрывают часть шаблонов но чтобы настроить их опять же нужно писать xml файл или конфигурационные классы. а если у вас маленький проект, то получается что ни фига вы не меньше кода пишете, а даже наоборот. Дальше мы оборачиваем работу с JPA в Спринг, есть много проектов, но наиболее удобный это, конечно же, Spring Data. Это очень большой проект который может работать наверное со всем чем можно и JPA и NoSQL еще целую кучу разных проектов, он невероятно магический мы будем его использовать в нашем проекте. Используя Spring мы почти избавляемся от настроек соединения с БД, Spring все делает за нас, нам только нужно навтыкать нужных аннотаций по транзакционности, кешированию и в особых случаях нагуглить (подсмотреть у других) еще каких-нибудь настроек в кофигурации контекста. Но при этом у большинства начинающих разработчиков нет абсолютно никакого понятия как создать проект на Spring. Никто не знает полностью как его настроить чтобы запустить проект и получить результат в браузере пройдя по ссылке начинающейся с localhost:8080/*. И тут на сцену выходит Spring Boot! Про Spring Boot лучше рассказать на конкретном примере! Начнем с заготовки. Чтобы создать проект Spring Boot разработчики Spring придумали "конструктор" создания шаблонов. Им можно воспользоваться на их сайте, но гораздо проще сделать это в нашей любимой IDE Intellij IDEA. И так: File->New->Project В окне переходим на вкладку Spring Initializr, в ней должно быть выставлено jdk, и URL https://start.spring.io, проверяем подключение к интернету, далее нужно будет выбрать название, а затем технологии которые мы будем использовать, на первом этапе нам нужно только WEB - ставим рядом с ней галочку и далее создается проект. Чтобы мавен подтянул все зависимости нам нужно открыть вкладку Maven в идее и нажать кнопку обновить. Мы получили готовый шаблон приложения, в котором зарыты все настройки для клиент-серверного общения. Чтобы получить первое впечатление создадим класс контроллера(про MVC-то уж наверняка все слышали). Во всех Spring приложениях контроллеры имеют достаточно простую конструкцию - это класс, который помечен аннотацией @Controller(возможны префиксы, например, @RestController), этот класс отвечает за обработку входящих запросов. Для того, чтобы контроллер распознал запрос на какой-нибудь адрес нужно сделать маппинг этого адреса на метод контроллера. Ниже представлен код этого класса, пока мы будем работать без иехрархии директорий, поэтому положим его в один пакадж с классом созданным автоматически Initializr'ом, у меня он называется DemoApplication. import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/hello") public class DemoController { @RequestMapping(method = RequestMethod.GET) public String halloWorld() { return "Hello World!"; } @RequestMapping(value = "/{name}", method = RequestMethod.GET) public String halloName(@PathVariable("name") String name) { return "Hello, " + name + "!"; } } разберемся что тут. @RestController. как раз та аннотация, о которой я писал выше. именно рестконтроллер используем поскольку мы хотим сразу увидеть результат и не хотим писать страницы.jsp (фу-кака), нам будет проще сразу увидеть результат в браузере в виде строки. @RequestMapping - как раз привязка к адресу. префикс общего адреса будет такой: localhost:8080. Как мы видим весь класс висит на адресе /hello, это означает что все методы внутри этого класса имеют префикс localhost:8080/hello. Далее первый метод класса, в его собственном маппинге указан метод Http протокола - запрос GET(про методы Http протокола почитайте сами) Что это всё означает? обратившись GET запросом на адрес localhost:8080/hello - получим ответ в виде строки "Hello World!", давайте проверим это! В классе DemoApplication, есть одна крутая аннотация, которая можно сказать в одиночку запускает весь контекст спринга - @SpringBootApplication. Метод main этого класса становится волшебным, как раз запускает всю магию скрытую в SpringApplication, если вызвать контекстное меню на этом классе то в строке Run появятся варианты, рекомендую запускаться раном с зеленой меткой, так консоль будет приятнее выглядеть и в будущем будет проще читать логи прям из нее. Запускаем приложение. когда вывод в консоль прекратится, вы должны увидеть в консоли
2015-09-02 09:25:36.895 INFO 5844 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2015-09-02 09:25:36.900 INFO 5844 --- [ main] demo.DemoApplication : Started DemoApplication in **** seconds (JVM running for 15.501)
где "****" - длительность запуска приложения :) после этого в любом браузере (или curl, или чем там вы пользуетесь?) нужно набрать адрес на который замапили метод контроллера
localhost:8080/hello
В браузере должно отобразиться каноническое
Hello World!
вот вам и веб приложение! Если вы заметили в контроллере есть еще один метод, там есть собственный маппинг адреса, к текущему адресу добавляется плейсхолдер. Который спрингом передается в метод в качестве параметра. Не трудно догадаться что за это отвечает аннотация @PathVariable. Так на запрос
localhost:8080/hello/Ваше имя
браузер покажет
Hello, Ваше имя!
С основами Spring Boot разобрались. Далее прикрутим базу данных, но это будет уже в следующем посте. Всем спасибо.
Комментарии (10)
  • популярные
  • новые
  • старые
Для того, что бы оставить комментарий вы должны авторизоваться
timurnav21 уровень
2 сентября 2015, 19:11
Там еще прикол такой был, я им пару вопросов уточняющих задал, которые мне казались спорными, ответ последовал такой: я не могу полностью ответить на этот вопрос, иначе это будет считаться подсказкой :D
Это такой тонкий референс к «неточным» формулировкам задач на javarush
quazrckk31 уровень, Sosnovy Bor
2 сентября 2015, 22:00
однако на jr валидатор принимает единственный вариант, а людям все же можно объяснить, почему сделал именно так)
timurnav21 уровень
2 сентября 2015, 22:04
согласен, в качестве учебного пособия пару раз на этом можно заострить внимание) я тоже очень много ругался на тему того, что «я не понял задание», меня Хуберт даже в игнор в вк ставил помнится) но щас я понимаю, что с его колокольни такие банальные вещи понять сложно, все равно что тебя попросят объяснять таблицу умножения :)

ps не единственный)
Kaxeda31 уровень, Москва
2 сентября 2015, 18:34
А это на какую позицию было такое тестовое задание? На джуна или на миддла? Потому что у меня на джуна было в разы проще…
timurnav21 уровень
2 сентября 2015, 19:06
Java разработчик написано, без уточнений
lichMax40 уровень, Санкт-Петербург
16 июля 2017, 20:31
это же обычно «миддл» означает. Что вообще-то видно по заданию.
4e4el34 уровень, Rostov
2 сентября 2015, 15:19
Статья понравилась, жду продолжения :)
quazrckk31 уровень, Sosnovy Bor
2 сентября 2015, 14:29
Какой срок на выполнение давали?
timurnav21 уровень
2 сентября 2015, 14:32
мне сроки не ставили, даже наоборот, у меня спросили за сколько я справлюсь. мне задание прислали в понедельник, в следующий понедельник вакансия уже была закрыта
timurnav21 уровень
2 сентября 2015, 11:36
Прочитал задание еще раз и понял что я кое в чем накосячил! Блин 10 раз уже наверно это задание читал и всё равно блин нашел что-то новое…