История Одного Тестового Задания

Некоторое время назад, листая бескрайние просторы Хабра, я наткнулся на вакансию «Python Backend Developer».

Больше всего меня привлекло расположение офиса - он был рядом с домом, и я написал ответ. Ответ пришел быстро с вопросом о том, готов ли я выполнить тестовое задание.

Я ответил, что подумаю, если мне его пришлют. Письма с заданием не было две недели.

И вот, накануне майских праздников, пришел ответ в виде тестового задания.

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

Однако в тот же день я заболел.

Довольно серьезный насморк со всеми вытекающими.

И на следующий день я решил попробовать выполнить это тестовое задание и посмотреть, что из этого получится.

И именно об этом моя история.

Ниже приведен текст того же задания:

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

Верстка не важна, сосредоточьтесь на бэкенде, дизайне кода и деталях.

По сути приложение должно состоять из одной страницы, но при желании ее можно разделить на несколько (отдельная форма загрузки).

Обязательные элементы — форма загрузки фотографий и таблица со списком загруженных фотографий.

Авторизация не требуется.

Скачать форму: Текстовое поле для ввода названия фотографии Выбор файла Стол: Превью фотографии (необходимо сделать уменьшенную копию фотографии (миниатюру); в этом превью также должна быть ссылка на оригинал/полное изображение, которое открывается по клику на превью) Название фотографии (которое указывает пользователь при загрузке) Производитель и модель камеры (из EXIF, если есть) размер файла Дата создания фотографии (из EXIF) Дата загрузки фото Кнопка «Удалить» Требования: Не сохраняйте существующие фотографии.

Проверьте наличие дубликата файла и при обнаружении выдайте сообщение об ошибке.

Проверьте, является ли загруженный файл изображением; если нет, сгенерируйте ошибку.

(Не используйте проверку наличия данных EXIF в качестве проверки) Не разрешать сохранять фотографии, созданные более года назад (проверьте дату создания фотографии в EXIF).

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

Итак, в качестве веб-фреймворка для Python был выбран Tornado; Я с этим знаком уже давно.

Мы будем поднимать несколько бэкенд-серверов, поэтому нам понадобится балансировщик и Супервизор.

Изначально я думал о HAProxy как о балансировщике, но потом меня осенило, что NGINX умеет хорошо раздавать образы.

В итоге архитектура вначале мне показалась такой: NGINX балансирует соединения и раздает статические данные с диска, 4 сервера Tornado обрабатывают запросы, Redis синхронизирует бэкенд. Бремя анализа входящих изображений и создания миниатюр легло на плечи Tornado. В задании не сказано, какие форматы необходимо поддерживать, поэтому я поискал в Википедии описание EXIF, где упоминаются форматы TIFF и JPEG. Если это все, то дела обстоят не так плохо, библиотека Pillow для Python поддерживает оба формата, а также метаданные EXIF. Но есть нюанс — изображения TIFF не открываются браузером.

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

стол.

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

А в экстренных ситуациях недостающую информацию можно восстановить из метаданных файлов JPEG. Решение с метаданными в JPEG мне показалось красивым, и хотя Pillow вполне способен сохранять EXIF в JPEG, сами метаданные уже должны быть в бинарном формате.

То есть Pillow выдаёт метаданные в виде словаря, но не умеет конвертировать метаданные из словаря.

Была найдена библиотека Gexiv2, которая также работает с метаданными, но ее установка потребовала некоторой сноровки.

Попытки собрать Gexiv2 из исходного кода много раз приводили к ошибкам об отсутствующих библиотеках.

В поисках еще одной такой библиотеки я наткнулся на установочный пакет этой библиотеки для Ubuntu. Но и здесь возникла проблема.

Я установил Python в систему через pyenv и планировал запускать скрипты из virtualenv, но в данном случае установленный в системе Gexiv2 недоступен.

На эту тему есть определенные танцы с бубном, но потратив час на Gexiv2, я решил отказаться от виртуалки и использовать системный Python 2.7.6. Gexiv2 успешно редактирует EXIF в файлах, но у него проблемы с данными в памяти.

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

Я еще не знал, что меня ждет. А меня ждало следующее: в документации Gexiv2 перечислены поддерживаемые форматы, такие как EXV, CR2, CRW и многие другие.

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

Так я нашел ImageMagick и соответствующий адаптер для Python — Wand. Wand выглядел многообещающе — поддержка многих форматов, чтение EXIF, относительно простая установка.

Но для сохранения файлов JPEG с их метаданными мне все равно нужна подушка.

Потратив некоторое время, мне посчастливилось найти библиотеку piexif, которая помогала редактировать метаданные в Pillow, и это стало на одну проблему меньше.

Потратив несколько часов, вы можете сесть и запрограммировать.

