Школа розробки інтерфейсів: розбір завдань для Мінська та новий набір у Москві

Сьогодні відкрився новий набір Школу розробки інтерфейсів Яндекса в Москві. З 7 вересня до 25 жовтня пройде перший етап навчання. Студенти з інших міст зможуть у ньому взяти участь дистанційно або очно — компанія оплатить дорогу та проживання у хостелі. Другий він фінальний етап триватиме до 3 грудня, його можна пройти тільки очно.

Мене звуть Юлія Середич, цю посаду ми написали разом із Сергієм Козаковим. Ми обидва розробники інтерфейсів у мінському офісі Яндекса та випускники ШРІ минулих років.

Школа розробки інтерфейсів: розбір завдань для Мінська та новий набір у Москві

З нагоди відкриття реєстрації в Москві ми публікуємо розбір вступних завдань до попередньої школи — тут, у Мінську.

Якщо простежити історію завдань ШРІ, то ми з року в рік перевіряли три важливі для програміста навички:

  • Верстка. Кожен розробник має вміти верстати. Не буває такого, що у вас є дядько Сергій, який верстає для всієї команди, а ви пишете тільки скрипти. Тому кожен студент має показати, як він вміє верстати.
  • JavaScript. Якби справа обмежувалася версткою, то у нас була б не Школа розробки інтерфейсів, а Школа верстальників. Гарний згорблений інтерфейс потрібно пожвавити. Тому завжди є завдання на JS, але іноді воно є і завданням на алгоритми — настільки сильно ми їх любимо.
  • Вирішення проблем — мабуть, головна навичка розробника. У створенні інтерфейсів все швидко змінюється. Це як у Льюїса Керолла: «Доводиться бігти з усіх ніг, щоб тільки залишитися на тому самому місці, а щоб потрапити в інше місце, треба бігти вдвічі швидше». Щодня ми стикаємося з новими технологіями — необхідно з ними зважати і вміти розібратися в них. Тому в третьому завданні ми запропонували розібратися в технологіях, з якими розробник-початківець зазвичай не знайомий.

У розборі кожного завдання ми розповімо не лише про правильний порядок дій, а й про поширені помилки.

Завдання 1: Портфоліо

Над першим завданням працював дизайнер Яндекс.Колекцій Олексій Черенкевич, який вміє верстати, та його колега з сервісу — розробник інтерфейсів Сергій Самсонов.

Умова

Створіть сайт-портфоліо: розкажіть про себе, свої роботи та очікування від Школи. Сайт повинен максимально відповідати запропонованому макету (посилання на макети: 1000px, 600px, 320px, специфікація). Нас цікавить лише верстка, тому JavaScript прохання не використовувати.

Під час перевірки ми враховуватимемо:

  • розміри відступів, правильність кольору, зображення шрифтів, розмір кегля;
  • семантичну верстку;
  • наявність різних станів елементів: відображення кнопок та посилань при наведенні курсору, виділення активних полів введення тощо;
  • кросбраузерність (перевіряється в останніх версіях популярних браузерів).

Плюсом буде:

  • використання сучасних CSS-рішень: flexbox, grid та ін;
  • адаптивна верстка;
  • використання пре- та (або) постпроцесорів, складання, мініфікація, оптимізація вихідного коду;
  • HTML-валідація форми, стилізована кнопка завантаження файлів.

Завдання досить об'ємне, тому можна пропустити те, що не виходитиме. Це трохи знизить бал, але ви все ж таки зможете продемонструвати свої знання. Після завершення роботи надішліть нам два посилання – на портфоліо та вихідний код на GitHub.

Макети, запропоновані в завданні, були не просто з екранами для мобільних пристроїв, планшетів та десктопів, а й зі справжньою специфікацією.

Щоб зробити результат перевірки першого завдання якомога більше об'єктивності, критеріїв цієї перевірки було дуже багато.

Критерії

