実践 React Native 設計チェックシート

=== 2020/12/01 追記 === 
続きを [実践 React Native 運用チェックシート](https://qiita.com/shoken/items/23bba5b288b4a23f4c1f) に書きました。
=== 追記終わり ===

この記事は[React Native Advent Calendar 2019](https://qiita.com/advent-calendar/2019/react-native)の1日目の記事です。

キッチハイクのアプリはReact Nativeで開発を始め、3年ほど経ちました。初期リリース時には自動テストもなく、Firebaseライブラリも限定的に使うだけでした。プロダクションにリリースし、ノウハウが溜まってきて、いまReact Nativeで開発するならここを抑えておくぞ、というポイントをまとめたいと思います。

この記事では、これからReact Native でアプリ開発を始める方をメインの対象としていますが、すでに開発中の方にもメリットがあればと思います。キッチハイクアプリも最初から全てを入れていた訳ではなく、まだまだ導入したいライブラリや仕組みは多いです。

# そのアプリ開発に React Native が最適か？

キッチハイクチームがアプリ開発ツールとしてReact Nativeに着目した理由は、アプリネイティブ開発者がチームにいないことでした。そこでまずは手始めにReactをRailsに入れることから始めます。それが2016年10月頃です。そこで手応えを掴んだことをきっかけにアプリをReact Nativeで開発することが決定しました。

これまで3年開発を続けた上で、当時を振り返りながらアプリ開発にReact Nativeを選ぶためのチェックポイントを考えてみました。当時は Xamarin や Flutter などの他のクロスプラットフォーム開発ツールはメジャーになっておらず、ネイティブ開発（Swift / Android）かReact Nativeかという視点でした。

キッチハイクアプリの開発には以下の3つの特徴がありました。

1. Webエンジニアのチーム
2. アプリはView開発がメイン
3. ネイティブ機能への強い依存がない

## 1. Webエンジニアのチーム

当時のキッチハイクチームにはRailsエンジニアが多くWebアプリケーション開発が中心でした。アプリ開発の企画は数年前からあったものの、専任のエンジニアがなかなか見つからず、Railsエンジニアが挑戦するかどうか、機会を伺っていました。
React Nativeでのアプリ開発に着手する前に、ReactをRailsに入れてみました。Reactの設計思想を使えるReact Nativeでの開発はWeb開発が長いキッチハイクチームには魅力的でした。

一方で、コンポーネントの共通化は思ったよりも難しいという印象でした。

### コラム: Reactの思想

Reactは関数型プログラミングの思想、とりわけimmutabilityを大事にしているフレームワークだと感じます。この点も、React Nativeを取り入れた理由の一つです。Ruby / Railsとは別の設計思想に触れることにより、開発チームに奥行きを持たせたかったという思いがあります。

 開発開始から3年、 React の思想である "Learn Once, Write Anywhere" はキッチハイクチームでは上手くワークしていると思います。

## 2. アプリはView開発がメイン

キッチハイクはWebアプリがすでにあったこともあり、ビジネスロジックはAPI側に持たせて、薄いViewとしてアプリを開発する方針にしました。原則として、View表示に必要なデータは全てAPIが返して、Viewはデータをレイアウトすることに注力します。React Nativeでの開発はこの設計方針にマッチしました。

### コラム: View開発の効率性

React Nativeはビルドを必要とせずにUI変更をシミュレーターに反映できるHotリロード機能があります。
また、Xcodeのストーリーボードではなく、Webでの知識をほぼそのまま使えるCSS styleと合わせて、UIの微調整は効率よく行うことができます。

## 3. ネイティブ機能への強い依存がない

ネイティブ機能（マルチカメラやジャイロセンサーなど）への要件がないことも重要でした。

### コラム: ネイティブ機能の要件と expo or Not?

React Native での開発を選択したとして、次に expo を使うかどうかという検討があります。いくつか検討事項があるのですが、ポイントは expo がサポートしていないサードパーティSDKの要件があるかどうか、でしょうか。例: Repro, AppsFlyer, Adjust

expo については弊社テックブログですが、下記も参考になるかと思います。

[React Native \+ Expoで1年以上運用したCTOが集まってみた 前編 \- KitchHike Tech Blog](https://tech.kitchhike.com/entry/react-native-expo-session-01)
[React Native \+ Expoで1年以上運用したCTOが集まってみた 後編 \- KitchHike Tech Blog](https://tech.kitchhike.com/entry/react-native-expo-session-02)

--------

ここまではチームがReact Nativeかそれ以外か、についての考慮ポイントを紹介しました。上記はキッチハイクチームの一例ですが、参考にしてもらえると嬉しいです。

ここからはReact Nativeでの開発を始めるに当たって、どのようなポイントで意思決定をしていくかを解説します。

# React Native 主要アーキテクチャ選定

## UIコンポーネント設計

多くの入門記事でも話題になるように、React NaitveではUIコンポーネントライブラリの選択肢がいくつかあります。Web開発でいうところのBootstrapで、コンポーネントにスタイルを自動で提供してくれるライブラリです。主なものを表にまとめました。

ライブラリ | star数
----|----
[React Native Elements](https://react-native-elements.github.io/react-native-elements/) | 17,619
[NativeBase](https://nativebase.io/) | 13,040
[RN Material Kit](http://xinthink.github.io/react-native-material-kit/) | 4,513
[React Native Material UI](https://github.com/xotahal/react-native-material-ui) | 3,176

star数は2019年12月1日現在

### キッチハイクでは？

キッチハイクでは検討した結果、ライブラリを導入せずにスクラッチからStyleを書いていくことにしました。背景にはRails開発でのBootstrapがあります。初期リリース時にはBootstrap導入にメリットがありましたが、長く開発を続けていくうちにカスタマイズにコストがかかったり、いざBootstapをやめようとしても影響範囲の把握が難しかったりします。そういった過去の開発経験から、アプリ開発では必要になるまではライブラリの導入はしないで開発を進めることにしました。結果、3年経ったいまも導入はしていません。

## 状態管理設計

React Nativeでの設計ポイントに状態管理があります。ここ数年でReactの開発が進み、状況が変わってきた箇所の一つです。現状での選択肢は大きくは、

1. Function Component + React 標準API（ Hooks, Context API )
2. Reduxなどのライブラリを導入

の2つがあります。もしライブラリの導入を検討する場合、国内の情報が多いのはRedux, MobXでしょうか。ReactのContext API ベースに作成されている Unstated も検討できそうです。

ライブラリ | star数
----|----
[Redux](https://redux.js.org/) | 51,537
[MobX](https://mobx.js.org/README.html) | 20,928
[Unstated](https://github.com/jamiebuilds/unstated) | 7,047


### キッチハイクでは？

ライブラリは必要になったら入れようというスタンスで、未導入でした。今後はReact標準のAPIを使うようにしていく方針です。

## ナビゲーションライブラリの選定

React Nativeの公式ドキュメントで紹介されているReact Navigationと、 Wixが開発しているReact Native Navigation、そしてReact Navigationをベースに開発されているReact Native Router ( react-native-router-flux, 通称 RNRF ) の3つでまずは検討すると良いかと思います。ライブラリの名前が紛らわしいので、間違えないように理解することが重要です。

ライブラリ | GitHubリポジトリ | star数
----|----|----
[React Navigation](https://reactnavigation.org/) | [react-navigation/react-navigation](https://github.com/react-navigation/react-navigation) | 16,939 
[React Native Navigation](https://wix.github.io/react-native-navigation/#/) | [wix/react-native-navigation](https://github.com/wix/react-native-navigation) |  11,008
[React Native Router ](https://github.com/aksonov/react-native-router-flux) | [aksonov/react-native-router-flux](https://github.com/aksonov/react-native-router-flux) | 8,582

### キッチハイクでは？

React Nativeの公式ドキュメントを参考にして、 React Navigation を使っています

## APIクライアント設計

APIクライアントは、JavaScript 標準API の Fetch API を使うか、より高度に制御したい場合はライブラリを導入するかの選択になります。

ライブラリ名 | star数 | 特徴
----|----|----
[axios](https://github.com/axios/axios) | 67,165 | PromiseベースのHTTPクライアント。ブラウザやNode.jsに幅広く対応したJSライブラリ。
[Frisbee](https://niftylettuce.com/frisbee/#/) | 904 | Alternative axiosとして後に開発が始まったReact Nativeに最適化したライブラリ。

### キッチハイクでは？

ライブラリを導入せずに JavaScript の Fetch API を使っています。必要になったらライブラリの導入も検討する予定ですが、いまのところは問題ないです。

## コラム: Firebase Remote Config の紹介

1年ほど前に [Firebase Remote Config](https://firebase.google.com/docs/remote-config?hl=ja) を導入しました。最初はキャンペーン情報の制御など、サーバーサイドのリリースをしないでも変更したい箇所から入れていきましたが、その使用範囲は広げていっています。リリースしなくともデータ変更ができるのは便利です。クライアント側からは参照のみで更新がなく、サーバーサイドで管理画面を作るほどでもないという条件のデータが使いどころだと感じています。

## アプリストレージ DB 設計

アプリストレージは React Native 標準の Async Storage 、もしくはサードパーティが提供している DB ライブラリを使用するかの選択になります。

ストレージ | ライブラリ | star数
----|----|----
Async Storage | [Async Storage](https://github.com/react-native-community/async-storage) | 1,105
Realm | [realm-js](https://github.com/realm/realm-js) | 3,768
SQLite | [react-native-sqlite-storage](https://github.com/andpor/react-native-sqlite-storage) | 1,849
Cloud Storage for Firebase | [react-native-firebase](https://github.com/invertase/react-native-firebase) | 6,608

### コラム: ObjectBox

記事を執筆中に [ObjectBox](https://objectbox.io/) というモバイル用のクロスプラットフォーム対応DBを知りました。公式サイトには *ObjectBox object oriented database - up to 10x faster than SQLite* とあり、パフォーマンスに特化した設計方針のようです。

クライアントライブラリが swift / java / go / dart などはあるのですが、 JavaScript については公式には提供されてないようで React Native ではまだ使えないのですが、気になっています。

### キッチハイクでは？

アプリ側に複雑なデータを持たせる要件がいまのところないので、Async Storageを採用してます。一方で、開発を続けていくとどうしてもアプリ側に持たせるデータやキャッシュが多くなってきたので、サードパーティDBも検討中です。

--------

ここまでReact Nativeの開発を始めるにいたって、検討ポイントを上げてきました。

# 開発体験 Development Experience

ここからは実際に開発する際の考慮ポイントについて紹介していきます。今回は3つの観点で整理しました。デザイナーとの連携作業である **コンポーネント設計** , 実際のコードに関連する **TypeScript / Lintツール** , そして **テスト** です。

## コンポーネント設計

コンポーネント指向であるReactで開発する上では、コンポーネント設計と向き合っていく必要があります。ReactはView開発がメインとなるので、デザイナーとの連携は多くなります。このことから、 **どのようにしてデザイナーとコンポーネント設計を共有するか** が開発チームの課題となってきます。

コンポーネント設計におけるデザイナーとエンジニアの架け橋候補の一つが **Atomic Design** でしょう。キッチハイクチームでもAtmic Designの導入を検討しました。そこで課題になったのが、どこまで厳密にAtomic Designに従うかです。より具体的に言うと、Atom / Molecule などをデザイナー主導で設計していくのか、エンジニア主導で設計していくのかです。

このような議論が起きる理由はコンポーネントが持つ責務にはデザイン以外の要素があるからだと考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32750/7903cb00-5412-76cd-ad20-497148382675.png)

[デザイナーとエンジニアで考えるReactコンポーネント設計 \- KitchHike Tech Blog](https://tech.kitchhike.com/entry/2018/09/30/230000) より

上記の図でいう、デザインとしての構造性はエンジニアでは判断できず、逆にコードとしての再利用性をデザイナーが判断するのは難しいことです。チーム方針としてコンポーネント設計にどう向き合っていくかは重要なテーマであり、チーム状況によっても変わってくるものだと考えています。

### キッチハイクでは？

Atomic Designをベースにしていますが、厳密に適用せずにエンジニア主導で開発するスタイルに落ち着きました。デザイナーは Figma を使ってカタログベースのデザインを作成し、どの部分をコンポーネント化するかはエンジニアが設計するというものです。ここに至る経緯に関しては弊社デザイナーの記事に詳細があります。

[デザインシステムを持たない組織のこれまでの取り組みとこれからを考える｜はのめぐみ \| KitchHike｜note](https://note.com/featherplain/n/n4aa45eb267b6)


## コンポーネントスタイルガイドツールの選定

デザイナーとエンジニアでコンポーネントを共有する際に、コンポーネントスタイルガイドツールが検討されるかと思います。Storybookなどに代表されるものです。ここでは、Storybookをはじめいくつかの代替ツールを紹介します。

ツール名 | star数 | 特徴
----|----|----
[Storybook](https://storybook.js.org/) | 43,673 | コードベースのコンポーネントスタイルガイドツール。スナップショットテストも可能。
[Docz](https://www.docz.site/) | 17,407 | ドキュメント管理ツール。Reactにも対応している。
[React Styleguidist](https://react-styleguidist.js.org/) | 8,023 | Hotリロード対応。コンポーネントカタログツールとしてフォーカスする設計思想で開発されている。


### キッチハイクでは？

コードベースのコンポーネントカタログツールは使わずに、Figmaを使ってカタログ化しデザイナーとやり取りをしています。詳細な経緯は弊社デザイナーの記事を参考にしてください。

[デザインシステムを持たない組織のこれまでの取り組みとこれからを考える｜はのめぐみ \| KitchHike｜note](https://note.com/featherplain/n/n4aa45eb267b6)

## ディレクトリ設計

TODO

[フォルダ構成 : ベストプラクティスを見つけるためのReact Nativeアプリ ソースコードリーディング](https://tech.kitchhike.com/entry/2018/12/31/040206#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E6%A7%8B%E6%88%90)

## 型チェッカー TypeChecker

キッチハイクアプリの設計が始まった3年前は、FlowとTypeScriptが主なJavaScriptの型チェッカーでした。当時はReact Nativeと同じFacebookが開発しているFlowの方が親和性が高いのではと思っていましたが、ここ数年で状況は変わりました。
2017年4月にはGoogle社内の標準言語としてTypeScriptが承認されるというニュースが出ましたし、ReactやReact Nativeの主要なライブラリはTypeScriptで開発されていることも少なくありません。

### キッチハイクでは？

初期リリースでは型チェッカーは入っていませんでした。ここ半年ほどでTypeScriptを随時導入していき、現在は多くのコンポーネントがTypeScript化されています。

## コラム: TypeScript と VS Code

TypeScriptの導入を決断したきっかけの一つが、VS Code ( Visual Studio Code ) でした。TypeScriptを導入すると、補完やエラー表示などVS CodeのIDEとしての機能を使えるようになり、開発効率が上がるのではと期待しました。

## Lint / コーディングスタイル

検討としては [Prettier](https://prettier.io/) か [ESLint](https://eslint.org/) ( or TSLint ) か、もしくはその両方を連携させるかでしょうか。

ライブラリ | star数 | 特徴
----|----|----
[Prettier](https://prettier.io/) | 34,595 | フォーマッタ
[ESLint](https://eslint.org/) | 15,412 | フォーマッタ + 静的解析ツール。未定義の変数の警告などができる。

### キッチハイクでは？

現状ではフォーマッタだけでやりたいことができているため、Prettierのみで運用しています。

## テスト設計

テストで担保したいカバレッジや方針によって、どのツールを使ってどこまでやるかが決まってきます。今回はキッチハイクアプリでの事例を紹介します。

キッチハイクアプリでは、可能な限りビジネスロジックをAPI側に持たせる薄いViewとしてのアプリという設計指針で開発しています。ビジネスロジックはRailsのRSpecでテストするので、アプリではView側のテストが多くなります。開発初期は手動テストがメインでしたが、Jest, E2Eの導入により、手動テストの時間は大幅に削減され多くのテストが自動化されました。

### Jest + Enzyme

コンポーネントのテストにはJestと、Airbnbが開発している [Enzyme](https://github.com/airbnb/enzyme) を一緒に使っています。

### E2E

クロスプラットフォームのE2Eテストにはいくつか選択肢があります。

ライブラリ | star数 | 特徴
----|----|----
[Detox](https://github.com/wix/Detox) | 5,632 | React Native専用。テスト用のコンパイルが必要。
[Appium](https://github.com/appium/appium) | 10,553 | Seleniumを使用した汎用的の高いフレームワーク
[Cavy](https://cavy.app/) | 1,068 | React Native専用

キッチハイクでは多くのReact Nativeツールを公開しているwixが開発しているという点や、グレーボックステストというコンセプトから Detox を採用しました。

### CI/CD

React NativeをサポートしてるCI/CD環境は [CircleCI](https://circleci.com/circleci-react/) か [Bitrise](https://devcenter.bitrise.io/jp/getting-started/getting-started-with-react-native-apps/) でしょうか。キッチハイクではまだ導入していないので、今後の課題となっています。


--------

ここまでReact Nativeの開発体験についての考慮ポイントを上げてきました。
まだ他にも

- 機能要件
- マーケティング要件
- 運用設計

を追記して書こうと思っています。各項目を追加したら通知しますので、もし必要な方はストックしていただけると通知いたします。

最後まで読んでいただいてありがとうございました。

2日目は [1人チーム本](https://booth.pm/ja/items/1315573) や [実践Expo](https://www.amazon.co.jp/dp/484439875X) の著者ハムカツおじさんこと @watanabe_yu さんです。お願いします！