Алгоритм был прост, Wand загружает изображение из памяти, выводит данные EXIF, затем Wand отдает буфер RGB, вычисляет свой хэш md5 для проверки на дубликаты, конвертирует буфер в JPEG и сохраняет его со своими метаданными, плюс сохраняет миниатюру.

.

Конечно, мы соответствующим образом обновляем данные в Redis. Остается только проверить.

Однако найти в Интернете картинки с метаданными, да еще и свежие, — проблема.

И я потратил много времени на поиск программы, которая бы хорошо редактировала EXIF-данные.

И вот первый образец JPEG готов, загружаем — работает! Но второй образец, файл CR2 размером 7 МБ, преподнес несколько сюрпризов.

Во-первых, Wand не мог прочитать его из буфера; требовалась подсказка формата в виде расширения исходного файла.

Но тут есть проблема, библиотека начала писать, что не может найти какой-то временный файл.

Поискав еще раз, оказалось, что мне нужно установить утилиту ufraw, и файл прочитался.

За 11 секунд. И тут в JPEG выпало что-то больше похожее на шум, чем на исходное изображение.

Изначально я грешил на Wand, мне казалось, что он криво преобразует изображение в RGB-буфер, однако, когда я запустил калькулятор, я обнаружил, что буфер ровно в 2 раза больше, чем нужно - то есть их не 8 , но 16 бит на канал.

Ура, одна строчка и все работает. Но что делать с длительной загрузкой файлов? Даже если серверов четыре, такое же количество больших файлов CR2 просто сделает сервис недоступным.

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

И в результате тестовое задание было провалено — результат работы приложения оказался неприемлемым.

И больное тело просило покоя.

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

Я начал с создания модуля загрузки NGINX, и, конечно же, безуспешно.

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

Далее, собственно, скопируйте и вставьте в новые сценарии обработки изображений.

Настраиваем Supervisor и NGINX, и завершаем скрипт установки.

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

В случае ошибки результат загрузки сохраняется в течение одних суток.

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

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

Что хотел узнать работодатель с помощью этого задания, мне не очень понятно.

Может быть, вам нужно было написать свою библиотеку для получения EXIF-данных? И такое тестовое задание нельзя назвать маленьким — оно заняло более 8 часов.

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

Исходники можно посмотреть на github .

И я буду продолжать болеть.

Теги: #python #tornado #Nginx #redis #backend #exif #python #Perfect code


Руководитель отдела развития Эквид Василий Васильков написал о том, как кандидаты выполняют тестовые задания и что из этого получается.

Получилось забавно.

Публикуем заметку слово в слово.

*** Расскажу историю одного тестового задания.

Немного длинно, но, надеюсь, интересно.

В Эквиде все тестовые задания для инженеров открыто публикуются на GitHub здесь — github.com/Ecwid/новая-работа .

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

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

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

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

Почему-то я так думал тогда.

Качельку нужно сделать действительно очень примитивно.

Судите сами — вы даете ему список ссылок в текстовом файле, а он скачивает эти файлы и кладет их в указанную папку на локальном диске.

Должен иметь возможность загружать несколько файлов одновременно (в несколько потоков, например 3 потока) и выдерживать указанное ограничение скорости загрузки, например, 500 килобайт в секунду.

Все.

Для работы с HTTP не нужно ничего изобретать; вы можете использовать любую библиотеку.

Для ограничения скорости - библиотека.

Для загрузки в несколько потоков даже не нужна библиотека — всё есть в стандартной библиотеке Java. Можно, конечно, все это придумать и написать самому на коленях, но это не обязательно.

По сути, вам нужно взять несколько «кубиков» и аккуратно придать им правильную форму, используя немного программирования.

Этому заданию почти три года.

За эти годы я приобрел бесценную коллекцию рокеров всех цветов и размеров.

Если жизнь заставляет меня скачивать что-то в несколько потоков по HTTP, я спокоен как удав, у меня более сотни решений на любой вкус.

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

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

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

Да, работа будет вестись на скомпилированных языках Java/Kotlin, но она не будет скомпилирована.

Локальная IT-разновидность корпускулярно-волнового дуализма, как я понимаю это явление.

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

Обычно это самые интересные вакансии.

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

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

Например, вы хотите скачивать со скоростью 300Кб/с, а программа скачивает около 2Мб/с.

Разница всего в шесть раз, но строго 2 мегабайта в секунду и не более.

Как сказал один кандидат, «скорость поддерживается в определенном интервале туда и обратно».

Мне очень понравился и «определенный интервал», и «туда-сюда».

Теперь я сам стараюсь как можно чаще использовать эту фразу — «Мы сделаем эту фичу за двадцать дней, пять дней туда-сюда».

— Параллельная загрузка.

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

Если вам приходит письмо с вопросом «Это как ReGet в нескольких тредахЭ», то вы сразу понимаете, что кандидат вряд ли намного моложе вас и помнит времена модемов.

