Досвід компанії, яка обрала React Native

19 хв. читання

У середині 2019 року мобільну реєстрацію в застосунку Coinbase повністю переписали на React Native. Чому? Причин у такого рішення було декілька.

Перша: Coinbase зараз підтримує понад 100 країн. Оскільки в кожної з них є свої юридичні особливості та вимоги (наприклад: Знай свого клієнта (Know your customer), Заборона відмивання грошей), реєстрація користувачів повинна бути адаптованою.

На жаль, саме реєстрація була найстарішою та найскладнішою частиною застосунків Coinbase. Тож навіть поступові зміни було б складно реалізувати. Аби організувати підтримку більшої кількості країн швидше (та безпечніше), потрібно було зробити реєстрацію більш надійною. До того ж у компанії вирішили, що написати цю частину заново буде значно швидше, аніж рефакторити вже наявну кодову базу.

Друга: Як ми вже згадували, в послідовності реєстрації застосунку було багато бізнес-логіки. Якщо переписати вже наявний код нативними мовами програмування — з'явилося би багато повторюваного коду, а підтримка застосунків і для IOS, і для Android була б затратною. Однак, якщо реалізувати потрібний модуль на React Native, можна підтримувати декілька платформ одночасно. Це дозволило б повторно використати більшість (якщо не всю) бізнес-логіку застосунку та впевнитись у постійності поведінки всіх застосунків.

Третя: Спочатку мобільні застосунки Coinbase були повністю нативними, а весь Coinbase Pro був написаний на React Native. У компанії хотіли поширити новий досвід реєстрації між обома продуктами. Тож очікувалося, що інтеграція пакета React Native була б менш вартісною, аніж вбудування нативних модулів.

Рішення було успішним і дало можливість зробити досвід однаковим на декількох платформах. Як наслідок, команда стала працювати швидше.

Розробники Coinbase впевнені, що обрати React Native було правильно. Команда з п'яти інженерів переписала модуль реєстрації з нуля та доставила його у продукти Coinbase та Coinbase Pro на iOS (зараз команда працює над підтримкою для Android).

Зрештою, інженери Coinbase вирішили поділитися своїм досвідом, важливими моментами та особливостями роботи з React Native.

Переваги

Якщо говорити стисло, то основна переваги React Native — це швидкість. В середньому команда витрачала менше часу на ознайомлення інженерів, доставляла більше коду (є сподівання, що це збільшуватиме продуктивність надалі) та нових фіч, якщо порівнювати з нативними мовами. Команді вдалося поєднати цей процес з підтримкою високої якості, тож в Coinbase сподіваються, що кінцевий продукт не відрізнятиметься від повністю нативних застосунків.

Таким перемогам посприяло багато факторів, в наступних частинах ми поговоримо про найважливіші з них.

Компоненти

Компоненти — це компоновані JavaScript-функції, які приймають незмінювані параметри (називаються props) та повертають елементи React, які описують що повинно бути на екрані. Це фундаментальні блоки будь-якого застосунку на React. Використання компонентів допомагає інженерам розбити користувацький інтерфейс на незалежні та повторно використовувані частини.

Для переписування реєстрації в застосунку команда заздалегідь створила набір компонентів форм (кнопки, поля вводу), текстові елементи (заголовки, абзаци тексту), елементи розмітки (екрани, розділювачі) та складніші UI-елементи (компоненти для вибору дати, індикатори прогресу, модальні вікна). За винятком компоненту для введення дати, все було написано на TypeScript.

Більшість основних компонентів створили на початкових етапах роботи над проєктом. Такі повторно використовувані елементи допомогли інженерам швидше створювати інтерфейс, адже розмітка стала більш декларативною. Наприклад, кнопки нижче створюють екран перевірки номера телефону:

const config = {
  name: 'PhoneScreen',
  formShape: { phoneNumber: '', countryCode: 'US' },
  optionsShape: { analytics: {} },
};
export default createScreen(config, ({ Form, isLoading, options }) => {
  const { phoneNumber, countryCode } = useFields(Form);
  const [submit, isSubmittable] = useSubmitter(Form);
  return (
    <AnalyticsContext.Provider value={options.analytics}>
      <Screen>
        <Header>
          Set up 2-step verification
        </Header>
        <Paragraph type="muted">
          Enter your phone number so we can text you an authentication code.
        </Paragraph>
        <PhoneInput
          {...phoneNumber}
          countryCodeValue={countryCode.value}
          label="Phone"
          keyboardType="phone-pad"
          onCountryCodeChange={countryCode.onChange}
          placeholder="Your phone number"
          returnKeyType="done"
          validators={[
            [required, 'Phone number is a required field.'],
            [phoneNumberValidator, 'Please enter a valid phone number.'],
          ]}
        />
        <Spacer />
        <Button
          disabled={!isSubmittable}
          isLoading={isLoading}
          name="continue"
          onPress={submit}
          >
          Continue
        </Button>
      </Screen>
    </AnalyticsContext.Provider>
  )
});

