Русский
Русский
English
Статистика
Реклама

Блог компании учи.ру

Первый Pentium, Turbo Pascal и олимпиадная физика разработчики вспоминают, как учились в школе

05.10.2020 10:14:40 | Автор: admin
В День учителя мы вместе с разработчиками вспоминаем школьные годы, любимых учителей и первый компьютерный класс.

Правда ли, что успехи в математике и геометрии укорачивают путь в профессиональное программирование? А химия и физика?



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


Слева Андрей Терешко руководитель фронтенда, справа ученик 5 класса

Андрей Рынкевич, product owner МТС Big Data: В программировании много абстрактного. Любая дисциплина, которая развивает абстрактное мышление и формальную логику, поможет в его изучении.

Олег Дулецкий, ведущий backend-разработчик Ruby on Rails Учи.ру: Математика и геометрия нужны, скорее, для того, чтобы не бояться проблем, которые на первый взгляд кажутся нерешаемыми.

Иван Чернов, технический директор Ostrovok.ru: Мне физика помогла на пути профессионального программирования, потому что в старших классах я участвовал в олимпиадах по решению задач с помощью численных методов. Тогда все абстракции по алгоритмам и структурам данных наложились на реальный мир, и стало понятно, зачем уметь эффективно вычислять формулы, если они вдруг не имеют аналитического решения.
Я вижу более успешных программистов, чем я, бывших филологов и поваров. В связи с чем сейчас думаю, что STEM это хорошая база, но к ней надо иметь еще хороший кругозор и по смежным дисциплинам.


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



Сергей Пимков, заместитель генерального директора по разработке и эксплуатации продуктов Selectel: Мотивировать меня, насколько я помню, было весьма неблагодарной задачей. Работала только одна методика позволить мне конструировать свою систему знаний самостоятельно. Это очень круто наблюдать, как из разрозненных фактов и допущений выстраивается целая система, которая обладает предсказательной силой и вообще приносит профит, а не сама по себе. Если чем-то таким заниматься на уроке не получалось (например, на английском), для меня это была бездна угнетения и отчаяния. В оценки такое отношение конвертировалось тоже так себе.


Слева Сергей Пимков первоклассник, справа заместитель генерального директора по разработке и эксплуатации

Николай Толли, руководитель отдела BI Учи.ру: Сильный преподаватель всегда хорошее подспорье к изучению предмета. У меня не было особого желания изучать русский язык и литературу, но именно по этим предметам была самая сильная учительница, благодаря чему я их достаточно неплохо знаю. Профильными математикой и информатикой мне самому было интересно заниматься, и роль преподавателя была менее важна.

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

Олег Дулецкий: Мне повезло с учителями, одноклассниками и, в конечном счете, со страной. Учится было трудно, но интересно. А из-за того, что я был законченным ботаном, хилым физически, мне судьбой было написано хорошо учиться и давать списывать одноклассникам.

Расскажите об учителе, который вам запомнился.



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

Алексей Вахов, технический директор Учи.ру: Сергей Евгеньевич Полянский мой преподаватель олимпиадной физики. Яркий, харизматичный дяденька. Я впервые познакомился с ним на контрольной по физике в новой школе. В классе никто не решил ни одной задачи, а я решил половину одной это были олимпиадные задачи из польского учебника. После этого мы с Сергеем Евгеньевичем начали готовиться к олимпиаде, взяли золото на международном соревновании по физике. Он не натаскивал меня, но давал кучу литературы, в этом не было принуждения. В поездках по российским олимпиадам он был внимателен, умел организовать быт детей, мог успокоить, когда нужно было поднажать.


Слева Алексей Вахов выпускник 11 класса и победитель международной олимпиады, справа технический директор

Алексей Петров, директор по качеству СберМаркет: Наверное, самые яркие и теплые впечатления у меня остались от нашей классной руководительницы в старших классах Раисы Григорьевны Миримской. Удивительный и прекрасный педагог, она преподавала математику и геометрию, поощряла свободу мыслей, пропагандируя при этом их строгость и выверенность, как это и подобает математику. Да, она была весьма экстравагантной женщиной, например, могла неожиданно прийти в школу с фиолетовыми волосами, а дома у нее жила дюжина кошек. Но с такой страстью и упоением рассказывать о равнобедренных треугольниках, многочленах, биноме Ньютона и теореме Чевы могла только она.

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

Учителя предполагали, кем вы станете? А вы сами?



Андрей Терешко: Хорошо запомнил, как учительница математики сказала: Не будешь знать математику не станешь программистом. И после этого я совсем на математику забил. Что, конечно, сильно мешало и мешает до сих пор в некоторых моментах. Во многом пришлось потом разбираться с нуля, что гораздо сложней, чем в школе.

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

Андрей Петров, тимлид Ruby on Rails Учи.ру: И учителя, и я с 10 класса были уверены, что я пойду учиться на программиста. Я даже не рассматривал другие факультеты. Мне было удивительно, что многие понятия не имеют, что их интересует и на какую специальность им бы хотелось поступить.

Сергей Пимков: Сложно сказать, но учитывая, что я довольно много времени торчал в кабинете информатики (поближе к Turbo Pascal, ну и Doom, чего уж тут), полагаю, моя работа в сфере IT могла казаться учителям вероятным вариантом.

Алексей Петров: Учителя надеялись, что из нас получится что-то путное.


Слева Алексей Петров школьник в последний учебный день, справа директор по качеству

Был ли в вашей школе компьютерный класс? Какой Пентиум?



Алексей Петров: У нас были Pentium 133 и один-два i386.

Андрей Терешко: Программировать я начал в десять лет, первым компьютером был советский аналог ZX Spectrum Ратон-9003. Он подключался к телевизору, и программы грузились с магнитофонных кассет. Я шучу, что начал кодить, потому что это было быстрее, чем загрузить игру. И это только отчасти шутка.

Сергей Пимков: Началось все с программирования в Кенгуренке, который чертил линии на экране. Затем был Turbo Pascal: я купил книгу Фаронова и какое-то время увлеченно занимался рисованием красивых фигур. Потом информатик подарил мне эпическую подшивку древней документации по Turbo Vision, распечатанную на папиросной бумаге (или чем-то таком), явно из какого-то вычислительного центра, и я нырнул в ООП.
В классе у нас, кажется, был один или два первых Пентиума, несколько 486-х и 386-х. У меня первый компьютер появился в 10 классе, это был Celeron 233 Mhz.

Евгений Помыткин: Компов тогда было мало. Пентиум? Хе-хе. У нас был один комп на класс, что-то советское. Я старый.

Андрей Рынкевич: В школе компьютерный класс был, но занимались мы в нем совсем базовыми навыками использования ПК. Соприкоснуться с программированием получилось только в институте. До сих пор помню, как на первом занятии учитель выдал задание и все кинулись его выполнять. Я же не знал даже, как управлять курсором в MC.


Школьные фото Андрея Рынкевича

Андрей Петров: У меня в 8 классе был первый двухъядерный AMD.

Иван Чернов: Мой отец работал программистом, еще когда меня не было. Поэтому дома у нас был компьютер еще до моего рождения, а ближе к нулевым мне подарили свой, с ЖК-дисплеем и Pentium 4. Школа тоже была оборудована компьютерным классом, мы изучали программирование с помощью черепашки Logo. В какой-то момент школе подарили свитч, и на переменках стали собираться турниры по Doom 2.

Алексей Вахов: У нас школа сильная была, было много компьютерных классов. Это был 97 год. Pentium, наверное, был MMX 133.

Олег Дулецкий: В школе не было ни класса, ни Пентиумов до их появления оставалось 20 лет. Тогда только появлялись программируемые калькуляторы. Типа МК-61. Такой отец приносил с работы, вот его запомнил.

Артем Мезин: В школе я фанател от всего, связанного с компьютерами. Фильм Хакеры и роман Нейромант просто библия школьных лет! Мой первый компьютер персоналка с процессором Intel 80286 (это еще не Pentium, но уже близко). В более-менее сознательном возрасте были разные машины от P1 MMX 166Mhz (а тогда весь PC характеризовали процессором для упрощения) до AMD Athlon 800.

Николай Толли: В школе был компьютерный класс, вроде, там были Pentium 4.


Слева Николай Толли на выпускном, справа руководитель отдела BI

Александр Цветков: В школе был новенький компьютерный класс, обустроенный по какой-то государственной программе. Помню, как я наткнулся в интернете на официальный сайт ОС Ubuntu и на нем был баннер, сообщающий, что можно бесплатно заказать диск с этой операционной системой, что я незамедлительно и сделал, не особо веря в результат. Каково было мое удивление, когда через месяц в почтовом ящике был диск! Настоящий! В тот день астрологи объявили месяц бессонных ночей и красных глаз.

Как бы вы вели информатику, если бы оказались у доски? А если окажетесь ровно на один урок, что расскажете школьникам?



Олег Дулецкий: Программирование это предмет не для доски. И за один урок ничего собственно о разработке, конечно, не рассказать. Но вот о ее значении можно.

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

Артем Мезин: У меня есть некоторый опыт преподавания. Важнее всего просто говорить с учениками на равных. По-настоящему хотеть понять, что интересно им, и этим и заниматься. Будет интересно напилить TikTok напилим, будет интересно сломать школьный Wi-Fi сломаем!


Артем Мезин слева ученик старших классов, справа технический менеджер по продукту

Алексей Петров: Уверен, что чем больше у учащихся будет доступа к воплощению своих идей, тем более интересным будет урок и тем более вовлеченными в занятие будут школьники. Например, я обучаю старшего сына азам программирования на Scratch, программирую с дочерью робота из Lego. Мы не просто учим циклы, переменные, условные операторы и функции, а тут же закрепляем эту информацию в реальном проекте: учим игрового персонажа бросать мяч по нажатию на кнопку или робота ездить по необходимому маршруту.

