Переводим без интернета: как мы делали Яндекс.Перевод...

Post on 15-Jan-2015

345 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

перевод

Переводим без интернета

Ваня Москалёв, отдел машинного перевода

Mobile!60 %

Мобильный интернет

Процент мобильных пользователей интернета в мире в 2013 году

Web of Apps

• Приложения стали практически неразделимы от веба, стали "представлением" веб-сущности на устройстве.

• Разработчики подчас строят бизнес-логику вокруг получения данных от веб-сервиса.

Где нужен офлайн?

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

• При плохом подключении (метро).

• Для экономии трафика.

Я.Перевод

• 16 марта 2011 – бета-версия онлайн-сервиса Яндекс.Перевод.

• В декабре 2012 – первое мобильное приложение – для iPhone, спустя полгода Android, спустя год Windows Phone.

• Весна-лето 2014 – версия 2.0 для iOS с офлайн-переводом.

Архитектура и реализация

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

Синхронный перевод

Машинный словарьПредиктор

Озвучка

Определение языка

Используемые веб-сервисы

Клиентская логика

Translate Detect

Dictionary

Predictor Text-To-Speech

Прочее

Что нужно было сделать

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

• Портировать серверный код на устройство.

• Зарефакторить приложение.

Что было

• Система, спроектированная в краткие сроки для работы в онлайн-режиме.

• Довольно высокая связность. • Накопившиеся поправки для логики работы приложения.

Как рефакторили

• Четко определили и описали проблемную область.

• Понизили связность системы (помогла абстракция над сервисами).

• Определили, описали и реализовали юзкейсы, обложили их тестами.

Проблемная область

YTR Domain

LanguagePair

Translation

Prediction

Dictionary

Errors

Business Logic

<I> DAL

Больше абстракций!

Business Logic

Translate S. Presentation Logic

Predictor S.

Dictionary S.

Больше абстракций!

Business Logic

Presentation Logic

Web<I>

Offline

Web

Offline

Web

Offline

<I>

<I>

Проектирование логики

• Нужно было объединить и описать в спецификациях все юзкейсы.

• Был объявлен базовый класс, представляющий составной запрос (гибрид Strategy и Command).

• Написаны тесты на конкретные реализации этого класса.

Юзкейсы

• Fail-over: переход к офлайн-модели, если веб-сервис недоступен.

• Логика синхронного перевода. • "Сборка" ответов разных сервисов в составной ответ.

Загрузчик

• Один из самых важных и сложных компонентов – загрузчик.

• Две реализации: для iOS 6 и iOS 7, фоновая загрузка на iOS 7.

• Оказался многофакторным компонентом.

Выводы

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

• Нельзя недооценивать сложность сопутствующих задач (загрузчик).

Грабли

Грабли: NSURLSession

• Сетевые задачи, созданные в фоне, всегда создаются с флагом discretionary

• Такие задачи тормозят и перестают работать если у устройства осталось мало заряда. На это жалуются пользователи ;)

Грабли: NSURLSession

NSDictionary *userInfo = @{ @"background" : @(self.context.isBackground) }; !// Сериализуем в JSON NSData *data = [NSJSONSerialization dataWithJSONObject:userInfo options:0 error:nil]; NSString *description = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; !// Прописываем в taskDescription sessionTask.taskDescription = description;

Можно хранить метаданные в -[NSURLSessionTask taskDescription]

и при входе в приложение пересоздавать discretionary-задачи

Грабли: NSURLSession

• NSURLSession не умеет возобновлять загрузки из Content Delivery Network.

• Под капотом – If-Modified-Since и ETag.

• Если CDN отдает ETag, то возобновление загрузок сломается (каждый сервер отдает свой ETag).

Грабли: mmap

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

• Для перевода в одном направлении нужно ~270 МБ виртуального адресного пространства.

Грабли: mmap

File = fopen(path.c_str(), "rb"); fseek(File, 0, SEEK_END); Size = static_cast<size_t>(ftell(File)); fseek(File, 0, SEEK_SET); Data = mmap(0, Size, PROT_READ, MAP_SHARED, fileno(File), 0);

Объем виртуального адресного пространства на iOS ограничен, mmap может вернуть MAP_FAILED, если она занята другими

процессами или недоступна одним чанком.

Грабли: mmap

• На iPhone 4 / 4S система выделяет около 700 МБ пространства на девайс.

• Оптимизация: пришлось пожертовать скоростью отклика при переключении между направлениями.

Грабли: донести фичу до пользователей

Пользователи сами не вникнут в сложный функционал. Нужно как можно больше учить и объяснять.

Важно: фидбек внутри приложения

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

С чем мы столкнулись

• NSURLSession не дружит с CDN.

• NSURLSession оптимизируется системой.

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

• In-App фидбек – очень удачное решение.

Открытые вопросы (обсудим вместе?)

• Как грамотно собирать статистику по User Experience в гибридном приложении?

• Как лучше всего осуществлять переход между онлайн и офлайн-режимом? Ручной и автоматический подходы.

Спасибо за внимание!

Ваня Москалёв iOS-разработчик, отдел машинного перевода !ivanmoskalev@yandex-team.ru @ivanmoskalev

top related