Кожен компонент з самого початку створили так, аби його стильова тема могла змінюватись. Це допомогло інженерам підлаштуватись до дизайн-системи. Постійність кольорів, розмірів відступів в компонентах по всьому застосунку легко досягається за допомогою провайдера тем.

До того ж інкапсуляція компонентів часто дозволяла розпаралелювати роботу інженерів над різноманітними частинами застосунку. Це неабияк посприяло ефективності розробки.

Швидке оновлення

Швидке оновлення — це фіча React Native, яка дозволяє розробникам майже миттєво бачити результат змін у React-компонентах. Коли файл TypeScript змінюється, Metro генерує пакет JavaScript (для поступових збірок це триває менше ніж секунду), а емулятор або тестовий девайс автоматично оновлює свій інтерфейс відповідно до останніх змін.

Зазвичай можна зберегти повний стан застосунку. Та коли змінюються залежності поза деревом React, замість швидкого оновлення відбудеться повне перезавантаження. Коли ж справа доходить до повного перезавантаження, застосунок втрачає більшу частину свого стану, однак розробник все одно може побачити результат внесених змін майже одразу.

Швидке оновлення значно збільшує продуктивність при створенні основних компонентів та екранів, оскільки зазвичай зміни стосуються візуальних елементів і мають повторюваний характер.

З досвіду компанії, швидке оновлення також стало в пригоді при роботі з API, оскільки інженери змогли налаштувати API-клієнт та виконати мережеві запити без необхідності конфігурувати стан застосунку (наприклад, маркери доступу, дані форм) після кожної зміни.

Навіть коли збереження стану користувацького інтерфейсу було не особливо важливим (наприклад, при роботі над бізнес-логікою всередині фреймворку), можливість вручну тестувати код за секунди є величезним плюсом для продуктивності, оскільки розробники не сидять в очікуванні компілятора.

Крива навчання для інженерів React/Веб

Існує декілька помітних відмінностей між написанням React-коду для мобільних та вебзастосунків.

  • Примітивні елементи різні. Наприклад, у React Native використовуються елементи View та Text, а от вебінженери використовують div чи span.
  • На відміну від CSS, стилі елементів у React Native не каскадні. Наприклад, якщо ви вкажете font-family для кореневого компонента, то ця властивість не застосується до його дочірніх елементів.
  • React Native часто потребує в інженерів деякі знання нативних інструментів розробки мобільних застосунків — на зразок XCode та Android Studio. Навіть якщо використовувати сторонню бібліотеку, яка не потребує Objective-C, інженер іноді повинен змінити дозволи в plist-файлі.
  • Мобільні девайси мають фічі, обмеження та особливості, яких можуть не знати вебінженери. Наприклад, логіка повторення запитів під час поганого з'єднання складніша для мобільних застосунків.

З досвіду Coinbase, більшість описаних аспектів легко засвоюються вебінженерами. Враховуючи, що основна частина логіки реєстрації була написана на TypeScript (тобто лише невелика частина застосунку потребувала нативного коду), це суттєво сприяло швидкості.

Варто помітити, що глибоке ознайомлення з нативним середовищем — найскладніша частина переходу від вебзастосунків до React Native. Це також причина, чому так потрібно мати інженерів з нативної мобільної розробки в команді React Native.

Спільний код

iOS + Android

Основна частина реєстрації в застосунку Coinbase була написана на TypeScript, який функціонує на пристроях iOS і Android «з коробки». Хоча є і виняток, оскільки необхідно написати власний нативний модуль, аби отримати переваги від нативного календаря iOS. Навіть з урахуванням таких додаткових зусиль, команда очікує на переваги у швидкості від спільного коду в 95%. Тож деякі додаткові налаштування для нативних платформ цілком виправдовують себе.

Coinbase + Coinbase Pro

Команда Coinbase випустила нові екрани реєстрації та внутрішній NPM-пакет, який зараз використовується застосунком Coinbase на Swift та Coinbase Pro для iOS, що повністю написаний на React Native. Додати підтримку до Coinbase Pro можна приблизно за два тижні.