Евгений Помыткин: Ландау как-то сказал: Физику наших дней не обязательно знать физику, ему достаточно знать математику. Что-то подобное можно сказать про программирование. Здесь есть две важные величины: логика и неподдельный интерес к изучению и изменению мира. Имея оба инструмента, вы сможете легко освоить программирование. Именно это я бы и показал школьникам.

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

О школе говорили:

  • Алексей Вахов, технический директор Учи.ру;
  • Сергей Пимков, заместитель генерального директора по разработке и эксплуатации продуктов Selectel;
  • Андрей Терешко, руководитель фронтенда Учи.ру;
  • Алексей Петров, директор по качеству СберМаркет;
  • Николай Толли, руководитель отдела BI Учи.ру;
  • Иван Чернов, технический директор Ostrovok.ru;
  • Евгений Помыткин, руководитель отдела мобильной разработки Учи.ру;
  • Александр Цветков, руководитель фронтенда проекта Почта Mail.ru;
  • Андрей Петров, тимлид Ruby on Rails Учи.ру;
  • Андрей Рынкевич, product owner МТС Big Data;
  • Олег Дулецкий, ведущий backend-разработчик Ruby on Rails Учи.ру;
  • Артем Мезин, технический менеджер по продукту Behavox.
Подробнее..

Как ускорить аутентификацию и снизить потребление памяти в 5 раз? Наймите дворецкого

07.05.2021 12:20:51 | Автор: admin

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

Меня зовут Роман Литвинов, я разработчик в команде Учи.ру. Хочу вам рассказать именно о такой истории из практики и о нашем сервисе под названием Butler, о дворецком, через которого проходит каждый пользователь, прежде чем зайти на платформу.

Итак, овсянка, сэр.

По мере роста популярности платформы система аутентификации перестала соответствовать нашим требованиям, как и некоторые другие части нашей архитектуры. Когда весной 2020 года в базе Учи.ру стало больше 11 млн активных пользователей (8 млн учеников, примерно 350 тыс. учителей и около 3,5 млн родителей), существующая реализация стала медленной, непрозрачной и потребляла слишком много памяти. Мы решили ее обновить.

Поставили перед собой следующие цели:

  • повысить производительность;

  • внедрить новые технологии защиты учетных данных;

  • выделить аутентификацию из монолита в микросервис;

  • подключить мобильное приложение.

При этом хотелось иметь возможность поддерживать функции, которые до этого не реализовывались.

В список новых функций попали:

  • принудительное отключение пользователя;

  • блокировка аккаунта;

  • верификация;

  • шифрование паролей учеников;

  • поддержка jwt-токенов и двухфакторной аутентификации;

  • интеграция с социальными сетями;

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

Сложности работы с таблицами. Роли пользователей

Долгая аутентификация

На Учи.ру заходят разные пользователи: ученики, их родители, учителя (в числе которых есть воспитатели или завучи), а также админы. Изначально для каждой из этих категорий пользователей была сформирована отдельная таблица. Поскольку форма аутентификации была единой, каждый раз поиск пользователя проходил по всем таблицам. Но когда пользователей стало почти в полтора раза больше, это стало занимать ощутимое время, до 23 секунд.

Проблема уникальности почты и логина

Если родитель одновременно является учителем и хочет зарегистрироваться на Учи.ру, он должен завести две учетные записи. Это значит, что его e-mail будет числиться в двух разных таблицах. Та же история может происходить, если один человек является и сотрудником, и родителем или и сотрудником, и учителем и т. д. Если e-mail один, то сложно определить, какого именно пользователя нужно аутентифицировать.

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

Теперь мы используем Butler

Чтобы исправить ситуацию, мы решили вынести аутентификацию в отдельный сервис. Для этого был создан Butler. Саму аутентификацию было решено проводить на базе открытой библиотеки Ruby под названием rodauth. Ее, конечно, пришлось немного доработать, но в целом решение подходило. Параллельно с улучшением своего продукта мы внесли небольшой вклад в развитие open source-сообщества.

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

Всех пользователей перенесли из нескольких таблиц в единую базу данных. Принадлежность к разным таблицам в прошлом позволила определить роли и записать их в отдельный столбец.

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

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

Небольшой тюнинг решения

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

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

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

Обновление камень преткновения

Обновлять исходный код open-source компонента нужно аккуратно, потому что в открытых проектах вопросы обратной совместимости не всегда оказываются решены полностью. Так, нам нужно было установить обновление, которое требовалось для внедрения очередной фичи. Но с этим обновлением возникал обязательный параметр связи между access-токеном и refresh-токеном. Раньше он был необязательным и от нашего внимания ускользнул. Это значит, что все выданные токены перестали бы работать разом, если бы мы накатили это обновление. То есть, если бы мы сразу обновили всю систему, это привело бы к сбросу всех активных сессий.

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

Криптография и защита от брутинга

Хранить логины и пароли в новой базе данных было решено в зашифрованном виде. Тогда дополнительным тормозом стал один из наиболее используемых алгоритмов в экосистеме Ruby BCrypt.

Его реализация на Ruby отнимала слишком много процессорного времени, затрачивая 250 мс на создание хеша со стандартным костом, равным 12. Зачастую подобную операцию необходимо проводить дважды в течение цикла вопрос-ответ, поскольку требуется проверка на использование этого же пароля пользователем прежде. Вкупе со множественным использованием колбеков в монолите ситуация стала приводить к большому времени ожидания внутри транзакций БД (idle in transaction), что начало сказываться на производительности системы. На этих самых колбеках висело слишком много бизнес-логики, что не позволило свести проблему к простому рефакторингу.

Выходом из положения стала смена алгоритма шифрования на более гибкий, который поддерживает конфигурацию как по затрачиваемой памяти, так и временному ресурсу. Мы взяли открытый алгоритм Argon2 и постепенно мигрировали пользователей с одного на второй, благо в rodauth имелись зачатки функционала для осуществления плавного перехода. Для этого потребовалось внести изменения в саму библиотеку rodauth. К счастью, Jeremy Evans ее автор оказался очень открытым человеком, пошел нам навстречу.

В сервисе rodauth также нашлось встроенное решение по защите от брутинга паролей. После определенного количества попыток аккаунт блокируется на некоторое время. Разблокировку можно провести за счет подтверждения через e-mail или вручную.

Перенос аккаунтов

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

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

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

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

Результаты

В итоге нам удалось оторвать от монолита кусочек, снизив его требования к производительности, и запустить современный сервис аутентификации. Разработчикам теперь стало немного сложнее: они не могут просто загрузить себе копию монолита и проверять свои гипотезы. Теперь вместе с монолитом нужно запускать Butler, чтобы хотя бы первый раз пройти аутентификацию. Но я уверен, что все мы к этому легко привыкнем.

Главный плюс же в том, что мы получили внимательного дворецкого: полноценный быстрый и безопасный сервис аутентификации с единой точкой входа. При этом он так же работает на базе Ruby, как и основная часть системы Учи.ру. Теперь процессы аутентификации происходят быстрее в десятки раз, а памяти нужно на это примерно в 5 раз меньше, чем раньше.

Подробнее..

Как мы построили Computer Vision из подручных материалов, чтобы сделать гифки

17.06.2021 14:15:17 | Автор: admin

Меня зовут Денис Власов, я Data Scientist в Учи.ру. С помощью моделей машинного обучения из записей онлайн-уроков мы сделали гифки последовательность из нескольких кадров с наиболее яркими эмоциями учеников. Эти гифки получили их родители в e-mail-рассылке. Вместе с Data Scientist @DariaV Дашей Васюковой расскажем, как без экспертизы в Computer Vision, а только с помощью открытых библиотек и готовых моделей сделать MVP, в основе которого лежат low-res видео. В конце бонус виджет для быстрой разметки кадров.

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

Если у вас, как и у нас, не стоит задача RealTime определения эмоций, можно пойти простым способом: анализировать записи уроков.

Маркеры начала и конца урока

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

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

Разбили видео на кадры

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

Научились детектировать детские улыбки (и не только)

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

Проблема 1. Распознавать лица на картинках низкого качества сложнее

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

Стандартный детектор DNN Face Detector из библиотеки OpenCV, который мы сначала взяли за основу, на наших данных давал неточные результаты. Оказалось, что алгоритм недостаточно хорошо справляется с реальными кадрами из видеочатов: иногда пропускает лица, которые явно есть в кадре, из двух лиц находил только одно или определял лица там, где их нет.

Стандартный детектор DNN Face Detector мог определить как лицо узор на занавеске, игрушечного медведя или даже композицию из картин на стене и стулаСтандартный детектор DNN Face Detector мог определить как лицо узор на занавеске, игрушечного медведя или даже композицию из картин на стене и стула

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

Размечали итеративно: после добавления новой порции размеченных кадров мы заново обучали модель. А после проверки ее работы сохраняли разметку для новых кадров, наращивая обучающую выборку. Всего мы разметили 2624 кадра из 388 видеозаписей, на которых в сумме было 3325 лиц.

Таким образом удалось обучить более чувствительный в наших условиях детектор. В валидационной выборке из 140 кадров старый детектор нашел 150 лиц, а пропустил 38. Новый же пропустил только 5, а 183 обнаружил верно.

Проблема 2. В кадре присутствует не только ребенок

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

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

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

  • возраст людей на кадре с низким разрешением становится неочевидным;

  • дети присутствуют в кадре практически весь урок, а взрослые минуты.

В процессе разметки мы заметили, что очень часто родитель присутствует на уроке плечом или локтем. Так мы назвали тип кадров, когда камера направлена на ученика, но видно, что рядом сидит родитель. Обычно на таких уроках видно плечо сидящего рядом взрослого или только локоть.