Зверстаний сайт. Це здається очевидним, але деякі хлопці пропускали деякі блоки цілком — чи хотіли заощадити час, чи не змогли зробити їх. Макет умовно можна поділити на чотири основні екрани: головний екран із аватаркою, блок зі списком очікувань від ШРІ, блок із портфоліо та блок із контактною інформацією. Їх можна було робити секціями або просто за допомогою div, головне — щоб були всі чотири блоки.

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

Адаптивна верстка — це коли інтерфейс не просто зверстаний так, щоб на трьох дозволах все було піксель у піксель за макетом. У проміжних станах верстка теж має розвалюватися. Хтось забував обмежити максимальну ширину контейнера і тягнув все на 1920 пікселів, хтось напортачив із фонами, але загалом кандидати впоралися з цим завданням добре.

Семантична верстка. «Скільки разів твердили світові», що посилання має бути оформлене як , кнопка — як . На щастя, більшість кандидатів виконали і цю вимогу. Не всі розпізнали список, що причаївся, в очікуваннях від ШРІ, зробивши його за допомогою тегів div, але це не так страшно. Був кандидат, який вставив усі семантичні теги, які тільки знав – де треба та де не треба. Наприклад, замість списку і . Все-таки семантика - вона про розуміння складу своєї сторінки і призначення кожного блоку (тут більшість впоралася), а також про використання пре-і/або постпроцесорів (тут справилися небагато, хоча це теж було в пунктах - найчастіше підключали less і scss) .

Працюючий слайдер. У завдання ми написали, що JS використовувати не можна. Тут перевірялася здатність вирішувати проблеми – слайдер можна було зробити за допомогою зв'язки та . Вся магія відбувається на рівні селектора #button-N:checked ~ .slider-inner .slider-slides. Коли ми клацаємо по одному з інпутів-чекбоксів, він переходить у стан checked. Ми можемо скористатися і призначити потрібний нам translate на контейнер зі слайдами: transform: translate(-33%). Реалізацію слайдера можна переглянути тут.

Списоки, що розкриваються. Тут все теж зводилося до і схожому селектору: .accordion-item input:checked ~ .accordion-item__content. Реалізацію можна переглянути тут.

Наявність станів :hover, :active та :focu*. Дуже важливий пункт. Від нього залежав комфорт під час взаємодії з інтерфейсом. Користувач завжди повинен отримувати зворотний зв'язок про свої дії. Цей пункт перевірявся протягом усієї взаємодії з анкетою. Якщо я натиснув кнопку "Зателефонуйте мені" і візуально нічого не трапилося (хоч запит і відправився) - це погано, тому що потім я натисну її знову і знову. У результаті вирушить десять запитів і мені передзвонять десять разів. Не треба забувати і про те, що на мобільних пристроях немає миші, а отже, не повинно бути hover. І ще один момент, який не торкнувся тих, хто виконав пункт про семантику. Якщо ваш контрол не є інтерактивним елементом, то при наведенні на нього курсор залишиться стандартним. Це виглядає дуже неохайно, навіть якщо ви прописали реакцію на hover. Не варто недооцінювати cursor: pointer.

Анімації. Важливо, щоб всі, що відбуваються з елементами реакції, були плавними. У житті немає нічого миттєвого, тому наявності transitions на hover та active було достатньо для того, щоб зробити інтерфейс приємнішим. Ну а ті, хто анімував слайдер та списки, взагалі молодці.

Використання новітніх технологій. Багато хто використовував flex, при цьому ніхто не виконав завдання за допомогою grid. Пункт зараховувався, якщо flex використовувався грамотно. Якщо десь верстка через ці самі flex роз'їжджалася — на жаль, додаткових балів ви не отримували.

Валідація форми. Потрібно було лише дописати в кожен input форми атрибут, що вимагається. Ми додавали бал тим, хто валідував поле електронної пошти як email.

