Яндекс о сервисе push-сообщений, качестве кода в автотестах и факторах ранжирования

120

31 августа 2013 года в Минске прошел Я.Субботник, в ходе которого сотрудники минского, московского, питерского и симферопольского офисов Яндекса делились своим опытом. Для тех, кто не присутствовал на конференции, была организована онлайн-трансляция и трансляция в Твиттере по хэштегу #yasubbotnik.

Юрий Василевский (руководитель группы разработки): «Сервис push-сообщений Яндекса»

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

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

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

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

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

В доставке Push-сообщений участвуют четыре компонента:

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

Далее Юрий рассказал, как организована генерация сообщений бэкенда на сервисе Яндекса.

Делается пост-запрос, в котором указывается четыре параметра:

app — имя пакета

app_tokens — cписок токенов приложения (device+apk)

ttl — время жизни сообщения в секундах 


data — payload нотификации в json формате

Официально Яндекс обеспечивает время хранения сообщений 30 дней. Это время можно уменьшить.

Push-клиент поставляется в виде библиотеки. Реализовать клиент можно на готовых сырцах, чтобы их было проще интегрировать (пример реализации).

Собственный сервис должен соответствовать определенным требованиям. Сервис Push-сообщений должен обеспечивать безопасное соединение, работать непрерывно и обрабатывать 100% входящих сообщений.

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

Алексей Витенко (разработчик Yandex.Store): «Синхронизация данных на клиенте»

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

Далее речь пошла об Account Manager’е, позволяющем работать со встроенными в систему аккаунтами. Это сервис, который встраивается в систему и позволяет добавлять аккаунт на устройство:

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

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

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

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

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

По словам Алексея решением может стать выделение главного приложения, приложения-флагмана. Флагманом может быть приложение, которое несет в себе все общие компоненты.

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

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

Механизмы обмена данными между андроид-приложениями:

  • SharedUserID 
  • Content Providers —
  • Services 
  • Broadcasts 
  • SharedPreferences (до API 17)

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

Передача данных через Content-провайдеров — это второй вариант решения, стандартный механизм для предоставления доступа к данным приложения. Все резервные сервисы обращаются к главному и копируют себе его данные. Это решение хорошее, только если данные одной структуры. Минус состоит в том, что при таком решении каждое резервное приложение должно обратиться к главному и вычитать из него данные. Если в процессе что-нибудь произойдет с главным приложением и оно будет удалено, то резервные приложения останутся без новых данных. Системный баг в самом Андроиде, также является серьезной проблемой, которая была решена только в четвертой версии OS.

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

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

Артем Кошелев (QA Team Lead): «Качество кода автотестов»

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

Статический анализ. Если расположить виды обратной связи на некоторой шкале обратной связи, на которой есть КПД и время, то КПД тем выше, чем меньше анализ занимает времени:

Компилятор, подсветка синтаксиса — это обратная связь, которая получается моментально.

Статический анализ может быть автоматическим и ручным. Автоматический анализ позволяет обеспечить понятность и простоту разрабатываемого кода. Понятность кода напрямую вытекает из следования стандартам. Каждый язык заточен под определенные задачи, соответственно, у каждого есть какой-то свой стандарт. Для Python это — РЕР 8, Perl — Perlstyle, Js — Framework depend, .NET — MSDN, Java — Oracle.

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

В целом, стандарт состоит из шести правил:

  • именование 
  • отступы/скобки 
  • пробелы 
  • коменты 
  • магические числа 
  • размер

Цикломатическая сложность вычисляется по формуле С = е — n + 2.

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

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

Ручной статический анализ (Code-review) ведет к хорошей архитектуре.

Юрий Картынник (руководитель бригады разработки): «Факторы ранжирования: основы»

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

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

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

Классификация факторов ранжирования по источнику данных:

1. Текстовые (одни из самых важных) 

  • Соответствие текста запроса и текста документа 
  • Тематическая классификация запросов и документов 
  • Язык, длина… 

2. Ссылочные 

  • Цитируемость документа 
  • PageRank и другие факторы на ссылочном графе 
  • Аналоги текстовых факторов по текстам ссылок 

3. Статистические 

  • Популярность запроса 
  • Популярность сайта 

4. Географические 

5. Временные 

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

Виды факторов по месту расчета:

  • Статические (один раз при индексировании) 
  • Запросные (один раз на запрос) 
  • Динамические (все пары запрос-документ)

Функция ранжирования по набору факторов определяет оценку релевантности

Инструменты факториста:

1. C++, Python и др. (в экспериментах)

2. Платформы распределенных вычислений

  • MapReduce (над большими таблицами)
  • Mesh (на графах)

3. Платформа FML

  • Тестовая реплика поискового индекса
  • Инфраструктура подбора формул
  • Эксперименты, мониторинг

Обзор подготовила Александра Кирьянова