На всех трех кадрах родитель присутствует, но по отдельному кадру найти его бывает непростоНа всех трех кадрах родитель присутствует, но по отдельному кадру найти его бывает непросто

Вторая модель должна была находить именно такие родительские плечи. Очевидно, что в этой задаче детектор лиц не применим, поэтому надо обучаться на кадрах целиком. Конечно, таких датасетов мы не нашли в публичном доступе и разметили около 250 000 кадров, на которых есть часть родителя, и кадры без них. Разметки на порядок больше, чем в других задачах, потому что размечать гораздо легче: можно смотреть не отдельные кадры, а отрезки видео и в несколько кликов отмечать, например, что вот эти 15 минут (900 кадров!) родитель присутствовал.

На дашборде урока с аналитикой доступны графики присутствия родителями по мнению обеих моделей. Они помогают понять, когда родитель просто интересуется процессом урока, а когда скорее общается с преподавателем.

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

Проблема 3. Дети улыбаются по-разному

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

За основу классификатора настроения мы взяли предобученную модель ResNet34 из библиотеки fast.ai. Эту же библиотеку использовали для дообучения модели в два этапа: сначала на публичных датасетах facial_expressions и SMILEsmileD с веселыми и нейтральными лицами, потом на нашем размеченном вручную датасете с кадрами с камер учеников. Публичные датасеты решили включить, чтобы расширить размер выборки и помочь модели более качественными изображениями, чем кадры видео с планшетов и веб-камер наших учеников.

Размечали с помощью кастомного виджета. Все изображения подвергались одной и той же процедуре предобработки:

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

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

  3. Аугментация. Позволяет в разы увеличить эффективный размер выборки и учесть особенности данных.

  4. Нормализация цветов с помощью CLAHE normalizer из библиотеки OpenCV. По ощущениям, такая нормализация лучше других вытягивает контраст на пересвеченных или темных изображениях.

Дообучаем модель для распознавания улыбок

1. Аугментации

При дообучении мы использовали достаточно жесткие аугментации:

  • Отражали изображение по горизонтали.

  • Поворачивали на случайную величину.

  • Применяли три разных искажения для изменения контраста и яркости.

  • Брали не всю картинку, а квадрат, составляющий не менее 60% от площади исходного изображения.

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

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

Пример аугментаций на одном изображении. Для наглядности аугментации сделаны до масштабирования к разрешению 64х64Пример аугментаций на одном изображении. Для наглядности аугментации сделаны до масштабирования к разрешению 64х64Код для аугментаций
# ! pip freeze | grep fastai# fastai==1.0.44import fastaiimport matplotlib.pyplot as pltfrom matplotlib import cmfrom matplotlib import colorsimport seaborn as sns%matplotlib inlinefrom pylab import rcParamsplt.style.use('seaborn-talk')rcParams['figure.figsize'] = 12, 6path = 'facial_expressions/images/'def _side_cutoff(    x,    cutoff_prob=0.25,    cutoff_intensity=(0.1, 0.25)):    if np.random.uniform() > cutoff_prob:        return x    # height and width    h, w = x.shape[1:]    h_cutoff = np.random.randint(        int(cutoff_intensity[0]*h), int(cutoff_intensity[1]*h)    )    w_cutoff = np.random.randint(        int(cutoff_intensity[0]*w), int(cutoff_intensity[1]*w)    )        cutoff_side = np.random.choice(        range(4),        p=[.34, .34, .16, .16]    ) # top, bottom, left, right.    if cutoff_side == 0:        x[:, :h_cutoff, :] = 0    elif cutoff_side == 1:        x[:, h-h_cutoff:, :] = 0    elif cutoff_side == 2:        x[:, :, :w_cutoff] = 0    elif cutoff_side == 3:        x[:, :, w-w_cutoff:] = 0    return x# side cutoff goes frist.side_cutoff = fastai.vision.TfmPixel(_side_cutoff, order=99)augmentations = fastai.vision.get_transforms(    do_flip=True,    flip_vert=False,    max_rotate=25.0,    max_zoom=1.25,    max_lighting=0.5,    max_warp=0.0,    p_affine=0.5,    p_lighting=0.5,        xtra_tfms = [side_cutoff()])def get_example():    return fastai.vision.open_image(        path+'George_W_Bush_0016.jpg',    )def plots_f(rows, cols, width, height, **kwargs):    [        get_example()        .apply_tfms(            augmentations[0], **kwargs        ).show(ax=ax)        for i,ax in enumerate(            plt.subplots(                rows,                cols,                figsize=(width,height)            )[1].flatten())    ]plots_f(3, 5, 15, 9, size=size)

2. Нормализация цвета

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

Пример нормализации цвета на изображениях из публичного датасетаПример нормализации цвета на изображениях из публичного датасетаКод для нормализации цвета
# pip freeze | grep opencv# > opencv-python==4.5.2.52import cv2import matplotlib.pyplot as pltfrom matplotlib import cmfrom matplotlib import colorsimport seaborn as sns%matplotlib inlinefrom pylab import rcParamsplt.style.use('seaborn-talk')rcParams['figure.figsize'] = 12, 6path = 'facial_expressions/images/'imgs = [    'Guillermo_Coria_0021.jpg',    'Roger_Federer_0012.jpg',]imgs = list(    map(        lambda x: path+x, imgs    ))clahe = cv2.createCLAHE(    clipLimit=2.0,    tileGridSize=(4, 4))rows_cnt = len(imgs)cols_cnt = 4imsize = 3fig, ax = plt.subplots(    rows_cnt, cols_cnt,    figsize=(cols_cnt*imsize, rows_cnt*imsize))for row_num, f in enumerate(imgs):    img = cv2.imread(f)    col_num = 0        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    ax[row_num, col_num].imshow(img, cmap='gray')    ax[row_num, col_num].set_title('bw', fontsize=14)    col_num += 1    img_normed = cv2.normalize(        img,        None,        alpha=0,        beta=1,        norm_type=cv2.NORM_MINMAX,        dtype=cv2.CV_32F    )    ax[row_num, col_num].imshow(img_normed, cmap='gray')    ax[row_num, col_num].set_title('bw normalize', fontsize=14)    col_num += 1        img_hist_normed = cv2.equalizeHist(img)    ax[row_num, col_num].imshow(img_hist_normed, cmap='gray')    ax[row_num, col_num].set_title('bw equalizeHist', fontsize=14)    col_num += 1        img_clahe = clahe.apply(img)    ax[row_num, col_num].imshow(img_clahe, cmap='gray')    ax[row_num, col_num].set_title('bw clahe_norm', fontsize=14)    col_num += 1        for col in ax[row_num]:        col.set_xticks([])        col.set_yticks([])plt.show()

В итоге мы получили модель, способную отличить улыбку от нейтрального выражения лица в с качеством 0.93 по метрике ROC AUC. Иными словами, если взять из выборки по случайному кадру с улыбкой и без, то с вероятностью 93% модель присвоит большую вероятность улыбки кадру с улыбающимся лицом. Этот показатель мы использовали для сравнения разных вариантов дообучения и пайплайнов. Но интуитивно кажется, что это достаточно высокий уровень точности: даже человек не всегда может определить эмоцию на лице другого человека. К тому же в реальности существует гораздо больше выражений лиц кроме однозначной радости и однозначной печали.

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

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

3. Увеличение объема выборки

На этом этапе у нас было около 5400 размеченных кадров, нам хотелось понять: достаточно ли такого объема для обучения. Мы разделили кадры на две подвыборки: половина для оценки качества (валидация), другая для обучения (трейн). Каждая группа состояла из кадров с разными учениками: если бы одни и те же лица попали в разные выборки, результаты оценки качества были бы завышены.

Мы несколько раз дообучили модель на публичных датасетах и подвыборках разного размера из трейна и проверили качество на валидационной выборке. На графике видно, что качество растет по мере увеличения объема подвыборки, поэтому мы разметили дополнительно еще 3 тыс. кадров: финальную модель обучали на выборке из 8500 кадров. Скорее всего и при таком объеме данных качество еще не начало выходить на плато, но перепроверять это мы не стали.

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

Качество на отложенной выборке растет по мере увеличения выборки для дообученияКачество на отложенной выборке растет по мере увеличения выборки для дообучения

4. Картинки Google для обогащения выборки

Мы пробовали спарсить первые 1000 результатов картинок по запросам в духе happy, unhappy, smiling, neutral и т. д. Не ожидали получить данные высокого качества, поэтому планировали потом просмотреть их глазами и удалить совсем неподходящие. В итоге мы быстро поняли, что никакая фильтрация эти картинки не спасет, поэтому отказались от этой идеи совсем.

Примеры изображений по запросам happy и unhappyПримеры изображений по запросам happy и unhappy

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

  • есть ли в кадре лицо;

  • с какой вероятностью этот человек улыбается;

  • ребенок это или взрослый;

  • есть ли в кадре взрослый, даже если мы не нашли лица.

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

Собрали гифку

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

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

Примеры итоговых GIF с улыбками нашей коллеги и ее детейПримеры итоговых GIF с улыбками нашей коллеги и ее детей

Что мы в итоге получили?

Исследование и эксперимент показали, что можно быстро и без глубокой экспертизы в Computer Vision научиться различать пользователей и их эмоции по видео (даже если оно плохого качества) на основе открытых библиотек и моделей.

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

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

Статистика дисконнектов. В этом уроке был единственный дисконнект на стороне ученикаСтатистика дисконнектов. В этом уроке был единственный дисконнект на стороне ученика

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

Виджеты

Все данные мы размечали сами и делали это довольно быстро (примерно 100 кадров в минуту). В этом нам помогали самописные виджеты:

  1. Виджет для разметки кадров с улыбками.

  2. Виджет для разметки кадров с детьми и взрослыми.

  3. Виджет для разметки кадров с плечом или локтем родителя.

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

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

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