Cтилізація кнопки завантаження файлів. Ми очікували побачити зв'язку виду: та Виберіть файл . Далі потрібно було приховати input та стилізувати label. Є ще один найпоширеніший спосіб - зробити прозорий input і покласти його поверх кнопки. Але не всі браузери дозволяють стилізувати , і таке рішення не можна назвати повною мірою кросбраузерним. Та й семантично правильніше зробити label.

Кросбраузерність. Ми перевіряли, що все добре, у двох останніх версіях сучасних браузерів (без IE - учасникам пощастило), а також у Safari на айфонах та Chrome на андроїдах.

Ми, навпаки, знімали бали, якщо хтось використовував JS або Bootstrap: і те, й інше позбавляло сенсу все завдання. Причому учасники з Bootstrap не лише отримували мінус, а й недоотримували багато балів за семантику та реалізовані елементи.

Ті, хто помітив свій сайт десь в інтернеті, не отримали особливої ​​переваги — але перевіряльники дуже раділи, коли не доводилося завантажувати репозиторії та запускати їх локально у себе на комп'ютері. Тож це служило плюсом у карму.

Перше завдання було дуже корисним насамперед для студента. У тих, кого ми не прийняли, тепер є зверстане резюме — можна гордо прикріплювати його до всіх відгуків або викласти на свій gh-pages.

Завдання 2: Транспортний шлях

Автор завдання – керівник групи пошукових інтерфейсів Денис Балико.

Умова

Ви маєте карту зоряного неба. На ній вказано назву кожної зірки, а також відстань від неї до інших зірок у світлових секундах. Реалізуйте функцію solution, яка має приймати три аргументи: об'єкт, у якому ключами є назви зірок, а значеннями – відстані до зірок (у космосі односторонній рух), а також назви початкової та кінцевої точки шляху – start та finish відповідно. Функція повинна повертати найкоротшу відстань від зірки start до зірки finish і шлях, яким потрібно пройти.

Сигнатура функції:

const solution = function(graph, start, finish)  {
    // Ваше решение
} 

Приклад вхідних даних:

const graph = {
  start: { A: 50, B: 20 },
  A: { C: 40, D: 20 },
  B: { A: 90, D: 90 },
  C: { D: 160, finish: 50 },
  D: { finish: 20 },
  finish: {}
};
const start = 'start';
const finish = 'finish'; 

Приклад вихідних даних:

{
    distance: 90,
    path: ['start', 'A', 'D', 'finish']
} 

Примітка: каркас рішення знаходиться в папці src/, помістіть рішення в solution.js.

Перевірка другого завдання була автоматизованою і об'єктивною. Більшість хлопців здогадалися, що потрібно реалізувати алгоритм Дейкстри. Ті, хто знайшов його опис та реалізував алгоритм на JS, — молодці. Однак під час перевірки завдання ми зустріли багато робіт з однаковими помилками. Ми пошукали в інтернеті за фрагментами коду та знайшли статтю, звідки учасники списали алгоритм. Цікаво, що багато хто копіював код зі статті разом із коментарями автора. Такі роботи здобули низький бал. Ми не забороняємо користуватися будь-якими джерелами, але хочемо, щоб людина вникала в те, що вона пише.

Критерії

Основні бали нараховували за тести. Іноді було видно, що хлопці погосподарювали в репозиторії, перейменувавши папки і тести падали просто тому, що не могли знайти потрібні файли. Цього року ми намагалися допомогти таким хлопцям та повертали все на місце за них. Але наступного року ми плануємо перейти на систему контестів, і таке вже не прощатиметься.

Були й людські, ручні критерії. Наприклад, наявність єдиного кодстайлу. Ніхто не знижував бали за те, що ви використовуєте таби замість прогалин або навпаки. Інша річ, якщо ви чергуєте одиночні лапки з подвійними по одному вам відомому правилу, а крапки із комами ставите вроздріб.

