15 января 2016 года был аннонсирован ежегодный конкурс Ubuntu Scope Showdown! Участникам предлагалось в течение шести недель разработать с нуля и опубликовать в магазине приложений свой скоуп для Unity 8 (официальный перевод слова scope как «линза» совсем не радует, поэтому пусть будет просто скоуп). За эти полтора месяца было разработано порядка 15 скоупов, еще полтора месяца шло голосование жюри (в три раза дольше заявленных двух недель). В результате победителями оказались Roman Shchekin, Ricardo Silva, Michael Weimann и Pieter Engelbrecht. О своем же опыте участия я бы хотел рассказать под хабракатом.


Идея


Для начала напомню, чем именно является scope по отношению к Unity 8:
  1. с точки зрения разработчика это ни что иное как плагин к среде рабочего окружения;
  2. с точки зрения пользователя это стартовый экран, позволяющий быстро получить доступ к необходимой информации без запуска отдельных приложений, кастомизируемая оболочка так сказать, конкурент виджетов.


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

Окей, есть желание участвовать, но нужна идея для скоупа. Опять же для справки уточню, что основное назначение скоупа это поиск информации, будь то поиск в книжном магазине, поиск информации об актуальных фильмах и событиях, поиск изображений в соцсетях и так далее (вторичное назначение это отображение текущего состояния, например показ текущей погоды или мониторинг ресурсов удаленной виртуальной машины). Помнится, в 2014 году был подобный конкурс, и тогда я из-за отсутствия идеи промаялся несколько недель, а потом забросил свои наработки по созданию скоупа на тему Dota 2 (которой тогда увлекался). Последние несколько лет я старательно изучаю различные онлайн-курсы (даже заполнил о себе страничку в https://github.com/open-source-society/computer-science), поэтому ничуть не удивительно, что мне в голову пришла мысль создать скоуп для поиска MOOC-курсов из различных источников.

Источники


Реализовывать свой замысел я начал с изучения возможностей, которые предоставляют «основные игроки» рынка online-курсов, а именно Coursera, edX, Udacity и Udemy. Вкратце по каждому:

Coursera

Добротный и неплохо продуманный API. Хорошая документация. Одним словом — лицом к людям, работать просто и удобно, попробовать можно прямо в браузере. Отдают JSON, содержимое настраивается.

edX

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

Udacity

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

Udemy

Самый удобный, гибкий и приятный API. Можно настроить практически все, что угодно. Единственное что мне было не очень понятно, зачем прикручивать «авторизацию» — перед использованием API предлагалось получить ключ доступа, который затем передавался бы в хидерах. У меня было сильное ощущение того, что я был первым, кто вообще этот ключ получил, потому что поддержка действовала крайне неуклюже.

Другие источники

Позднее добавились iversity и OpenLearning. По «богатству» API очень близки к Udacity, детально рассматривать не буду.

В общем и целом я был удовлетворен. Источники предоставляли всю желаемую информацию, а именно описание курса, детали проведения (длительность, уровень сложности и тд), ссылки на изображения и видео-визитки, информацию об инструкторах. Естественно она [информация] была разношерстная, местами неполная, по-разному организованная. Задачи поиска, структуризации и показа в приемлемом для пользователя виде и нужно было решить. Дав проекту временное название CourseExplorer, я принялся за разработку.

Инструментарий (и немного деталей)


В Canonical разработали специальный инструментарий для создания скоупов. Физически каждый скоуп представляет собой динамическую библиотеку. Притом ближе к конкурсу обновили список доступных языковых средств: если за несколько месяцев до этого единственным безальтернативным вариантом был C++, то уже в рамках конкурса предлагалось использовать JavaScript и Go. Естественно акцент был на новые языки и технологии, дабы привлечь новичков. Я же выбрал C++, так как среди теймплейтов присутствовал «C++ (Qt)», что не могло не обрадовать бывалого Qt разработчика.

Тут меня ждало первое разочарование — в шаблоне был «голый» C++. Я даже создал проект скоупа на C++ без Qt'a, чтобы попытаться увидеть разницу. Как оказалось, в шаблоне с Qt в одном месте используется QJsonDocument. И все :) «Лааааадно», — подумал я, — «будем гнуть свою линию!». Было решено использовать Qt во всех местах, а на чистый C++ переходить только в местах взаимодействия с API. Кстати об API: по сути, предлагалось реализовать в своем проекте три сущности (унаследоваться от некоторых базовых классов):
Scope
Сам скоуп, способный обрабатывать запросы на поиск и показ информации. В моем случае практически не требовал доработки.
Query
«Рабочая лошадка» скоупа, осуществляет поиск информации и разделение по категориям. Реализация свелась к последовательному вызову классов-клиентов источников (которые в свою очередь осуществляли разбор данных, возвращаемых сервисами).
Preview
Отображение ранее найденной и специальным образом структурированной информации в декларативном стиле с помощью заранее заданного множества элементов управления.
Про исходники рассказывать особого смысла нет, можете сами все посмотреть тут: GitHub

Для ускорения отображения результатов по пустому запросу было применено кэширование (в официальной документации такое использование именуется surfacing mode). Помимо этого в скоупе был применен механизм маппинга категорий, предоставляемых источником, на внутренние категории скоупа. В некоторых случаях приходилось два десятка категорий сводить к своим десяти (например, Literature и History свелось в Humanities), а иногда наоборот — использовать одну внутреннюю категорию для всех категорий оригинального источника (Web design, Desktop development, JavaScript свелись в одну IT & Tech).

Визуальная составляющая


На определенном этапе я понял, что нужно приводить свои наработки в товарный вид, правильно озаглавить и нарисовать иконку. Поразмыслив несколько минут я пришел к выводу, что неплохо было бы назвать скоуп на начальную букву алфавита, чтобы он всегда был в топе сортируемого по алфавиту перечня установленных скоупов на одном из базовых экранов ОС. Так родилось название Academy. С иконкой, к сожалению, так быстро не вышло расправиться. Идею пришлось искать уже не в своей голове, а в одном из сервисов создания логотипов. На глаза попался значок атома с частицами на орбитах. Он мне сразу понравился, так как у многих людей твердо ассоциируется с наукой. Я перерисовал его в одном популярном графическом редакторе. Получилось хреново, что тут скажешь, торопился. Однако первая версия полетела в магазин именно в таком виде. В следующий раз я решил взяться за иконку основательнее и перерисовал старую концепцию с повышенным качеством. Вышло лучше, быть может потому, что уже не было такого давления сроков. На этом варианте я было совсем хотел остановиться, но мне повезло — случайно в G+ наткнулся на пост одного OpenSource дизайнера, он как раз рисовал иконки для некоторых приложений UP. Согласился нарисовать и мне :) Так получился конечный вариант, который Вы можете видеть ниже. Остальные компоненты интерфейса я подвел под цветовой дизайн иконки, получилось прямо-таки миленько.