Видео работы виджета

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

Код виджета
import pandas as pdimport numpy as npimport datetimeimport randomimport osimport ipywidgets as widgetsfrom IPython.display import displayfrom pathlib import Pathclass BulkLabeler():    def __init__(self, frames_path, annotations_path,                 labels = ['0', '1'],                 predict_fn = None,                 frame_width=120,                 num_frames = 27,                 face_width = 120,                 num_faces = 27,                 myname = '?',                 ):        self.predict_fn = predict_fn        self.labels = labels        self.frames_path = frames_path        self.frame_width = frame_width        self.num_frames = num_frames        self.face_width = face_width        self.num_faces = num_faces        self.myname = myname        self.faces_batch = []                # get annotations        self.annotations_path = annotations_path        processed_videos = []        if annotations_path.exists():            annotations = pd.read_csv(annotations_path)            processed_videos = annotations.file.str.split('/').str[-3].unique()        else:            with open(self.annotations_path, 'w') as f:                f.write('file,label,by,created_at\n')                # get list of videos        self.video_ids = [x for x in os.listdir(frames_path)                           if x not in processed_videos]        random.shuffle(self.video_ids)        self.video_ind = -1                self._make_video_widgets_row()        self._make_frames_row()        self._make_range_slider()        self._make_buttons_row()        self._make_faces_row()        self._make_video_stats_row()                display(widgets.VBox([self.w_video_row,                              self.w_frames_row,                              self.w_slider_row,                              self.w_buttons_row,                              self.w_faces_row,                              self.w_faces_label,                              self.w_video_stats]))        self._on_next_video_click(0)            ### Video name and next video button        def _make_video_widgets_row(self):        # widgets for current video name and "Next video" button        self.w_current_video = widgets.Text(            value='',            description='Current video:',            disabled=False,            layout = widgets.Layout(width='500px')            )                self.w_next_video_button = widgets.Button(            description='Next video',            button_style='info', # 'success', 'info', 'warning', 'danger' or ''            tooltip='Go to the next video',            icon='right-arrow'        )                self.w_video_row = widgets.HBox([self.w_current_video, self.w_next_video_button])                self.w_current_video.observe(self._on_video_change, names='value')        self.w_next_video_button.on_click(self._on_next_video_click)                        def _on_next_video_click(self, _):        while True:            self.video_ind += 1            current_video = self.video_ids[self.video_ind]            if next(os.scandir(self.frames_path/current_video/'student_faces'), None) is not None:                break        self.w_current_video.value = current_video                    def _on_video_change(self, change):        self.video_id = change['new']        self.frame_nums_all = sorted(int(f.replace('.jpg',''))                                      for f in os.listdir(self.frames_path/self.video_id/'student_src'))        start, stop = min(self.frame_nums_all), max(self.frame_nums_all)        self.w_range_slider.min = start        self.w_range_slider.max = stop        step = self.frame_nums_all[1] - self.frame_nums_all[0] if len(self.frame_nums_all)>1 else 1        self.w_range_start.step = step        self.w_range_stop.step = step        # change to slider value will cause frames to be redrawn        self.w_range_slider.value = [start, stop]               # reset faces        self.faces_df = None        self._reset_faces_row()        self.w_video_stats.value = f'Video {self.video_id}  no annotations yet.'                def _close_video_widgets_row(self):        self.w_current_video.close()        self.w_next_video_button.close()        self.w_video_row.close()        ### Video frames box        def _make_frames_row(self):        frame_boxes = []        self.w_back_buttons = {}        self.w_forward_buttons = {}        for i in range(self.num_frames):            back_button = widgets.Button(description='<',layout=widgets.Layout(width='20px',height='20px'))            self.w_back_buttons[back_button] = i            back_button.on_click(self._on_frames_back_click)            label = widgets.Label(str(i+1), layout = widgets.Layout(width=f'{self.frame_width-50}px'))            forward_button = widgets.Button(description='>',layout=widgets.Layout(width='20px',height='20px'))            self.w_forward_buttons[forward_button] = i            forward_button.on_click(self._on_frames_forward_click)            image = widgets.Image(width=f'{self.frame_width}px')            frame_boxes.append(widgets.VBox([widgets.HBox([back_button, label, forward_button]),                                              image]))                    self.w_frames_row = widgets.GridBox(frame_boxes,                                             layout = widgets.Layout(width='100%',                                                                     display='flex',                                                                     flex_flow='row wrap'))            def _on_frames_back_click(self, button):        frame_ind = self.w_back_buttons[button]        frame = int(self.w_frames_row.children[frame_ind].children[0].children[1].value)        start, stop = self.w_range_slider.value        self.w_range_slider.value = [frame, stop]            def _on_frames_forward_click(self, button):        frame_ind = self.w_forward_buttons[button]        frame = int(self.w_frames_row.children[frame_ind].children[0].children[1].value)        start, stop = self.w_range_slider.value        self.w_range_slider.value = [start, frame]            def _close_frames_row(self):        for box in self.w_frames_row.children:            label_row, image = box.children            back, label, forward = label_row.children            image.close()            back.close()            label.close()            forward.close()            box.close()        self.w_frames_row.close()                    ### Frames range slider                        def _make_range_slider(self):        self.w_range_start = widgets.BoundedIntText(                                        value=0,                                        min=0,                                        max=30000,                                        step=1,                                        description='Frames from:',                                        disabled=False,                                        layout = widgets.Layout(width='240px')                                    )        self.w_range_stop = widgets.BoundedIntText(                                        value=30000,                                        min=0,                                        max=30000,                                        step=1,                                        description='to:',                                        disabled=False,                                        layout = widgets.Layout(width='240px')                                    )        self.w_range_slider = widgets.IntRangeSlider(            value=[0, 30000],            min=0,            max=30000,            step=1,            description='',            disabled=False,            continuous_update=False,            orientation='horizontal',            readout=True,            readout_format='d',            layout=widgets.Layout(width='500px')        )        self.w_range_flip = widgets.Button(description='Flip range',            button_style='', # 'success', 'info', 'warning', 'danger' or ''            tooltip='Invert frames selection',            layout = widgets.Layout(width=f'{self.frame_width}px'),            icon='retweet'                                          )                self.w_range_slider.observe(self._on_slider_change, names='value')        self.w_range_start.observe(self._on_range_start_change, names='value')        self.w_range_stop.observe(self._on_range_stop_change, names='value')        self.w_range_flip.on_click(self._on_range_flip)        self.w_slider_row = widgets.HBox([self.w_range_start,                                          self.w_range_slider,                                          self.w_range_stop,                                          self.w_range_flip])        def _close_range_slider(self):        self.w_range_start.close()        self.w_range_stop.close()        self.w_range_slider.close()        self.w_range_flip.close()        self.w_slider_row.close()            def _on_range_flip(self, _):        start, stop = self.w_range_slider.value        left, right = self.w_range_slider.min, self.w_range_slider.max        if start==left and right==stop:            pass        elif start - left > right - stop:            self.w_range_slider.value=[left, start]        else:            self.w_range_slider.value=[stop, right]                                                   def _on_range_start_change(self, change):        new_start = change['new']        start, stop = self.w_range_slider.value        self.w_range_slider.value = [new_start, stop]                    def _on_range_stop_change(self, change):        new_stop = change['new']        start, stop = self.w_range_slider.value        self.w_range_slider.value = [start, new_stop]                    def _on_slider_change(self, change):        start, stop = change['new']        # update text controls        self.w_range_start.max = stop        self.w_range_start.value = start        self.w_range_stop.min = start        self.w_range_stop.max = self.w_range_slider.max        self.w_range_stop.value = stop        # show frames that fit current selection        frame_nums = [i for i in self.frame_nums_all if i>=start and i<=stop]        N = len(frame_nums)        n = self.num_frames        inds = [int(((N-1)/(n-1))*i) for i in range(n)]        # load new images into image widgets        for ind, box in zip(inds, self.w_frames_row.children):            frame_num = frame_nums[ind]            filename = self.frames_path/self.video_id/'student_src'/f'{frame_num}.jpg'            with open(filename, "rb") as image:                f = image.read()            label, image = box.children            label.children[1].value = str(frame_num)            image.value = f            ### Buttons row        def _make_buttons_row(self):        labels = list(self.labels)        if self.predict_fn is not None:            labels.append('model')        self.w_default_label = widgets.ToggleButtons(options=labels,                                                      value=self.labels[0],                                                      description='Default label:')                self.w_next_batch_button = widgets.Button(description='New batch',            button_style='info', # 'success', 'info', 'warning', 'danger' or ''            tooltip='Show next batch of faces from current frame range',            icon='arrow-right'        )        self.w_save_button = widgets.Button(description='Save labels',            button_style='success', # 'success', 'info', 'warning', 'danger' or ''            tooltip='Save current labels',            icon='check'        )        self.w_buttons_row = widgets.HBox([self.w_default_label, self.w_next_batch_button, self.w_save_button])        self.w_next_batch_button.on_click(self._on_next_batch_click)        self.w_save_button.on_click(self._on_save_labels_click)                def _close_buttons_row(self):        self.w_default_label.close()        self.w_next_batch_button.close()        self.w_save_button.close()        self.w_buttons_row.close()                def _on_next_batch_click(self, _):        if self.faces_df is None:             self._create_faces_df()        # select a sample from faces_df        start, stop = self.w_range_slider.value        subdf = self.faces_df.loc[lambda df: df.frame_num.ge(start)&                                             df.frame_num.le(stop)&                                             df.label.eq('')]        num_faces = min(len(subdf), self.num_faces)                if num_faces == 0:            self.faces_batch = []            self.w_faces_label.value = 'No more unlabeled images in this frames range'            self.w_faces_label.layout.visibility = 'visible'            for box in self.w_faces_row.children:                box.layout.visibility = 'hidden'        else:            self.w_faces_label.layout.visibility = 'hidden'            self.faces_batch = subdf.sample(num_faces).index            # if we have a model then we use it to sort images            if self.predict_fn is not None:                probs, labels = self._predict()                # sort faces according to probability                ind = sorted(range(len(probs)), key=probs.__getitem__)                self.faces_batch = [self.faces_batch[i] for i in ind]                labels = [labels[i] for i in ind]            # create labels for each face            if self.w_default_label.value != 'model':                labels = [self.w_default_label.value]*len(self.faces_batch)            # update faces UI            for facefile, label, box in zip(self.faces_batch, labels, self.w_faces_row.children):                image, buttons = box.children                with open(self.frames_path/facefile, "rb") as im:                    image.value = im.read()                buttons.value = label                box.layout.visibility = 'visible'            if len(self.faces_batch) < len(self.w_faces_row.children):                for box in self.w_faces_row.children[len(self.faces_batch):]:                    box.layout.visibility = 'hidden'        def _predict(self):        probs = []        labels = []        for facefile in self.faces_batch:            prob, label = self.predict_fn(self.frames_path/facefile)            probs.append(prob)            labels.append(label)        self.faces_df.loc[self.faces_batch, 'prob'] = probs        return probs, labels                    def _on_save_labels_click(self, _):        self.w_save_button.description='Saving...'                        with open(self.annotations_path, 'a') as f:            for file, box in zip(self.faces_batch, self.w_faces_row.children):                label = box.children[1].value                self.faces_df.at[file,'label'] = label                print(file, label, self.myname, str(datetime.datetime.now()),sep=',', file=f)                # update current video statistics        stats = self.faces_df.loc[self.faces_df.label.ne(''),'label'].value_counts().sort_index()        stats_str = ', '.join(f'{label}: {count}' for label, count in stats.items())        self.w_video_stats.value = f'Video {self.video_id}  {stats_str}.'                self.w_save_button.description = 'Save labels'        # ask for next batch        self._on_next_batch_click(0)            ### Faces row        def _make_faces_row(self):        face_boxes = []        for i in range(self.num_faces):            image = widgets.Image(width=f'{self.face_width}px')            n = len(self.labels)            toggle_buttons_width = int(((self.face_width-5*(n-1))/n))            toggle_buttons = widgets.ToggleButtons(options=self.labels,                                                    value=self.w_default_label.value,                                                    style=widgets.ToggleButtonsStyle(button_width=f'{toggle_buttons_width}px'))            face_boxes.append(widgets.VBox([image, toggle_buttons]))                    self.w_faces_row = widgets.GridBox(face_boxes,                                            layout = widgets.Layout(width='100%',                                                                    display='flex',                                                                    flex_flow='row wrap'))        self.w_faces_label = widgets.Label()        self._reset_faces_row()            def _close_faces_row(self):        for box in self.w_faces_row.children:            image, buttons = box.children            for w in [image, buttons, box]:                w.close()        self.w_faces_row.close()        self.w_faces_label.close()            def _reset_faces_row(self):        for box in self.w_faces_row.children:            box.layout.visibility = 'hidden'        self.w_faces_label.layout.visibility = 'visible'        self.w_faces_label.value = 'Press "New batch" button to see a new batch of faces'        self.faces_batch = []            ### Video statistics row        def _make_video_stats_row(self):        self.w_video_stats = widgets.Label('No video currently selected')        def _close_video_stats_row(self):        self.w_video_stats.close()                def _create_faces_df(self):        folder = Path(self.video_id,'student_faces')        df = pd.DataFrame({'file':[folder/f for f in os.listdir(self.frames_path/folder)]})        df['frame_num'] = df.file.apply(lambda x: int(x.stem.split('_')[0]))        df['label'] = '' #TODO maybe existing annotations?        df['prob'] = np.nan        df = df.sort_values(by='frame_num').set_index('file')        self.faces_df = df                    def close(self):        self._close_video_widgets_row()        self._close_frames_row()        self._close_range_slider()        self._close_buttons_row()        self._close_faces_row()        self._close_video_stats_row()
Подробнее..