Більшість зусиль йде на дослідження підтримки greenfield та brownfield реалізацій React Native, а також на абстрагування логіки автентифікації (тобто надання та оновлення токенів доступу). Як і з підтримкою iOS і Android, команда сподівається, що зусилля, витрачені на підтримку спільного коду для реєстрації в Coinbase та Coinbase Pro, вартуватимуть того.

React Native + Web

В Coinbase є певна кількість внутрішніх бібліотек, які команда використовує у своєму вебстеку. Тому з React Native команда змогла отримати від власних інструментів користь. Особливо доречною виявилась внутрішня бібліотека, яку створили для управління станом форм, валідації та відправлення даних.

Оскільки згадані бібліотеки були важливою частиною проєкту, команда змогла використовувати їх з мінімальними змінами, а також застосовувати їх як у вебі, так і на мобільній платформі. Тож React Native та веб можуть спільно використовувати будь-який код, який:

  1. можна виділити в NPM-пакет;
  2. не зв'язаний тісно з примітивними елементами UI (такими як div, View). Наприклад, це можуть бути API-клієнти, модулі локалізації та утиліти (на зразок парсерів адрес, форматерів валют тощо).

TypeScript

TypeScript — це типізована мова програмування, що компілюється в JavaScript. Її часто застосовують для розробки застосунків на React Native і вона має потужність, подібну до Swift та Kotlin.

Хоч TypeScript і має не дуже низький поріг входження, ускладнює написання коду (у порівнянні з ванільним JavaScript), та переваги в безпеці, фічі IDE й підтримка коду варті того. Без типізованої абстракції над JavaScript більшість змін рівня фреймворку, потрібні в проєкті, були б набагато складнішими та схильними до помилок. Якщо врахувати, що випуск оновлень у мобільних застосунках повільніший, ніж у вебі, типізована мова додає впевненості.

Труднощі

Хоч загалом досвід використання React Native був позитивним, не обійшлося й без труднощів. В наступних частинах ми поговоримо про проблеми, які спіткали команду, про криву навчання React-Native для нативних мобільних розробників, труднощі націлювання на кілька платформ та про проблеми, які приносять нові технології.

Крива навчання для інженерів нативної мобільної розробки

React Native побудований на безлічі технологій. TypeScript транспілюється у JavaScript з Babel, потім Metro (подібно до Webpack) займається збіркою застосунку. Відкомпільований JavaScript взаємодіє з React Native API, який працює з Objective-C чи Java.

React Native також пропонує глобальні змінні для створення поліфілів функціоналу, який очікується від сучасних браузерів (на зразок fetch чи FormData). Більшість коду застосунку написано на React з використанням TSX. Розробники можуть натрапити на посібники, де використовуються компоненти класу, що інтегруються з Redux, однак спільнота рекомендує переходити на функціональні компоненти, хуки та контекст.

Лінтери (на зразок TSLint/ESLint) та форматери (типу Prettier) мають свої правила організації коду. Команда використовує Jest для модульних тестів, а Detox для E2E-тестів. В майбутньому, можливо, додадуть Enzyme. Більшість часу розробники застосовують VSCode, термінал та налагоджувач на свій вибір (наприклад, Chrome dev tools, Reactotron).

Вебінженери, імовірно, знайомі з переліком технологій вище, тож поріг входження в React Native для них досить низький. Інженери нативної розробки, як правило, не обізнані з цим стеком, тому для них бар'єр вищий. Вони не просто опановують нову мову. Вони вивчають метамову, яка транспілюється в іншу нову мову, використовуючи нові інструменти збірки, нову бібліотеку (React), з новими парадигмами, новий фреймворк (React Native) та нову екосистему. Все це виникло в результаті тривалої еволюції JavaScript.

Модульна природа також ускладнює перехід нативних інженерів на React Native. У нативній розробці використовують потужні IDE (XCode, Android Studio), які беруть на себе більшість складної роботи з управління локальним середовищем. Натомість розробка на React Native часто потребує самостійних налаштувань: встановлення залежностей, запуск сервера з командного рядка, налаштування збірки та скриптів, конфігурації сторонніх налагоджувачів.

І останнє: гіганти на кшталт Apple i Google підтримують багато інструментів та пропонують кращі практики для нативної розробки, а от екосистема React Native не має явного лідера. Хоч в такій децентралізації можна знайти свої переваги, новачків вона може заплутувати.