Окремо враховувалася зрозумілість та читання рішення. На всіх конференціях світу розповідають, що робота програміста на 80% складається із читання чужого коду. Навіть школярі проходять шнур — у своїх кураторів і один одного. Отже, цей критерій мав значну вагу. Зустрічалися роботи, в яких не було змінних довше за один символ — будь ласка, не робіть так. Дуже тішили коментарі учасників — за винятком тих, що були ідентичні до коментарів Стелли Чанг.

Останній критерій – наявність автотестів. Їх додали лише кілька людей, але для кожного це стало величезним плюсом у карму.

Правильне рішення:

const solution = function(graph, START, FINISH)  {
    // Всё не бесплатно в этом мире
    const costs = Object.assign({[FINISH]: Infinity}, graph[START]);

    // Первая волна родительских нод
    const parents = { [FINISH]: null };
    Object.keys(graph[START]).reduce((acc, child) => (acc[child] = START) && acc, parents)

    const visited = [];
    let node;

    // Ищем «дешёвого» родителя, отмечаем пройденные
    do {
        node = lowestCostNode(costs, visited);
        let children = graph[node];
        for (let n in children) {
            let newCost = costs[node] + children[n];

            // Ещё не оценена или нашёлся более дешёвый переход
            if (!costs[n] || costs[n] > newCost) {
                costs[n] = newCost;
                parents[n] = node;
            }
        }
        visited.push(node);
    } while (node)

    return {
        distance: costs[FINISH],
        path: optimalPath(parents)
    };

    // Возврат назад по самым «дешёвым» родителям
    function optimalPath(parents) {
        let optimalPath = [FINISH];
        let parent = parents[FINISH];
        while (parent && parent !== START) {
            optimalPath.push(parent);
            parent = parents[parent];
        }
        optimalPath.push(START);
        return optimalPath.reverse();
    }

    // Минимальная стоимость из текущей ноды среди непросмотренных
    function lowestCostNode(costs, visited) {
        return Object.keys(costs).reduce((lowest, node) => {
            if (lowest === null || costs[node] < costs[lowest]) {
                if (!visited.includes(node)) {
                    lowest = node;
                }
            }

            return lowest;
        }, null);
    };
};

Завдання 3: Календар подій

Його підготували розробники інтерфейсів Сергій Казаков та Олександр Підскребкін.

Умова

Напишіть міні-календар для відображення розкладу. Можна взяти будь-який розклад, який вам сподобається. Наприклад, розклад фронтенд-конференцій у 2019 році.

Календар має виглядати як список. Інших вимог до дизайну немає. Зробіть можливість ставити нагадування про подію за 3, 7 та 14 днів. Після першого завантаження з Інтернетом календар повинен відкриватися та функціонувати в автономному режимі.

Корисні ресурси

Розклад фронтенд-конференцій:
confs.tech/javascript?topics=javascript%2Bcss%2Bux

Service workers:
developer.mozilla.org/ru/docs/Web/API/Service_Worker_API/Using_Service_Workers
developers.google.com/web/fundamentals/primers/service-workers

Notifications API:
developer.mozilla.org/ru/docs/Web/API/Notifications_API

Третє завдання було найцікавішим для перевірки, бо знайшлося дуже багато варіантів розв'язання, кожен має свій. Ми перевіряли, як кандидат поводиться з незнайомими технологіями — чи вміє дослідити, чи тестує свої рішення.

Критерії

Зверстаний календар. Так, його все-таки потрібно було згорнути. Були й ті, хто зрозумів умову надто буквально і не вставив жодного рядка CSS-коду. Це виглядало не дуже уважно, але якщо все працювало — бали не знижувалися.

Отримання списку подій із джерела. Це вже завдання не на верстку, тому вшитий до неї перелік заходів не зараховувався. Завжди можна скасувати конференцію, перенести її, додати нову. Отже потрібно було отримувати дані ззовні і рендерувати верстку вже на основі отриманого JSON. Важливо було будь-яким способом (методом fetch або за допомогою XMLHttpRequest) отримати дані. Якщо людина додавала поліфіл для fetch і позначала в readme свій вибір - це зараховувалося як плюс.