Баг


В какой-то действия в моем скоупе начали приводить к падению Unity. Не хотелось верить, что это моих рук дело, поэтому я протестировал все стабильные версии без последних изменений — баг присутствовал. Благо удалось быстро связаться с разработчиками Unity 8, вместе мы нашли проблему. Оказалось, что движок скоупов не может корректно реагировать на абсолютно одинаковые результаты (так как внутри производит сравнение по всем полям). Оказалось, что это edX так жизнь портит, присылает два одинаковых описания. Простая проверка на основе QSet и проблема решена.

Итог


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

И вот, долгожданное объявление победителей. Распределение мест уже было озвучено в прологе, так что можете быстренько вернуться в начало, чтобы еще раз увидеть призеров, а я в это время буду устало радоваться, ведь Roman Shchekin — это я!

P.S. Несколько скриншотов готового скоупа можно увидеть тут: uappexplorer/academy, анонс результатов developer.ubuntu.com
P.S.S. Может быть должно быть на гиктаймсе. Задумывалось как легкое чтиво, ИТ история и не более того. Критика приветствуется!

Комментарии (3)


  1. vasilisc
    19.04.2016 12:54

    Роман, поздравляю Вас с победой! Отслеживал конкурс и публиковал победу в различных группах социальных сетей. Как специалист объясните мне такой момент. Ранняя технология выглядела так: lens использовали различные scopes для окончательного представления инфо для пользователя. Например, область Google Docs может дополнить результатами ответ из области Zeitgeist в файловой линзе (Files Lens) и результаты будут выведены рядом с друг другом, как ответ на поисковый запрос пользователя. В терминах MVC Линза (lens) — это контроллер, область (scope) — модель.
    Сейчас так всё серьёзно изменилось или я что-то не понимаю, но всегда переводил scope как область, а тут все scope начали обзывать линзами. Разжуйте плиз. Спасибо!


    1. QtRoS
      19.04.2016 13:37

      Спасибо!
      Вопрос сложный — у Canonical все постоянно меняется. Один мой товарищ по команде DocViewer'a 6 раз переписывал свое приложение под последнюю версию UI Toolkit'a, а оно до сих пор еще даже не вышло в релиз. Но ответить попытаюсь — сейчас центральное место в модели занимает сама оболочка Unity 8. Она оперирует скоупами, являющимися физически плагинами к ней. Каждый скоуп сам по себе содержит некоторый определяемый им самим (не оболочкой) UI, а так же решает, какие данные показывать, притом в общем случае у скоупа есть данные даже при пустом поисковом запросе (я показываю актуальные и популярные курсы, например). Следующее отличие от старой технологии — в разных скоупах можно одновременно искать разные вещи. То есть теперь это не только расширение для поиска информации в каком-то определенном источнике, а отдельный элемент оболочки, практически живущий своей жизнью. Во внутренностях все шаги разделены, поэтому теоретически новая модель скоупов может эмулировать старые линзы.
      P.S. Кстати, если здесь есть кто-то из команды переводчиков — задумайтесь о использовании перевода «область» (или «сфера») для Scope.


      1. Hameloid
        19.04.2016 16:22

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