Часто немає єдиного джерела істини, на яке можна було б покластися, тому інженери вимушені звертатися до різних ресурсів (документації GitHub, статей на Medium, обговорень на StackOverflow, сирцевого коду). Інформація звідти буває суперечливою чи застарілою, оскільки екосистема JavaScript змінюється швидко.

Можливі майбутні покращення

  • Створити власні інструменти, щоб покращити досвід локальної розробки для нативних розробників.
  • Організувати співпрацю вебінженерів та інженерів нативної мобільної розробки для роботи з React Native.
  • Підтримувати власну бібліотеку, в якій зібрати найкращі актуальні практики для створення застосунків React Native в Coinbase, додати посібники, порадники тощо.
  • Команда React Native також постійно працює над оновленням документації, аби бути більш привітною для інженерів різних платформ.

Нативна взаємодія

Іноді застосунку необхідний доступ до API платформи, для якої React Native не має поки відповідного модуля. Або певна фіча буде продуктивнішою лише з нативним кодом. Для подібних сценаріїв React Native пропонує нативні модулі, які дозволяють JavaScript делегувати завдання на користувацький нативний код.

При розробці екранів реєстрації розробники не помічали в Coinbase згаданих проблем продуктивності, які не можна було б розв'язати за допомогою чистого JavaScript. Однак команда мусила написати власний компонент для вибору дати, використовуючи нативний модуль, оскільки хотілось, аби цей компонент не відрізнявся від традиційного UIDatePicker в iOS. Компонент успішно створили, але досвід розробки був далекий від ідеального з декількох причин:

  • Якщо нативні модулі можна написати на Swift та Kotlin, то React Native автоматично підтримує лише Objective-C та Java. До того ж нативні модулі необхідно експортувати, використовуючи набір макросів, запропонованих React Native. З Objective-C (команда не ставила в пріоритет підтримку Swift) та макросами написання коду для нативних модулів може бути трохи незручним.
  • Основні компоненти React Native (на зразок TextInput) не надто легко розширюються за допомогою нативного коду. Якщо потрібно, щоб компонент поводився подібно до нативного, може знадобитись переробити функціонал, який зазвичай вже готовий в нативних компонентах. Прикладом функціоналу може бути активація фокусу для користувацьких інпутів.
  • Зміни в користувацьких нативних модулях потребують повторної збірки, що мало відрізняється від розробки в нативних застосунках. Як наслідок, інженери, котрі працюють над нативним кодом, не відчують ніякого пришвидшення.
  • Дані, що відправляються, долаючи «міст» між JavaScript та нативним кодом, не типізовані, тому з обох боків необхідно забезпечити обробку типів.

Можливі майбутні покращення

  • З'явиться підтримка Swift і Kotlin для нативних модулів.
  • Для постійних проблем (наприклад, обробки фокусу полів вводу, які базуються на користувацьких нативних модулях) з'являться легкі бібліотеки, що стандартизують та абстрагують поширену поведінку.
  • Підтримка пісочниці для прискорення збірки при написанні нативних модулів.
  • Описання нативних API з JSON та використання інструменту на зразок quicktype для генерації типів для TypeScript, Swift та Kotlin. Це має спростити синхронізацію типів у JavaScript та нативних мовах мобільної розробки.
  • Вийдуть фічі React Native на зразок CodeGen, які суттєво змінять принцип роботи нативних модулів та усунуть багато проблем.

Відмінності платформ

Хоча більшість TypeScript-коду працює на обох платформах з коробки, існують деякі поведінкові/стильові невідповідності між фундаментальними UI-компонентами на iOS vs Android. Більшість відмінностей згадуються в документації React Native, однак можуть траплятися й нові, якщо інженери недостатньо тестують обидві платформи.

React Native пропонує два зручних варіанти для реалізації поведінки, особливої для певної платформи, де це необхідно (модуль Platform та особливі для платформи розширення файлів). Однак з таким підходом ми ще більше розмежовуємо різні платформи.

Можливі майбутні покращення

  • У Coinbase намагатимуться забезпечити кожну команду React Native хоча б одним інженером нативної мобільної платформи з кожної платформи (iOS, Android). Такі інженери, найімовірніше, краще розумітимуть, чи є поведінка очікуваною, коли справа доходить до специфічних для платформи компонентів.
  • Підтримуватимуться ретельні інтеграційні та E2E-тести, якими перевірятимуться обидві платформи, перш ніж код потрапить у master. Так можна передбачити залежні від платформи дефекти, які не помітили розробники.
  • Зробити необхідними скріншоти та/або гіф-зображення для пул-запитів нових фіч на iOS та Android, аби забезпечити мануальне тестування на обох платформах.
  • Використовувати фреймворк для автоматизованого візуального тестування, аби передбачити неочікувані зміни інтерфейсу.