Реєстрація service worker без помилок та робота в офлайні після першого завантаження. Ось приклад service worker з кешуванням розкладу на першому завантаженні. Подробиці про service workers, їх можливості та способи роботи з ними (стратегії роботи з кешем, роботу в офлайні) можна переглянути тут.

Можливість встановити нагадуваннящоб воно дійсно спрацювало через 3, 7, 14 днів. Потрібно було розібратися в Notifications API, посилання на який знаходилася прямо в завданні. Ми не чекали якоїсь конкретної реалізації перевірки того, чи настав час для пуша. Приймався будь-який варіант: зберігання в localStorage, IndexDB або періодичне опитування сервіс-воркером. Можна було навіть зробити пуш-сервер (ось приклад), але в офлайні він би не працював. Не менш важливо було отримати пуш після того, як сторінку закрили і відкрили через якийсь час. Якщо нагадування «вмирало» одночасно із закриттям сторінки, рішення не зараховувалося. Круто, коли хлопці думали про перевіряльників і робили змогу отримати пуш прямо зараз, щоб не чекати 3 дні.

Можливість винести іконку на робочий стіл (PWA). Ми перевіряли наявність файлу manifest.json з правильними іконками. Деякі хлопці зробили цей файл (або залишили згенерований у CreateReactApp) - але не додали вірні іконки. Тоді при спробі встановлення виникала помилка виду "потрібна інша іконка".

Кодстайл та структура проекту. Як і в другому завданні ми дивилися на єдиний кодстайл (навіть якщо він не збігався з нашим). Деякі хлопці прикручували лінтери – це чудово.

Помилки в консолі. Якщо прямо в консолі був індикатор, що щось не так, а учасник не звертав на нього уваги, ми знімали бали.

Підсумки

Кумедне у рішеннях учасників:

  • Одна анкета містила наступний текст: Зібрати реакт-додаток допоміг друг програміст. Я його закидав питаннями, що як і чому, він розповідав. Дуже сподобалося, хочу більше дізнатися про це. Ми всім серцем вболівали за цю анкету, але на жаль, друг кандидата не дуже допоміг йому зробити додаток, що працює.
  • Один кандидат надіслав посилання на GitHub, де лежав RAR-архів — це складно якось прокоментувати. 🙂
  • Ще один кандидат у коментарі першого рядка файлу solution.js чесно зізнався, що скопіював алгоритм.

Ми отримали анкети від 76 кандидатів та відібрали з них 23 особи. Нам надсилали анкети не лише з Мінська, а й із Москви, Санкт-Петербурга та навіть Татарстану. Дехто здивував своїми нинішніми професіями: один із них судмедексперт, а інший — студент медичного вишу.

Вийшов цікавий розподіл успішності виконання завдань. З першим завданням учасники впоралися в середньому на 60%, з другим — на 50%, а третє виявилося найскладнішим і виконали його в середньому на 40%.

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

Я пам'ятаю, як побачила своє вступне завдання у ШРІ два роки тому і подумала, що мені його ніколи не вирішити. Головне в цей момент — сісти, добре вчитатися в умови та почати робити. Виявляється, в умовах міститься майже 80% рішення. Наприклад, за умови третього завдання (найскладнішого) ми додали посилання на service workers і Notifications API на MDN. Студенти, які вивчили вміст посилань, впоралися легко.

Дуже хочеться, щоб цю статтю прочитали кандидати, які планують вступати до ШРІ надалі, не змогли вступити до мінської школи або починають виконувати будь-яке інше тестове завдання. Як бачите, вчинити цілком реально. Потрібно тільки вірити у свої сили та слухати всі підказки авторів.

Джерело: habr.com

Додати коментар або відгук