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

Вначале было слово


Изначально наше мобильное приложение задумывалось как простой вспомогательный инструмент для учеников школы. Большинство уроков содержат некоторый набор лексики для заучивания, к нему и студент, и преподаватель могут добавлять слова прямо во время занятия, и все это по идее надо выучить к следующему классу. Понятно, что делать это на телефоне или планшете – удобно. Так появилась первая версия приложения для iOS, доступная нашим ученикам, содержавшая лишь четыре простых механики заучивания (словарная карточка, «помню — не помню» и две проверки с выбором правильного ответа из четырех вариантов). Никаких «умных» алгоритмов там не было, была простая зубрежка, а программа решала, что слово выучено, когда ученик определенное количество раз подряд правильно выбирал перевод. Позже такое же приложение было написано с нуля для Android.

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

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

Но вот идея писать с нуля еще две версии приложения (для iOS и Android), а потом поддерживать и развивать параллельно все три, нам совсем не нравилась. Поэтому было решено ядро оформить в виде C++ библиотеки, единой для всех версий приложения, и дальше работать с ней.

Поэтому мы, по сути, еще раз переписали все с нуля. Но один и, надеемся, последний раз.

Одна библиотека


Почему именно C++? Потому что С++ – кроссплатформенный язык, он отлично компилируется под iOS, хорошо поддерживается на Android, его можно использовать с PHP в вебе, скомпилировав C++ код в PHP-extension. Другие языки не могут похвастать такой поддержкой. Например, в случае выбора Java нам было бы проще сделать приложение для Android, но для переноса на iOS пришлось бы использовать непопулярные инструменты (jvm вроде RoboVM), а работало бы оно заметно хуже. Плюс более сложная, чем в случае C++, интеграция Java с PHP.

В итоге у нас получилась такая картина: интерфейсы (клиентские программы), написанные отдельно для каждой платформы на их нативных языках (Objective C, Java и бэкенд на PHP), обращаются к общему для всех версий ядру приложения (библиотеке C++), выполняющему основную работу. Приложение также имеет связь с сервером (авторизация, хранение общих ресурсов, каталог статических сетов, словарь, потенциальная связь со сторонними приложениями) и хранилищем локальных данных (Realm).

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

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

Для веб-версии используется фреймворк PHP-CPP. Выбор был обусловлен удобством, наличием более-менее полной документации и поддержкой именно C++, а не C. К минусам относим проблемы с отладкой: смотреть логи – не самый удобный способ, а других официальный сайт не предлагает.

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

И мы видим, что это хорошо!

Посмотреть, как это работает, можно, загрузив мобильное приложение Aword для iOS или для Android. Веб-версия будет доступна позже.

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

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


  1. roman_art
    16.01.2017 11:32

    Интересная статья. Как осуществляется сетевые запросы? используя нативные механизмы(NSURLSession) или механизмы c++


    1. akM12a
      16.01.2017 11:36

      Ядро на C++ отвечает только за логику. Работа с базой данных, сетевые запросы и UI реализованы нативно.


      1. altk
        16.01.2017 12:10

        А почему бы не использовать SQLite и libcurl? Тогда ещё большую часть логики можно будет вынести в C++.


        1. akM12a
          16.01.2017 12:29

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


        1. roman_art
          16.01.2017 12:32

          Возможно, что libcurl умеет делать не всё то, что умеет нативный NSURLSession.


  1. DancingOnWater
    16.01.2017 12:00
    +4

    если пишите на C++, то что мешает использовать QtQuick из Qt?


    1. akM12a
      16.01.2017 12:23

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


  1. MKutuzoff
    16.01.2017 12:27
    +1

    Я так понимаю ASP.NET, WCF, Xamarin не в почете?


    1. ad1Dima
      16.01.2017 13:48
      +2

      Они бы не встроили его в нативное приложение.


      1. MKutuzoff
        16.01.2017 15:05

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


        1. akM12a
          16.01.2017 15:14

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


      1. Atreides07
        16.01.2017 15:50

        Судя по статье они и не встраивали, а написали все с нуля:


        Поэтому мы, по сути, еще раз переписали все с нуля.


        1. ad1Dima
          16.01.2017 16:35

          Ну а в комментариях они пишут другое.

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


  1. roman_kashitsyn
    16.01.2017 14:39
    +1

    Возможно, вам будет интересно посмотреть на https://github.com/dropbox/djinni.


    1. akM12a
      16.01.2017 15:09

      Спасибо за комментарий, в статье эта тулза не упомянута.


  1. mu3
    20.01.2017 11:38
    -1

    WebView и AppCache ещё не изобрели