Налагодження

Команду здивувало, що налагоджувачі React Native не обов'язково аналізують JavaScript в тому ж рушії, що й емулятор/девайс. На пристроях iOS React Native запускається на JavaScriptCore, а на Android — на Hermes. Коли ж режим налагодження увімкнено, виконання JavaScript делегується налагоджувачу. Якщо налагоджувати через Chrome dev tools, то JavaScript аналізується рушієм V8 у вебконтексті, а не JavaScriptCore чи Hermes в нативному контексті.

В теорії ці всі рушії мають поводитись однаково, адже вони слідують специфікації EcmaScript. Однак команда розробників не раз помічала помилки, які з'являлись несподівано, а потім зникали при спробах дослідити їх уважніше.

Після довгих тестувань команда з'ясувала, що баги з'являються, лише коли налагодження вимкнено. Основна причина проблем була в тому, що глобальні змінні (зокрема, функція fetch і об'єкт Date) поводились трохи по-різному. Це залежало від того, який рушій запускає код. Інші команди також наводили різні характеристики продуктивності, залежні від роботи налагоджувача.

Варто зазначити, що більшість коду на JavaScript поводиться однаково, незалежно від налагодження. Ба більше, тепер, коли команда знає про можливі проблеми в режимі налагодження, надалі їх буде значно легше ідентифікувати.

Можливі майбутні покращення

  • Рекомендувати новим інженерам покладатися переважно на дебагери на зразок Reactotron чи Safari dev tools (які аналізують JavaScript, використовуючи рушій девайса/емулятора).
  • Рекомендувати новим інженерам обирати налагоджувач на свій смак, однак повідомляти про проблеми, що стосуються рушія, аби було простіше ідентифікувати категорію проблеми.
  • Підтримувати ретельний набір інтеграційних/E2E-тестів, які повинні підходити для емуляторів iOS і Android , перш ніж код комітиться в master. Такий крок може допомогти переконатися, що баги не спричинені відмінностями між рушіями на емуляторі/девайсі та налагоджувачі.

Що далі

Загалом команда Coinbase отримала позитивний досвід роботи з React Native. Повторне використання компонентів, швидке оновлення, легкість процесу для вебінженерів — все це допомогло пришвидшити проєкт. Оскільки команда рухається динамічно, модульні та E2E-тести повинні дбати про безпеку. Також зазначимо, що не виникало проблем продуктивності, які розробники не могли розв'язати за допомогою самого лише JavaScript.

Тож в Coinbase і надалі планують працювати з React Native, зосереджуючись на досвіді розробників, засвоєнні й адаптації.

Досвід розробників

Хоч команда була задоволена React Native, не обійшлося і без незручностей, особливо для інженерів, які прийшли з нативної розробки. Наприклад, робота над застосунком на React Native потребує встановлення та конфігурування декількох системних залежностей (тобто Homebrew, Node, Yarn, Ruby, Bundler, XCode, XCode Commandline Tools, XCodeGen, OpenJDK, Android Studio, Watchman, React Native CLI, TypeScript), синхронізації NPM-пакетів (JavaScript та native) і ресурсів (наприклад, шрифтів), управління локальним сервером Metro з емуляторами та з'єднання з автономним налагоджувачем.

Засвоєння та адаптація

React Native — це потужна технологія, яку веброзробники легко засвоюють. Однак всю її міць можна осягнути, лише якщо глибоко розуміти платформи iOS та Android — тож потрібен кількарічний досід мобільної розробки. Саме тому в Coinbase усіляко залучають нативних розробників для застосунків з React Native.

Як ми вже згадували, нативним інженерам засвоїти фреймворк складніше. Окрім самого React Native, їм необхідно ознайомитись ще з кількома рівнями технологій з вебекосистеми. Якщо ваша команда думає про використання React Native, зробіть все необхідне, аби нативні інженери отримали потрібні знання для розробки. Можливо, вам треба буде створити спеціальні посібники, чітко визначити найкращі практики, методи боротьби з певними багами та помилками, регулярно залучати веброзробників для допомоги, а також формувати власні інструменти, що спростять процес розробки.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація