Первый пост блога мы решили посвятить «мобильной» тематике и  рассказать о  разработке глобального решения для запуска и создания приложений — «Мобильная платформа ЕФС».
       
Что это? Это многомодульный продукт, позволяющий массово создавать мобильные приложения, тиражировать их и поддерживать во время эксплуатации.



Итак, что мы делаем по порядку и по пунктам.

       
Разработка продукта


Мы разрабатываем собственный фреймворк, используя библиотеку React Native. Наш фреймворк включается в мобильные приложения ЕФС для сотрудников и является мобильным ядром, содержащим нативный код. Мобильные бизнес-приложения теперь разрабатываются на JavaScript.
       
Мы выносим типовые фрагменты кода в сущности, которые называем «компоненты» или «сервисы».
       
На текущий момент наши компоненты бывают трех типов:

  • визуальные компоненты (стилизованные кнопки, переключатели, списки, свитчеры, загрузчики и т.д.);
  • не визуальные сервисы (работа с сетью, аутентификация, логирование, удалённое конфигурирование и т.д.);
  • мобильные виджеты (end-to-end компоненты, позволяющие выводить некоторые агрегированные показатели в специальном разделе, называемым «Dashboard»).

Компоненты имеют мост-обертку в JavaScript (используется механизм ReactNative), тем самым мы позволяем JavaScript-разработчикам, используя стек JS/TS, React + Redux, создавать мобильные и frontend клиенты.
       
За каждым из компонентов скрывается нативная имплементация. Мы используем objective-c как основной язык, строго подходим к архитектуре, а также заботимся о производительности и оптимизациях.
       
Нас не удовлетворила организация библиотеки ReactNative, т.к. она не выглядела изолированной, многослойной и пригодной для масштабирования, поэтому мы изобрели свою архитектуру компонентной библиотеки — сейчас наша архитектура многослойна и придерживается основных правил из VIPER, SOLID и SOA.
       
Концептуальный эскиз на рисунке ниже:


По сути мы подружили ReactNative и VIPER.





Мы почти полностью отказались от стандартных компонентов, разработанных Facebook, и реализуем заново те, которые требуются для построения наших приложения. Почему?
       
  1. Наши компоненты должны иметь уникальный единый визуальный стиль ЕФС и быть непригодными для изменения (только допустимые настройки через свойства).

  2. Мы не можем покрыть тестами код ReactNative и отвечать за их качество, а также корректное поведение.

  3. Мы не приемлем fork-библиотеки и их дальнейшее развитие.

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

  5. ReactNative — еще в глубокой beta-версии и динамически изменяется. Между сменами версий не поддерживается принцип обратной совместимости и мы не можем быть уверены, что код нашей библиотеки корректно скомпилируется после выхода обновлений от Facebook.

  6. Мы хотим иметь «в запасе» нативный код, который потенциально позволяет использовать этот компонент в других проектах и даже вне концепции ReactNative.

       
Почему ReactNative?


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

  2. Позволять быстро переиспользовать уже разработанную ранее функциональность.

  3. Минимизировать затраты банка на разработку и поддержку приложений.

  4. Обеспечить быстрый time-to-market.

При анализе и выборе решения у нас было несколько выходных параметров и критериев:

  • большое количество legacy-систем в банке, разработанных для Web;

  • как следствие этого большое количество разработчиков с компетенциями в JavaScript;

  • развивающийся перспективный продукт для Web, использующий в своих принципах JS, React и Redux.

Так как одними из наших исходных задач были унификация стека разработки и минимизация затрат, мы приступили к подбору решения, позволяющего нам создавать мобильные приложение, используя JavaScript как язык для написания прикладного кода.
       
Cordova и PhoneGap быстро отпали, т.к. используя их, на выходе мы получаем не нативное приложение.
       
ReactNative же интерпретирует JS-код в objective-c вызовы в Runtime, что позволяет исполнять нативный код и строить интерфейсные формы из UIView-потомков.
       
ReactNative — это естественное продолжение React, что дает возможность нам писать унифицированный код, исполняющийся на мобильных приложениях и frontend-клиентах на десктопах.

       
Тестирование