Еще я помню все эти бесконечные ReGet, FlashGet, Download Master и прочую милую интернет-лажу конца девяностых-начала двухтысячных.

Нет, вам нужно скачивать не один файл в несколько потоков, а просто несколько файлов одновременно.

Однако, с другой стороны, это требование дает неиссякаемый источник удовольствия при проверке задач: * Например, я хочу скачивать в 3 потока, а программа скачивает в 4. Ставлю 5 потоков - программа скачивает в 6. Что за фигня? Как здесь можно сделать ошибку? Захожу в исходный код и нахожу комментарий «Давайте увеличим количество запрашиваемых пользователем потоков на один, чтобы он загружался еще быстрее».

Черт, можешь поспорить.

* Другой пример — кандидат пишет «Программа может загружать файлы в N потоков, но случаи N более одного пока не поддерживаются».

Фраза прекрасна до последней точки.

Читая, я вытирал пот ушами, подивился человеческой ловкости и вспомнил анекдот про математика и камерный оркестр.

Бесконечное количество просто интересных решений от неординарных людей: * Как вам, например, такое решение - задача просто узнавала, файлы какого размера и с какой скоростью следует скачивать, делила размер на скорость и уходила в сон на полученное количество секунд. Я даже где-то в глубине души нахожу это решение логичным - программа должна работать NN секунд, и она работает, до чего вы докопались?! Судя по всему, кандидат не ожидал, что инспектор просто возьмет и увидит (какой обман!), что на самом деле программа накачала.

Действительно, очень умное решение.

* А вот еще один, видимо, очень умный человек, который прислал один класс с пустой основной функцией (и ничем больше) и объяснил: «Вот как я планирую как-то выполнить эту задачу.

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

Жду второй год, не теряя надежды, однако.

* Помню замечательного человека, который написал, что скачивание файлов по HTTP — совершенно простая задача и можно ли ему этого не делать? Я в духе ответил, что, конечно, не надо этого делать, и мы расстались друзьями.

Больше я его никогда не слышал и не видел.

Мужчина просто спросил меня в письме, не может ли он что-то сделать; Я, со своей стороны, не нашел в себе сил запретить ему это сделать.

Все.

Надеюсь, мой ответ помог человеку достичь нирваны, а он по-прежнему ничего не делает. * Замечательный кандидат, который сказал, что не знает Java и можно ли выполнить задание на Go? Я сказал в том смысле, что «черт с ним, давайте использовать Go», на что получил ответ — «отлично, я тоже Go не знаю, так что выучу и сделаю»! Скажу честно - я горжусь тем, что знаю (пусть даже случайно) такого настойчивого человека.

Самый интересный случай произошел со мной в Пензе (СЕК, привет!) ночью на улице после after-party. Ночь, улица, людей почти нет, я стою и жду такси, чтобы поехать в отель.

Вдруг откуда-то из темноты ко мне подходит мужчина и говорит: «Василий, я пытался устроиться на работу в Эквид, ты мне отказал и с тех пор я очень хочу встретиться с тобой лично!!» Трудно описать, какие мысли проносились у меня в голове в эти секунды.

Чувак, если ты читаешь эти строки, то спасибо за опыт, ко мне еще никто ночью не подбегал с такими двусмысленными формулировками.

Вообще-то этой несерьезной историей я хотел сказать две серьезные вещи: 1) Уважаемые кандидаты.

Что вас губит, так это ваше нежелание бросить проделанную работу и начать все сначала.

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

В панике вы начинаете вставлять в свой код костыли concurrency, которые для этого не предназначены.

Вам не обязательно этого делать.

Самый правильный способ — выкинуть все написанное и написать с нуля, учитывая недостающие требования.

Серьезно.

Это не производственный код, костылям здесь не место.

2) Может сложиться впечатление, что я как-то несерьёзно отношусь к кандидатам и их тестовым заданиям.

Это абсолютно неправда.

Каждую представленную работу я проверяю с большим любопытством и удовольствием.

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

Делайте больше тестовых заданий, делайте их чаще и присылайте мне.

Эквид всегда ищет разработчиков.

Прямо сейчас тоже.

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

В общем, это непросто, но интересно.

Основной стек — Java/Kotlin, но очень нужны и специалисты по ReactNative. Ищем разработчиков практически любого уровня от джуниора и выше (Ульяновск, Самара).

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

Наш стек в виде непонятных слов и аббревиатур — Java, Kotlin, PostgreSQL, Cassandra, Redis, AWS, Consul, Docker, микросервисы.

Ну, есть еще много всего.

По всем вопросам пишите в комментариях или на почту [email protected] Теги: #ecwid #тестовое задание #HR-процесс #java #Управление разработкой #фриланс #Управление продуктом #Карьера в IT-индустрии

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.