Музыка фоном помогают ли сконцентрироваться Моцарт, белый шум и тяжелый рок?

11.01.2021 12:12:41 | Автор: admin

За время пандемии работы у разработчиков Учи.ру только прибавилось: по данным SimilarWeb за апрель, платформа стала вторым по популярности образовательным сайтом в мире. А вот сконцентрироваться на ней из дома получается с переменным успехом. Мы проверили на себе самые разные лайфхаки и хотим поделиться результатами. Сегодня разбираемся с одним из самых многообещающих способов музыкой.

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

При опросе коллег мнения разделились: примерно по 40% из них для лучшей концентрации выбирают тишину и любимую музыку. Еще у 15% есть специальные плейлисты или приложения именно на тот случай, когда необходима максимальная сфокусированность. Еще 4% и 3% соответственно слушают белый шум и звуки природы.

Интерес к влиянию музыки на концентрацию породил огромное количество исследований, мифов и коммерческих проектов. Миллионы людей ищут способ борьбы с прокрастинацией в аудио. Одно лишь приложение Endel, которое обещает генерировать звуки для концентрации внимания пользователя, скачали в общей сложности более 2 млн раз. А YouTube-канал ChilledCow с самыми популярными стримами лоу-фай хип-хопа насчитывает уже больше 7 млн подписчиков.

Главный миф музыкальной терапии

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

Судя по всему, это мнение породило исследование, опубликованное в журнале Nature, в котором ученые анализировали влияние музыки разного темпа и тональности на состояние обучающихся. Проблема в том, что участникам эксперимента давали слушать одну и ту же сонату Моцарта в более быстром или более медленном темпе, в миноре или мажоре. Результаты показали, что быстрая и жизнерадостная музыка лучше способствует решению пространственных задач. Ну а выбор был: Моцарт или Моцарт. Так что победил Моцарт. Возможно, музыка великого композитора действительно позитивно влияет на состояние и помогает настроиться, однако метаанализ с говорящим названием Эффект Моцарта эффект Шмоцарта полностью опровергает красивую теорию. Скорее всего, это просто влияние позитивной мажорной музыки. Например, к таким выводам пришли организаторы исследования 2017 года.

Приятный джаз или тяжелый рок?

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

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

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

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

Шум: проблема или решение

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

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

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

Громкий продолжительный шум наносит вред организму этот факт давно изучен и подтвержден опытами. Длительное воздействие шума негативно воздействует на вегетативную и центральную нервные системы: ухудшает психическое состояние и повышает тревожность. С громким шумом на фоне мы устаем быстрее на 1525%, чем обычно. По данным Роспотребнадзора, уровень шума не должен превышать 68 дБ. Для сравнения: в жилых домах мы слышим примерно 40 дБ, в офисах, в которые вернемся нескоро, 5565 дБ. Поэтому так тяжело работать удаленно родителям младенцев: плач ребенка звучит на уровне 7682 дБ.

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

Что слушать

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

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

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

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

My Noise еще одно аудиокафе. Система позволяет смешать звуки прямо в браузере, в отличие от Coffitivity, здесь все делается прямо на первой странице сервиса, без загрузок и регистраций.

Brain.fm создатели приложения заявляют об искусственном интеллекте, который генерирует музыку для концентрации внимания, сна и других приятных дел. Обещают, что эффект будет длиться 15 минут после прослушивания. Много это или мало, каждый решает сам.

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

A Soft Murmur еще одна система для индивидуального смешивания фоновых звуков. Можно настроить уменьшение звука до тишины к нужному времени.

Расскажите: вы слушаете музыку во время учебы или работы? Помогает ли это вам?

Подробнее..

Учиться и работать как разработчику поставить образование на рельсы

27.01.2021 16:20:11 | Автор: admin

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

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

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

Шаг 1. Оценить себя

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

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

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

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

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

Шаг 2. Удерживать фокус

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

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

Можно отслеживать эти позывы и силой возвращать внимание к делу. Для наглядности можно представить, что вы передвигаете что-то физическое и тяжелое, как камень. Первое время, пока навык фокуса не разовьется, за этим камнем придется пристально следить: вы постоянно будете обнаруживать, что он сбежал. Хорошая новость в том, что это продлится недолго фокусом можно будет управлять легко.

Шаг 3. Поддерживать интерес

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

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

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

Шаг 4.1. Учиться на работе

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

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

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

Результаты показали, что точность ответов на вопросы теста была выше у той группы, которая должна была объяснять свои действия во время решения задач: Почему вы выбрали этот метод?, Почему вы считаете, что здесь должно быть число 7? и так далее. Объяснение после теста тоже хорошо сказалось на итогах. Подробнее об этом можно почитать в статье.

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

Шаг 4.2. Учиться вне работы. Когда?

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

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


Расскажите, получается ли у вас постоянно учиться чему-то новому. Как вы решаете проблему прокрастинации и концентрации?

Подробнее..

Фронт без релиз-инженера, или Как я перестал бояться и полюбил деплой

08.02.2021 14:10:06 | Автор: admin

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

В нашей компании самостоятельный деплой это часть workflow многих разработчиков. Такая практика типична, скорее, для стартапов и редка в средних и крупных компаниях. Почему? Мне кажется, решение о полной передаче деплоя выделенным специалистам, играющим роль релиз-инженеров, происходит по вполне понятным причинам:

  • Разделение ответственности в ряде случаев ответственность за деплой оказывается высокой.

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

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

Как это происходит у нас

В Учи.ру был создан собственный инструмент для выкатки сервисов и настройки стейджей под названием Шаман по сути кастомный интерфейс к HashiCorp Nomad. Несколько лет назад он помог уйти от исполнения скриптов на локальных машинах, автоматизировать процесс деплоя и позволил разработчикам создавать тестовые конфигурации максимально быстро. Об этом мои коллеги из команды инфраструктуры написали отдельную статью.

Немного истории

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

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

Да придет спаситель

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

А что делать, если тебе нужно поднять копию среды для тестирования второго релиза? Не создавать же всю связку целиком заново? А если ее незначительно видоизменить? Для подобного в Шамане есть возможность создать шаблон конфигурации, в котором с помощью YAML описана вся россыпь машин, сервисов и эндпоинтов. В результате, если ваша команда поддерживает свой шаблон, поднятие нового инстанса развесистой связки сервисов становится тривиальной задачей.

И, кажется, коллеги со мной согласны:

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

Схема связи Шамана с кодом

На данный момент почти все наши GitHub-репозитории собираются при помощи GitHub Actions, в результате чего докер-образ пушится в общую приватную докер-репу. Этот workflow можно триггерить как автоматически (пуш в релизную ветку), так и руками, если хочется потестить какой-то сиюминутный фикс. Дальше Шаман подцепляет свежий образ и по кнопке раскатывает его на стейдж. Ну не красота, а?

И так как этот процесс находится в ведении разработчиков чуть более чем полностью, у нас есть возможность его упрощать. Меня, например, все-таки расстраивает необходимость сначала идти в GitHub, чтобы посмотреть статус билда, а потом в Шаман чтобы нажать на заветную зеленую кнопку для выкатки образа. После незначительной встряски коллег из инфраструктуры выяснилось, что последний предоставляет API, ручку которого можно дернуть из Github Actions с адресом для деплоя и идентификатором образа для деплоя. А это значит, что деплоить код можно полностью автоматически!

Когда что то идёт не так

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

Так нужно ли деплоить разработчику?

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

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

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

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

  • Стоит держать в голове, что мы работаем с in-house-решением со всеми вытекающими: оно может сломаться. Поэтому здесь нужно быть достаточно открытым и помогать коллегам чинить проблему, а не бранить решение.

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

Как происходит деплой в вашей компании? Считаете ли вы наш подход с одной кнопкой оптимальным или вам нравятся другие варианты выкатки новых сервисов и обновлений? Поделитесь мнением в комментариях.

Подробнее..

Единый UI-кит и синхронизация дизайна в Учи.ру. Часть 1

20.02.2021 10:19:11 | Автор: admin

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

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

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

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

И для разработчика, и для дизайнера

Создавая UI-кит, мы постарались сделать так, чтобы дизайнер мог участвовать в развитии интерфейса, не привлекая разработчиков. Он выбирает размер, цвет, шрифт, поведение компонентов прямо из Figma для этого там есть отдельная доска, на которой задаются дизайн-токены. Например, дизайнер может обозначить основной цвет (color-primary) как фиолетовый, тогда для визуальных компонентов будет использоваться именно он.

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

Выбираем основу библиотеки

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

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

Также мы хотели оставить себе пространство для маневра, чтобы не быть привязанными к определенному фреймворку. Отчасти потому, что несколько решений уже развивались не на рекомендуемом в компании стеке (React). Но в большей степени из-за нежелания безусловно завязываться на одной технологии. Учитывая скорость развития отрасли, мы должны были обеспечить командам возможность экспериментировать с технологиями без отказа от базы готовых UI-элементов.

Библиотек и фреймворков для создания веб-компонентов много. Например, ресурс WebComponents.dev, кроме предоставления исчерпывающего списка вариантов, обновляет их и информацию об их характеристиках. Мы составили свой топ-3: связку lit-element + lit-html и фреймворки Stencil, Hybrids выделили наиболее значимые критерии и сравнили по ним. На момент выбора это было в начале июня 2020 года получили такую картину:

Критерии

Фреймворк/библиотека

lit-element + lit-html

Stencil

Hybrids

JavaScript ES3+

+

+ (при использовании полифиллов)

+

JavaScript ES6+

+

+

-

TypeScript

+

+

+

JSX

+

+

+

Выгрузка для React

-

+ (при использовании плагина)

-

Выгрузка для Vue

-

+ (при использовании плагина)

-

Поддержка работы без фреймворка

+

+

+

Поддержка IE11

+

+ (при использовании полифиллов)

-

Поддержка современных браузеров

+

+

+

Поддержка плагинов / возможности расширения

-

+

-

CSR

+

+

+

SSR

+ (при использовании доп. библиотеки)

+

-

Подключение ассетов и CSS как отдельных файлов

-

+

-

Хорошая документация

+

+

+

Развитое комьюнити

+

+

+

Что за выгрузка в React/Vue?

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

На первый взгляд, lit-element + lit-html и Stencil показались почти равноценными. Первые не поддерживали плагины или не давали возможности расширения, соответственно не решали наш вопрос с выгрузкой, не поддерживали подключения ассетов и CSS как отдельных файлов, а со вторым на помощь пришли плагины. Для большей ясности мы ввели коэффициенты для каждого критерия и остановились на Stencil.

Если у вас похожий стек, можете посмотреть нашу таблицу.

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

Когда мы выбирали инструменты, оценивали, насколько изменится размер бандла сайта и на React, и на Vue. Сначала все было не очень хорошо, потому что демосайт на React весил без библиотеки 2,5 Мбайт, а с библиотекой 5 Мбайт. Бандл оказался таким большим потому, что по умолчанию Stencil предоставляет библиотеку с полифилами с поддержкой старых браузеров. Чтобы уменьшить размер бандла, мы использовали решение для выгрузки компонентов в виде отдельных файлов, с которыми очень хорошо работают фреймворки. Также мы отдельно вынесли шрифты и подключаем их по URL так мы добились, чтобы с библиотекой на Stencil сайт весил 3 Мбайт. Это хорошо, хотя уже сейчас понятно, что можно еще поработать над размером дополнительных компонентов.

От Figma до готового компонента

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

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

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

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

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

Для презентации UI-кита мы используем Storybook. Бандлы выкладываются сначала на внутренний ресурс. Дизайнер или менеджер может зайти, пощупать какой-то компонент, изучить особенности работы, почитать описания настроек. Например, можно сделать кнопку активной или неактивной и посмотреть, как это выглядит, еще до публикации бандла. Во второй вкладке таблицы вы найдете сравнение интерфейсов для UI-кита.

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


Расскажите в комментариях, используете ли вы в работе UI-киты. Может быть, у вас уже есть лайфхаки по дальнейшей оптимизации процессов дизайна и переходу на микрофронтенды? Приходилось ли вам более глубоко автоматизировать обновление компонентов в библиотеках? Насколько увеличивается размер бандла из-за использования общего UI-кита в вашем случае и удалось ли вам его оптимизировать? Интересно было бы узнать о вашем опыте.

Подробнее..

История Учи.ру от мини-монолитов до микросервисной архитектуры

31.03.2021 14:23:38 | Автор: admin

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

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

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

Артур Чарльз Кларк. 2001: Космическая одиссея (1968)

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

Актуальная схема Учи.ру и распределение сервисовАктуальная схема Учи.ру и распределение сервисов

Начиналось же все с маленького сайта около десяти лет назад.

С чего все начиналось

Эра мини-монолитов

Первые версии Учи.ру появились в начале второго десятилетия ХХI века. Это были очень простые сайты с отдельными базами данных, образовательным контентом и менеджментом: старая платформа Учи.ру с уроками, Учи.ру Столбики и Учи.ру Колонки. Спустя десятилетие они выглядят немного старомодно, но все равно мило мы храним их во внутреннем музее славы Учи.ру и публичный доступ к ним не предоставляем.

Так выглядело задание на сайте Учи.ру Столбики там дети учились считать в столбик.Так выглядело задание на сайте Учи.ру Столбики там дети учились считать в столбик.Еще несколько исторических документов.
В Столбиках уже можно было получать ачивки за учебу.В Столбиках уже можно было получать ачивки за учебу.А список уроков на старой платформе Учи.ру выглядел довольно просто.А список уроков на старой платформе Учи.ру выглядел довольно просто.

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

Эра зарождения первого монолита

До 2012 года сайты существовали обособленно. Затем мы создали новую платформу с единой точкой входа Login, которая поглотила старую Учи.ру и Колонки. Столбики ждало скорое забвение.

Изменения и перенос контента породили проблемы вроде конфликта стилей, что сказывалось на качестве. Тогда команда впервые задумалась о создании эталонной системы управления контентом CMS.

Эра CMS

Через два года системная архитектура выглядела скромно: CMS, основная платформа, а также разные прикладные модули, например, для аудита, управления персоналом, временного трекинга.

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

Расширение функционала основного модуля

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

Изначально мы старались разделить ответственность. Так, часть задач мы реализовали в виде функций CMS, таких как управление уроками или разработка методических материалов. Но когда темпы выросли, практически все новое стало добавляться в uchiru-login, просто потому что так было быстрее. Постепенно усложняя этот компонент, мы получили монолит. Чем дальше, тем больше его размеры и высокая степень связности затрудняли дифференциацию различных функциональных элементов.

Из-за сложностей с любыми модификациями в монолите в начале 2019 года мы работали с устаревшими версиями Rails (4.1) и Ruby (2.1.5). Webpack с небольшими вкраплениями React-компонентов не позволял легко обновить зависимости без существенных рисков отказа в обслуживании. Нужно было что-то делать

Выделение функций из состава монолита

Чтобы прощупать возможности разделения, мы начали проводить эксперимент по разъединению фронтенда и бэкенда. К этому моменту интерфейс представлял собой классические Rails-шаблоны с примесью старого Webpack. И хотя мы не ставили глобальной задачи по переходу на микросервисы, этот опыт все же стал большим шагом для нашей команды сразу в техническом, инфраструктурном и организационном плане. Но самое главное, мы начали выделять компоненты из uchiru-login. Стало понятно, что обуздать монолит реально. Отправной точкой стало выделение откровенно обособленного функционала с минимальной степенью связности. На подобных некорневых блоках мы и сосредоточили усилия.

  1. Генератор PDF-сертификатов. Попрактиковались мы на микросервисе, который должен выдавать готовый документ по входным параметрам. Фактически мы сделали классический распределенный монолит с синхронным сетевым взаимодействием.

  2. Олимпиадная платформа. Ее отделение от большого брата стало важным шагом. Стоит пояснить, что олимпиады выросли в отдельное направление: они бурно расширялись, и разработчикам приходилось постоянно оглядываться на другие части системы из-за большого риска сломать имеющийся функционал. Эта скованность мешала развиваться хотелось независимости. В итоге команда олимпиад повысила свои компетенции и создала прецедент выделения реально большого куска из монолита.

  3. Развивающие игры. Используя опыт олимпиадников, мы создавали игры как отдельный компонент, связанный с монолитом авторизацией, но способный развиваться самостоятельно.

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

    Сначала монолит и новый сервис использовали общую базу данных. Мы старались по возможности переносить операции записи ответственных данных в новые БД, а из монолита использовать их в режиме чтения.

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

    Для разработки этого модуля мы использовали библиотеку JSONAPI Resources, которая сочетает в себе гибкость, низкую скорость и синтаксис, очень похожий на классический ActiveRecord. Залогом успеха стало стремление группы энтузиастов, которые во что бы то ни стало хотели достичь нужного эффекта.

Справляемся с высокими нагрузками

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

  1. Кеширование. Это было первое, что пришло в голову. В качестве инструмента мы использовали Redis. Чтобы не заниматься поддержкой кластера в облаке, мы решили заменить его урезанной версией Redis от Envoy с шардированием по ключу хранения. В результате система стала держать нагрузку лучше, но это было только начало.

  2. Реплики БД. После очередного скачка трафика мы уперлись в лимит пула соединений с БД. Теоретически работа с микросервисами должна была помочь в масштабировании самых нагруженных частей системы или вовсе избежать этой проблемы. Но это в идеальном мире.

    Мы попытались выйти из ситуации с помощью реплик БД, к которым поступали бы запросы на чтение. Звучит просто и круто, но те, кто знаком с рельсовой кухней и большой связностью данных, моделей и ассоциаций, назвали бы нас психами. Все дело в контекстах инициализации объектов и механизме ассоциаций. Поэтому первым делом под нож пошли запросы статистического характера, большие списки и отчеты.

  3. Octopus. К счастью, на помощь нам пришел Octopus, но и он не обрабатывал все случаи, особенно те версии, которые были совместимы с устаревшей платформой. Например, мы обнаружили, что запись в режиме реплики тянет за собой все ассоциативные связи в том же режиме. Это порождает конфликты, связанные с попытками записи в read-only-транзакциях. Пришлось заниматься monkey-патчингом ORM-компонентов. Методом проб и ошибок проблему решили.

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

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

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

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

Боевое крещение Circuit breaker.Боевое крещение Circuit breaker.

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

Разделение на микросервисы действительно возможно

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

Артур Чарльз Кларк. 2001: Космическая одиссея (1968)

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

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

Подробнее..

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

14.07.2020 18:11:56 | Автор: admin
Лето время каникул и низкий сезон для образовательных проектов. За эти три месяца дети могут забыть до четверти знаний, полученных в классе и дома. Для того чтобы вовлечь детей в повторение математики на каникулах, мы делаем образовательные игры.

Сегодня я расскажу о нашем опыте в такой лернификации мультиплеерных игровых механик и адаптации их для детей от семи до одиннадцати лет на примере новой онлайн-игры Формула 1+1. За несколько месяцев работы в тестовом режиме (игра доступна только 10% пользователей платформы) в ней приняли участие 95 тыс. игроков, а самые упорные провели в ней больше 100 часов, то есть более 6 тыс. игр. Я постараюсь показать, как мы реализуем лернификацию процесс, когда мы не пытаемся сделать интересной учебу, а напротив добавляем элемент обучения в игру.


Карта гонок в игре Формула 1+1

Игра Формула 1+1 мультиплеерные гонки, где на скорость автомобиля влияет решение примеров устного счета: чем быстрее и больше правильных ответов будет давать игрок, тем быстрее он будет ехать. За победу в заезде игрок получает опыт (поднимается в рейтинге) и монеты, на которые можно покупать новые, более мощные на вид машины.

Какие цели мы ставили


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

Мы стремились:

Учесть особенности детского восприятия


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

Показать ценность игры взрослым


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

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

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

Игровая механика


Ядро геймплея


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

В пользу мультиплеера выступает наш удачный опыт проведения различных соревнований на портале и обилие успешных мультиплеерных мобильных игр на рынке: Brawl Stars, Clash of Clans, Clash Royale и подобные. Так у нас получились гонки, где в онлайн-заезде два ученика соревнуются в том, кто быстрее доедет до финиша.

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

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


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

Второстепенные механики


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

Чтобы добавить гонке вариабельности (читай реиграбельности), мы придумали бонус за быстрые ответы. Если игрок два раза подряд дает правильные ответы быстрее соперника, его автомобиль еще чуть-чуть продвигается вперед.

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

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

Например, ученики 1 класса умеют считать только в пределах 20, а в 4-м дети решают примеры с трехзначными слагаемыми и переходом через один десяток. С заданиями последнего уровня без калькулятора справится не каждый взрослый на один пример отведено всего десять секунд. Попробуйте прямо сейчас быстро выполнить задание на сложение с двумя переходами через десятки: 574 + 349.



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

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

Чтобы избежать договорных матчей, мы не даем вознаграждений за заезды с друзьями.

Персонаж: детали и нюансы


Три составляющие персонажа игрока


Дети любят подражать родителям, им нравятся атрибуты взрослой жизни. Мы постарались это учесть, поэтому при первом входе в игру каждый ребенок получает игровые автомобильные права. Заполняя их, игрок создает своего персонажа: выбирает аватарку, игровое имя и автомобильный номер для внутриигровой идентификации.

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

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



Авторизация 0+


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

Мотивация


1. Награда за сыгранную партию


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

Кстати, когда мы тестировали разные модели авто с детьми, самыми крутыми они называли не суперкары и не новинки автопрома, а модели, которые видели в семье.



2. Прокачка в нескольких направлениях


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

3. Личный рейтинг


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

Для расчета рейтинга игрока мы используем коэффициент Эло, часто применяемый в спорте (шахматы, футбол, теннис). Способности в счете у детей сильно различаются не только от года к году, но и внутри класса. Кто-то научился считать еще до школы, а кто-то в 1 классе только знакомится с цифрами. Поэтому мы должны подбирать соперников, учитывая не только класс игрока, но и его способности. Иначе слабому ребенку будет грустно играть с сильными игроками, а сильному быстро надоест постоянно выигрывать.

Рейтинг Эло метод расчета относительной силы игроков в парных играх. Все новые игроки получают стартовое значение рейтинга. После гонки с соперником рейтинг обоих изменяется в зависимости от победителя и значений рейтингов обоих игроков. Если ребенок выиграл у партнера с более высоким местом в рейтинге, его рейтинг вырастет больше, чем если бы он выиграл у соперника на более низком месте. Таким образом сильный игрок, постоянно выигрывая, будет увеличивать свой рейтинг, пока не дойдет до равных ему, а шанс на победу не составит 50/50.


Игроки с меньшим уровнем могут оказаться выше в рейтинге.

4. Рейтинг класса


Как показывает наш опыт, дети с удовольствием соревнуются целыми классами, поэтому мы добавили в игру и рейтинг класса. Чтобы решить проблему разной численности классов (от нескольких учеников до 35) и чрезмерного рвения к первым местам, мы разработали отдельную систему расчета классного рейтинга.
  1. Очки для рейтинга класса игрок получает только за первые пять заездов в день в режиме Микс.
  2. Количество получаемых очков зависит от численности класса. Если каждый ребенок в каждом классе будет участвовать в пяти гонках в день и выигрывать, то эти классы наберут одинаковую (максимальную) сумму очков класса вне зависимости от количества учеников. Эта сумма становится основой для расчета баллов рейтинга для всех классов в игре.
  3. Эта максимальная сумма должна хорошо (без остатка или с наименьшим остатком) делиться на количество дней в месяце, на пять гонок, на различное количество детей в классе и на три (за проигрыш полагается от выигрыша). Это важно, потому что ученики 14 классов еще не знают дробей.
  4. Для подбора наилучшего значения этой максимальной суммы мы написали скрипт, который перебрал несколько сот тысяч значений и выбрал наиболее подходящее число 890 100. Сумма вознаграждения за заезд получается в виде целого числа, при этом не громоздкой. Например, в классе из 30 человек за победу в заезде игрок получит 198 очков класса.


Матрица расчета баллов

Вывод


У нас получилась игра, очень похожая на обычную онлайн-игру, но с реальным образовательным эффектом, при этом адаптированная для детей 711 лет. Главная механика игры служит улучшению навыка счета у ребенка. Первые результаты показывают, что дети готовы проводить в ней огромное количество времени: на момент написания этой статьи мы насчитали более 95 тыс. активных игроков (при том, что игра все еще находится в тестовом режиме и доступна только 10% учеников Учи.ру). Реакция родителей на Формулу 1+1 тоже положительная.

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

Game-based learning VS геймификация 5 основных отличий

31.08.2020 10:17:14 | Автор: admin
Игровые механики давно используются в неигровых процессах: продажах, маркетинге, управлении персоналом и обучении. Геймификация зарекомендовала себя как действенный способ вовлечения в образовательный процесс и стала одним из главных трендов.

Однако все более заметным становится game-based learning тип игрового процесса, в результате которого пользователь получает знания или навыки. Исследователи говорят о нем как о самом быстрорастущем тренде в секторе образования по всему миру, в частности в школах, а общий объем рынка к 2025 году оценивают в $28,8 млрд.

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