Мы всегда тестируем то, что мы разрабатываем, ведь одно из обязательных качеств платформенных библиотек — это надежность.
       
Сейчас у нас есть автоматические Unit-тесты, которые запускаются при каждом PR и билде фреймворка.
       
Мы считаем необходимым тестировать отдельные компоненты и код демо-проекта руками.
       
В ближайшем будущем к ним присоединятся автоматизированные интеграционные тесты между модулями, UI-тесты и Performance-тесты для внедрения в бизнес-проекты.
       
Также в стратегических планах стоят: разработка своего фреймворка для написании кросс-кодовых тестов (JavaScript <-> objc-C) и статических анализаторов для анализа кода бизнес-проектов.

       
Автоматизация процессов


Мы автоматизируем то, что мы делаем. Сейчас у нас есть CI и CD для отдельных модулей платформы. У нас есть отдельная физическая билд-машина, подсоединенная к корпоративному Jenkins.
       
Запуск тестов, code coverage report, обновление показателей в dashing.io, сборка версии и публикация в nexus — только маленький перечень всех процессов, которые автоматизированы у нас на текущий момент.
       
Мы развиваем DevOps и планируем интегрировать CI/CD со всеми прикладными проектами, а также автоматизировать работу с службой поддержки, разбор инцидентов и многое другое.

       
Масштабирование


Сейчас мы работаем над глобальной архитектурой и принципами построения всех мобильных приложений в рамках ЕФС, использующих платформу.
       
Для возможности переиспользования между проектами, мы прорабатываем систему разделения прикладного кода и оформления в виде независимых JS Bundle. JS Bundle распространяются в виде npm-пакетов и подключаются в приложение на этапе компиляции.
       
Такой подход позволит создавать статические приложения и обновлять их через сборку. Это не решает проблемы: бизнес хочет видеть различные «наборы» из  JS Bundle в приложениях в зависимости от роли пользователя (продавцам один функционал, начальникам другой).Такую проблему можно решить либо созданием большого количества маленьких приложений по роли, либо включением всех JS Bundle в один бинарник.
       
К сожалению, в таком случае мы нарушаем наше требование к time-to-market, т.к. чем больше приложение, тем дольше регресс-тесты, направленные на выявление дефектов определенной версии.
       
Была предложена концепция динамической загрузки JS Bundle в мобильное приложение. Да, звучит очень клево и инновационно! Но это новая система, требующая разработки, прототипирования и пилотирования. На сегодняшний день в мире таких систем единицы (особенно для нативных приложений).
       
Проработку данной концепции мы начнем с R&D. Отличная возможность присоединиться к команде, если вам интересна такая амбициозная история :-)

       
Как мы работаем?


Наши команды разработки Мобильной платформы ЕФС работают по Agile-методологиям, используя Scrum-подход.
       
У нас двухнедельный delivery-цикл, а также все обязательные Scrum-артефакты: planning, stand-up, grooming, demo, retro.
       
Stand-up помогают нам актуализировать проблемы каждый день, а также делиться реализованным между всеми членами команды. Важно: мы не тратим больше 15 минут в день на stand-up и проводим их только стоя.
       
Мы регулярно переоцениваем наш бэклог и детализируем наши задачи — это помогает нам тратить меньше времени на планирование. А ретро и демо проходят у нас весело и инициативно (участвуем в конкурсах и номинациях, организованных нашим скрам-мастером).
       
Помимо процессов мы строго следим за технической стороной нашего продукта: пишем документацию, гайды, проводим консультации и оказываем помощь другим проектам.
       
Мы документируем свои процессы и подходы, чтобы не забывать их  и минимизировать активные дискуссии в следующий раз.
       
Новички не чувствуют себя потерянными, потому что мы сидим рядом, всегда выделяем наставника и имеем внутренние инструкции-шпаргалки.

       
Как узнать больше и присоединиться?


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

Еще вы можете посмотреть наши выступления



А если чувствуете в себе силы и желанием, мы приглашаем в команду амбициозных и талантливых  специалистов:

  • iOS-разработчиков (obj-c, ReactNative, VIPER, JS, SOA, Typhoon).
  • frontend-разработчиков (TypeScript, JavaScript, React, Redux).
  • дизайнеров и проектировщиков интерфейсов.
  • автоматизаторов и мобильных тестировщиков.

Пишите на почту Евгению Ртищеву ESRtishev.SBT@sberbank.ru или Островской Анастасии ASOstrovskaya.SBT@sberbank.ru

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

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


  1. Fortisa
    14.02.2017 22:32

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


    1. katleta
      14.02.2017 23:28
      +1

      Очень классная платформа, но хочется больше технических подробностей.

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

      Кстати, чем обусловлено то, что вы не приемлете fork-библиотеки?

      Мы начали разрабатывать на версии 0.33.0 (iOS), сейчас уже версия 0.41.0
      Версии меняются очень быстро — и мы бы не хотели каждый раз вносить изменения в нашу «копию» библиотеки.
      Как мы пытались показать в статье — мы стараемся не сильно зависеть от внутренностей ReactNative и используем только минимально необходимую часть для рендеринга компонентов и проброса вызовов из JS в obj-c.


  1. Subrisk
    14.02.2017 22:36

    А платформа всем доступна за плату или как там ещё? Или просто внутренней разработкой хвастаетесь? Хотелось бы подробно, про бекенд, фронтенд и особенно — поддержу приложения.


    1. katleta
      14.02.2017 23:25
      +1

      А платформа всем доступна за плату или как там ещё? Или просто внутренней разработкой хвастаетесь?

      На текущий момент платформа развивается indoors и используется внутри продуктов банка, но некоторые модули уже скоро попадут в outsource :)
      Уверен, что на эту тему будет отдельный анонс и пост.

      Хотелось бы подробно, про бекенд, фронтенд и особенно — поддержу приложения.

      Мы начинаем цикл статей и будем рассказывать конкретные детали различных аспектов. Спасибо за интерес!


  1. jehy
    15.02.2017 06:18

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


    1. katleta
      15.02.2017 09:08

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


  1. Bimawa
    15.02.2017 07:16

    Если вам так не подходит ReactNative, почему вы не выбрали тот же NativeScript, в вашем случае?


    1. katleta
      15.02.2017 09:12

      1. Мы не говорим, что нам не подходит ReactNative. Именно он и подходит. Мы говорим, что мы хотим минимизировать риски, которые мы видим в использовании ReactNative.
      2. Мы выбрали ReactNative, потому что он является естественным продолжением фреймворка React от того же разработчика. Кроме мобильной платформы есть на текущий момент и web-платформа, написанная на стеке TypeScript, React + Redux. Одной из важной задач мобильной платформы — это унификация API и компонентов с web-платформой, так чтобы можно было создать единую платформу для сборки мобильных и web приложений.


      1. Bimawa
        15.02.2017 09:29

        ясно, т.е. вы взяли бридж реакта и под себя его кастомайзити?


        1. katleta
          15.02.2017 10:21

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


  1. Amati
    15.02.2017 07:36

    И всё таки… Вы конструктор моб. приложений делаете?


    1. katleta
      15.02.2017 09:19

      Платформа — это многомодульная система.
      Например, в неё входят:
      — мобильная библиотека (которая встраивается в мобильные приложения)
      — модуль платформу на backend'e
      — различные шлюзы (из-за богатой внутренней инфраструктуры)
      — инструменты DevOps
      — методологии и инструменты тестирования
      — средства для сбора мобильной аналитики и логов
      и т.д.

      Мобильная библиотека — это конструктор приложений в некотором роде, т.к. она основана на принципах разбиения всей функциональности на некоторые блоки — компоненты.
      Компоненты бывают визуальными (кнопки, чекбоксы, прогресс-бар, загрузчики, карты и т.д.), из которых выстраивается интерфейс и не визуальными или сервисами (логирование, работа с сетью, удаленное управление и т.д.).
      Прикладной разработчик бизнес-проекта уже в итоге на TypeScript (JavaScript) быстро собирает мобильное приложение как из кубиков, используя готовые компоненты.


  1. 23derevo
    15.02.2017 17:27
    +1

    Тот факт, что в посте нет слов «СберБанк» и «СберТех» — это задумка такая или продолб?


    1. katleta
      15.02.2017 17:55

      ESRtishev.SBT@sberbank.ru )


      1. 23derevo
        15.02.2017 18:47

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


        1. katleta
          15.02.2017 18:56

          Спасибо за ценный фидбек, возьмем на заметку!


  1. freerider77
    15.02.2017 17:57

    Спасибо за статью, очень интересно! Люблю React Native :)
    А вы в каком банке реализуете платформу?


    1. katleta
      15.02.2017 18:06

      Отвечу намёком :) ESRtishev.SBT@sberbank.ru


  1. Chika
    15.02.2017 20:01

    Спасибо за статью, уже не первая в которой хвалят React Native.

    Недавно читал статью, как разработчики Artsy перешли с Objective-C на Swift, потом на React Native. Подробнее можете прочитать вот здесь. Как понял это не для каждого проекта. Как и всегда есть свои плюсы и минусы. Понравилось, что можно сложные вещи писать на нативном коде Objective-C/Swift и потом интегрировать с React Native. Раньше если у них iOS разработчики были отдельной «эко» системой, то сейчас веб разработчики могут вносить свою помощь.


    1. katleta
      15.02.2017 22:18

      Спасибо за ссылку. Как раз на этой неделе она была в рассылке от iOS Good Reads


  1. unel
    15.02.2017 20:05

    Спасибо за интересную информацию! Хорошо, что хоть кто-то начал задумываться о том, что react в какой-то момент может захотеться поменять…


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


    Интересны следующие нюансы:


    • как связываете отображение на react со стейтом в redux, есть ли между ними какая-то прослойка, позволяющая заменить только react или только redux, например?
    • как связываете отображение на react и контроллер (ну или ту сущность, которая решает, как менять модель в зависимости от действий пользователя / каких-то внешних действий (тик таймера, например))


    1. katleta
      15.02.2017 22:38

      Хорошие вопросы. Постараюсь ответить подробно.

      как связываете отображение на react со стейтом в redux, есть ли между ними какая-то прослойка, позволяющая заменить только react или только redux, например?

      Мы делаем наши компоненты stateless на нативном уровне, точнее как мы сами ввели термин valueless.
      То есть компонент внутри себя не может изменить значение.
      Значения в компонент задаются с уровня JS. А на уровне JS хранятся в redux store.

      Давайте на примере компонента TextInput (можете посмотреть видео-материал, там есть этот пример).
      На уровне JS TextInput — это React.Component. Когда мы используем его внутри нашего кода мы пишем что-то вида:

      <TextInput text=''/>
      

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

      onChange = text => this.setState({text})
      ...
      <TextInput text=this.state.text onChange={this.onChange}/>
      


      Мы возвращаем новое значение введенного текста, сохраняем его в JS и обновляем свойство text у компонента.
      Т.е. методология React не нарушается — мы храним значения для наших компонентов не внутри них самих.

      как связываете отображение на react и контроллер (ну или ту сущность, которая решает, как менять модель в зависимости от действий пользователя / каких-то внешних действий (тик таймера, например))

      Изменения интерфейса также происходят согласно правилам React, например, при изменении state, props или context.


    1. Rag0n
      15.02.2017 23:26

      Компонент связывается с redux-стором посредством стандартных биндингов входящих в пакет react-redux, т.е используется Provider и connect.

      Компонент — это чистая функция. При изменении стейта React обновляет virtual dom, если параметры компонента(т.е функции) изменились — React Native пробрасывает измененные параметры на нативный уровень(bridge level).

      Bridge level конвертирует полученный JSON в нативные типы данных и вызывает соответствующие методы презентера. Презентер смотрит на то, что ему пришло и в каком состоянии он находится. И на основе этого обновляет UIView. UIView состояния не имеет и все свои события пробрасывает в презентер. От презентера опять попадаем в bridge level, React Native пробрасывает события из нативного уровня на уровень JS.


      1. unel
        16.02.2017 12:27

        Презентер смотрит на то, что ему пришло и в каком состоянии он находится

        вот тут хотелось бы поподробней: presenter — это уже какая-то сущность в нативном коде или в js-коде? Получается весь viper-подход содержится только в нативной части и никак не распространяется на разные части js-кода (отображение, хранение данных)?


        1. Rag0n
          16.02.2017 12:59

          Presenter — это сущность в нативном коде. Да, весь viper-подход содержится только в нативной части. На уровне JS-кода разработка идет согласно архитектуре redux.

          Т.е типичный компонент это:
          1) один js-файл, в котором импортируется нативная UIView и объявляется React.Component, который возвращает эту вью в своем рендер методе.
          2) ViewManager: RCTViewManager — синглтон, который создает UIView и передает параметры в presenter. Его использует React Native.
          3) Presenter: NSObject
          4) View: UIView
          5) Interactor: NSObject
          6) Иногда Wireframe: NSObject

          Все кроме пункта 1 — это нативный код. Единственная часть которая зависит от React Native в нативном коде — это пункт 2


          1. unel
            16.02.2017 13:05

            Ага, т.е. если и предполагается выкинуть react native, то вместе с накопленной частью на redux?
            А если планируется отказаться от redux, но оставить react-native — насколько это будет безболезненно?


            1. Rag0n
              16.02.2017 13:34

              Можно посмотреть с двух сторон:
              1) Со стороны мобильной платформы
              2) Со стороны проектов которые используют мобильную платформу

              Со стороны мобильной платформы отказаться от redux и оставить react-native — просто. Мы от него почти не зависим и получается в нативном коде изменений не будет.

              Со стороны проектов отказаться от redux и оставить react-native уже сложнее. Потребуется вносить изменения в js-код. Количество изменений зависит от того, на какой фреймворк/архитектуру мы переходим(mobx/relay/...).

              Со стороны мобильной платформы выкинуть react native — это значит написать свою обертку над фреймворком JavaScriptCore, которая возьмет обязанности React native на себя. Т.е появится слой, который будет получать JSON из уровня JS-кода и что-то на его основе делать с нативным кодом. И наоборот — на основе событий нативного уровня будет отправлять JSON на уровень JS. На самом нативном коде будет минимум изменений.
              Но при этом сам нативный код можно переиспользовать в проектах в которых нет React Native.

              Со стороны проектов выкинуть react-native(но оставить react) — это в принципе тоже самое что и со стороны платформы, т.е нужно будет написать свой механизм взаимодействия JS <-> Objective-C. Но при этом проект продолжит работать в вебе, потеряем только мобильное приложение.


              1. unel
                17.02.2017 12:35

                Со стороны проектов отказаться от redux и оставить react-native уже сложнее. Потребуется вносить изменения в js-код. Количество изменений зависит от того, на какой фреймворк/архитектуру мы переходим(mobx/relay/...).

                И вот тут не возникало мысли так же применить какой-нибудь из упомянутых подходов, чтобы избежать завязки на конкретную модель хранения / изменения данных? Или это бы наоборот всё усложнило?


                1. Rag0n
                  18.02.2017 12:01

                  Всегда ведь будет какая-то конкретная модель хранения / изменения данных. Либо общеиспользуемые подходы redux/mobx/relay и тд, либо что-то свое. Но чтобы был смысл писать свое решение — оно должно решать какие-то проблемы. Видимо пока таких проблем нету.


  1. Fanruten
    16.02.2017 12:04

    Классная статья, спасибо.

    Появилось несколько вопросов:
    1. Разве за time to market отвечают выбранные технологии (в данном случае React), а не Agile?
    2. Как у вас с поиском разработчиков знающих JS и Obj-C?


    1. katleta
      16.02.2017 15:45

      Руслан, привет!

      1. Согласен. В первую очередь помогает короткий итерационный цикл итерации, тестирование и выпуска.
      А автоматизация всего этого — DevOps.
      И в одну из технических задач входит CI/CD модулей платформы и прикладных проектов, использующих их.

      2. На разработку внутри платформы мы ищем людей, знающих Оbj-C. JS мы обучаем в процессе.
      Я бы даже добавил, что при при написании компонентов куда важнее понимание принципов React и Redux.