Магическая математика







Математическая игра Учи.ру для школьников. Основная механика: чтобы колдовать в схватке с противником, нужно решать примеры. Дополняется многочисленными фичами в виде кастомизации и прокачки персонажей.

Minecraft: Education Edition





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

Adventure Academy







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

12 is a dosen





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

Еще несколько примеров:

Oregon Trail





Один из первых представителей game-based learning. Игра для средней школы посвящена важному событию из истории США освоению Дикого Запада. Пользователь ведет группу переселенцев в Орегон, распоряжается припасами, охотится на диких животных и принимает решения в трудных ситуациях.

VR-тренажеры и симуляторы





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

Empire of Code







В стратегии, обучающей программированию, игрок присоединяется к команде Python или JavaScript. Для нападения на противника используются стандартные алгоритмы домашнего лагеря. Совершенствование алгоритмов и создание бота помогут производить больше ресурсов и эффективнее атаковать соперников.

Screeps





ММО по программированию на JavaScript: игроки программируют логику юнитов для захвата ресурсов и обороны от соседей.

Mystic Math





Мистическая новелла Учи.ру об исчезновении электричества в городе, которое главный герой-старшеклассник расследует, решая математические головоломки. От выбора реплик зависят отношения с другими персонажами.

SimRefinery





Cимулятор нефтеперерабатывающего завода от создателей SimCity, разработанный в 1993 году по заказу энергетической компании Chevron. Сотрудники в игровой форме могли отрабатывать аварийные ситуации, изучать производственные и технологические процессы.

Space School







Game-based learning встречается даже на приставках NES (Fomicom), работающих только со специальным адаптером. В образовательной игре с научно-фантастическим сюжетом для учеников 46 классов человечество отправилось в открытый космос и вошло в контакт с инопланетянами. Оказалось, что вселенная находится под гнетом темного союза, а победить его можно, прокачав интеллект у детей. История помогает привлечь внимание к обучающей части в игре даже можно поговорить с одноклассниками-пришельцами и учителем.


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

Роль, которую играет пользователь


  • GBL: есть роль
  • Геймификация: нет роли

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

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

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

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

В любой игре на первом плане есть роль и миссия. Играешь в Super Mario ты сантехник и спасаешь принцессу, в Uncharted ты искатель сокровищ и пытаешься опередить соперников.

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

Цель, к которой стремится пользователь


  • GBL: развлечься
  • Геймификация: научиться

Цель у игрока в образовательных game-based-проектах выиграть: завершить уровень, убить босса, дойти до конца. Достичь ее можно, придерживаясь внутриигровых правил, косвенно связанных с обучением.

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

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

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

Цель ученика геймифицированного курса другая научиться чему-то конкретному, например: программированию в классическом подходе, чтобы обрести профессию и стабильную зарплату, или математике, чтобы сдать экзамен. То есть пользователь такого проекта хочет получить новые знания, и PBL (points, badges, leaderboards), основа геймификации, помогает их освоить.

Мотивация пользователя и ее связь с возрастом


  • GBL: дети хотят больше играть и меньше учиться
  • Геймификация: взрослые тоже хотят меньше учиться, но осознают, что это необходимо

Мотивация детей отличается от мотивации взрослых. Например, в 5 классе учиться совсем не хочется: до экзаменов, поступления в вуз, продвижения по карьере еще далеко. Радость от познания нового исчерпана, в школе начинаются темы, которые непонятно как применить в жизни. Игры, сериалы и общение со сверстниками на этом этапе основные конкуренты образования.

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

У взрослых все по-другому. Школьники с 9 класса, студенты, специалисты обычно знают, какие именно экзамены будут сдавать, что хотят получить с помощью новых знаний. Развлекаться они тоже не прочь, но хотят уже не смешивать обучение с развлечением, а как можно быстрее достичь конкретного результата. У взрослых другая система развлечений: в отличие от детей, которые на 100% зависят от родителей, они сами поставщики своего досуга.

Геймификация это защита от прокрастинации. Игровые механики в образовательных курсах остаются на втором плане. Они помогают решить проблему монотонности, получить порцию дофамина на длинной дистанции. Человек получает удовлетворение от результата, например, успешно сданного экзамена. Если он не скоро, а объем необходимой для усвоения информации слишком велик, на помощь приходят очки, ачивки и визуализация прогресса.

Геймификация работает только тогда, когда студенту уже интересен или важен предмет. Game-based learning может сделать изучение предмета интересным, даже если он изначально не вызывает теплых чувств. Например, в Minecraft Education дети, которые не любят уроки химии, ищут нужные элементы, чтобы сделать новое вещество, а вовсе не для того, чтобы выучить химию.

Вознаграждение в системе проекта


  • GBL: вознаграждение напрямую влияет на прохождение
  • Геймификация: вознаграждение влияет на мотивацию пользователя

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

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

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

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

В GBL ассортимент гораздо шире. За заработанные очки можно прокачать персонажа, улучшить его внешний вид, открыть новую локацию. Обычно хочется сделать сразу все, но приходится выбирать, что важнее именно сейчас.
Также один из основных мотивов GBL любопытство, универсальный источник дофамина. Что будет дальше? главный вопрос и двигатель игрового процесса.

Разный подход к контенту


  • GBL: основной игровой + дополнительный обучающий
  • Геймификация: основной обучающий + дополнительный игровой

В game-based learning первична игра. При этом игровой механики может не быть только роль и сюжет (как в текстовом квесте). В том же Go Practice, который лично я считаю GBL, механика не игровая, а основанная на ролевой модели и решении проблем продуктовой аналитики.

Как сделать сюжет и механику интересными всегда та еще задача. Это сложно, но открывает горизонт для творчества.

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

В game-based learning за счет прогресса развиваются сюжет и персонаж, а в геймификации прогресс завязан, в основном, на поинтах, ачивках и лидерборде.

***

Говоря коротко, если геймификация это упаковка для образовательного продукта, то game-based learning это и есть продукт, игра, в которую встроено обучение.

В последнее время game-based learning-проектов становится больше, появляются новые решения и идеи. Геймификация своего рода стандарт, который показал эффективность. Это как фича, которую многие хотят внедрить и которая быстро повышает метрики. Сегодня даже внутри банковских приложений есть геймификация. Оба подхода к созданию образовательных проектов могут быть полезны и результативны.
Подробнее..

Образование 20202030 будущее наступило вчера

29.07.2020 10:12:50 | Автор: admin
А откуда можно получить знания помимо лент? Из межзвездного пространства?
Из книг. Непосредственно изучая приборы. Думая.

А. Азимов. Профессия (1957)

В 2020-м весь мир как будто временно оказался в тестовом режиме одного из антиутопических сценариев будущего. Всё, что нельзя было отложить или приостановить, пришлось менять: рабочий график, досуг, школьные занятия. Дети стали похожи на Марджи, героиню рассказа Айзека Азимова: грустили и думали о том, как же было весело в школах раньше.


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

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

Даже до вынужденной дистанционки многие были скептически настроены к онлайн-образованию: 55% взрослых уже имели неудачный опыт прохождения курсов в интернете.

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

Образование будет интерактивным


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

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

Геймификация уже внедрена во многие сферы: ритейл, human resources и образование. Ею активно пользуются для бизнес-обучения и оценки эффективности. В настоящее время геймификационные механики активно начинают внедрять и для реализации образовательных стратегий, в том числе в крупнейших вузах мира, на базе игр формируются образовательные проекты. Например, недавно Microsoft объявил о выпуске новых киберспортивных миров и уроков Minecraft: Education Edition.

В образовании уже давно в каком-то смысле есть элементы игры: хорошие и плохие оценки за выполнение задания как баллы в прохождении квеста. А по окончании очередного учебного года у каждого происходит Level Up переход на следующий уровень сложности.

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

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

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

Обучению помогут гаджеты


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

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

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

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

Образование будет дистанционным отчасти


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

Всего за несколько недель специалистам удалось разработать и запустить самую крупную интернет-платформу для дистанционного обучения. Одновременно ей могут бесплатно пользоваться 50 млн учащихся из разных регионов страны.

Сегодняшний опыт показывает, что онлайн-формат обучения становится неотъемлемой частью классической школы, при этом полностью дистанционное образование невозможно: живой контакт по-прежнему необходим. Скорее всего, в будущем будет меняться соотношение офлайна и онлайна: какие-то вещи будет эффективнее поручить компьютеру например, проверку домашних заданий. Согласно отчету ЮНЕСКО, примерно 60 тыс. школ в Китае уже внедрили машинное обучение для оценки эссе: оценка алгоритма на 92% совпадает с оценкой учителя.

Образование будет индивидуальным


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

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

На индийской платформе Byju's, крупнейшем EdTech-проекте в мире, обучающие задания представлены в формате анимированных карточек и увлекательных живых тестов. Также для каждого ученика выстраивается своя траектория обучения, которая отображает путь, который он прошел, и время, которое он потратил на решение.

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

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

Специалисты говорят, что в самом ближайшем будущем data-driven-индивидуализация готова шагнуть еще дальше. Системы научатся подбирать и рекомендовать курсы, задания и даже различные методики не только на основе того, как ученик справляется с программой. Возможно, рекомендации по обучению будут составляться исходя из интересов ребенка, его любимых видов спорта, компьютерных игр, прошедших или предстоящих поездок и путешествий, а также социальных навыков. Британский проект ClassCharts, например, уже предлагает оптимальный план рассадки учеников в классе, руководствуясь анализом полученных данных. Искусственный интеллект анализирует способности и успеваемость учеников, то, как они взаимодействуют и влияют друг на друга, а также ищет оптимальные схемы работы в парах и группах.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru