良いアプリを作るために、良いコードを読む。
CTOの Shoken です。キッチハイクでは2年前にRailsへのReact導入、1年半前に0からReact Nativeでアプリ開発を始めました。この記事では、React Nativeアプリ開発のベストプラクティスを見つけるためのソースコード探索手法と、コードリーディングのポイントを紹介します。
React Nativeアプリのソースコードの探し方
良いアプリを開発するためには、良いコードをたくさん読むことが必要となります。GitHubがある現代では、OSSとしてReact Nativeアプリのソースコードが公開されており、私たち開発者は無償でソースコードを読むことができます。設計者の思想はディレクトリ構成やメソッド名・変数名から汲み取ることができます。ソースコードを公開している開発者に感謝しながら、アプリ開発のベストプラクティスを見つけるために参考になったソースコードの探索場所を4つ紹介します。
ReactNativeNewsのShowcase, React Native Appsから探す
React Native Apps is a showcase of only open source React Native apps.
ReactNativeNewsがオープンソースのReact Nativeアプリを集めたShowcaseを公開しています。かなりの数が登録されていて、最近もPRが送られて更新されているようです。
今回はその中から、実際にコードリーディングを行った2つを紹介します。
F8 2017
https://github.com/fbsamples/f8app
F8はFacebook のデベロッパーカンファレンス F8 2017の公式アプリです。React Nativeの開発元であるFacebookが開発しているので、ディレクトリ構成やメソッド名などのネーミングの参考にしました。 このアプリではRedux, Jest, Flow, ESLint, Prettierが採用されており、当時はもちろん今でもお手本アプリとして十分参考になります。
また Building the F8 App というドキュメントも公開されており、アプリ構成の概要図など充実した資料となっています。
PxView
https://github.com/alphasp/pxview
PxViewは非公式のPixivビューワーアプリです。このアプリはFunctional Componentを積極的に使っていること、HOCというディレクトリを作成して管理していることなどが特徴です。
例えば、FollowButtonというコンポーネントはFunctional Componentで実装されています。 https://github.com/alphasp/pxview/blob/master/src/components/FollowButton.js
キッチハイクにもフォロー機能があるので、参考にさせてもらいました。
React Docs ( React公式ドキュメント ) から探す
React Nativeではなく、Reactのドキュメントです。React Nativeのドキュメントはコンポーネントのリファレンス部分が多いですが、ReactのドキュメントにはReactを使った実践的なテクニックとサンプルコードが紹介されています。特に ADVANCED GUIDES
には多くのサンプルコードがあるので、Reactのコア機能を使う前には参考にしています。Typechecking With PropTypes ,
Higher-Order Components など多くのアプリで普及しているテクニックから、まだサンプルアプリではあまり見かけないエラーハンドリング機能である Error Boundaries まで、開発元からの一次情報という信頼できるコードを学べます。
react-nativeリポジトリのRNTesterを読む
React NativeはGitHubでオープンソースとして公開されていますが、そのリポジトリの中にRNTesterというUIコンポーネントカタログのサンプルアプリがあります。React Nativeリポジトリ内でメンテナンスされているので、公式のサンプルアプリという位置付けに近いようです。
The RNTester showcases React Native views and modules.
ビルドすると、以下の画面が表示されます。
React NativeアプリのUI部分のサンプルコードが多く含まれています。また Detox を使用したE2Eテストも入っており、テストについての参考にもなるリポジトリです。
RNTesterはReact Nativeリポジトリ内にあるので、Reacrt Native自体のアップデートにもついていっており、更新が活発なのも魅力的です。
ライブラリのサンプルアプリのコードを読む
ライブラリのリポジトリ内ある、サンプルアプリコードも有用な情報源となります。
- react-native-fcmのサンプルアプリ: simple-fcm-client
- react-native-navigationのサンプルアプリ: Navigation Playground
それぞれのライブラリの使い方はもちろん、ディレクトリ構成やコンポーネント構成なども参考になります。
以上、ここまでReact Native開発の参考にしているソースコードの入手先を紹介してきました。 ここから、どの観点でコードリーディングを行うかについて紹介します。
コードリーディングのポイント
コードリーディングでは主に以下の観点でマクロ視点・ミクロ視点を切り替えながらコードを読んでいます。
- ディレクトリ構成
- 使用しているライブラリ
- Prettier でカバーできないコードブロックの構成
- メソッド名、クラス名、変数名
ディレクトリ構成
ディレクトリ構成で見るポイントは、どのように分けているか と Styleをどう管理しているか の2つです。
React Nativeアプリのネイティブ関連ファイルは android
, ios
以下に配置されます。一方、メインで開発するJavaScriptファイルの配置場所はアプリごとにディレクトリ構成を作って管理します。このJavaScriptファイルを配置しているディレクトリの名前は主にこの3つが使われているようです。
- js
- app
- src
Facebook が開発している f8app は js
というディレクトリ以下にJavaScriptファイルが配置されています。
f8app/ ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __mocks__ ├── android ├── app.json ├── docker-compose.yml ├── index.android.js ├── index.ios.js ├── ios ├── js ├── package.json ├── scripts ├── server └── yarn.lock
その下の階層もアプリによって様々で、f8appのように機能で分けるものもあれば、 components
styles
という名前で分けるアプリもあります。
以下の f8app では filter
login
など、ディレクトリ名が機能の名前となっています。
f8app/js ├── actions/ ├── common/ ├── filter/ ├── login/ ├── rating/ ├── reducers/ ├── store/ ├── tabs/ ├── video/ ├── F8Analytics.js ├── F8App.js ├── F8Navigator.js ├── FacebookSDK.js ├── Playground.js ├── PushNotificationsController.js ├── env.js ├── flow-lib.js ├── relay-environment.js └── setup.js
以下はpxview というアプリのディレクトリ構成です。JavaScriptファイルは src
ディレクトリ以下に配置され、 components
styles
という名前のディレクトリ構成になっています。
pxview/src/ ├── common/ ├── components/ ├── containers/ ├── images/ ├── navigations/ ├── screens/ └── styles/
キッチハイクでは、Atomic Design ベースでコンポーネントを設計しており、ディレクトリ名にも components
や pages
を使っていて、上記の例ではpxviewに近い構成です。
使用しているライブラリ
ライブラリの調査は、npmパッケージの管理ファイルであるpackage.jsonを参照します。主な確認ポイントは以下です。
- React , React Native のバージョンとライブラリの互換性
- 同じライブラリを使っていたら、その使用方法
- 知らないライブラリがあったら調査
特に React Native 自体のバージョンアップをする際、ターゲットバージョンのReact Native で開発されている他アプリの package.json を確認することで、ライブラリのバージョン互換性調査の参考にしています。
Prettier でカバーできないコードブロックの構成
キッチハイクではPrettierを採用しており、基本的なコードフォーマットはPrettierを実行することで統一されますが、カバーできない部分もあります。
例えば以下のようなコードの構成です。
- Functional Component で
function
を使うか、const
を使うか - propTypes, defaultProps はファイルのどこに書くか
- export default はファイルのどこに書くか
キッチハイクでは他アプリのソースコードを参考に、 Functional Component
は以下の構成に統一しています。
// functionではなくconstを使う. propsは展開しない const KHButton = props => { return ( <View> <KHText style={props.textStyle}>{props.title}</KHText> </View> ); }; // ロジック部分を書いた後に propTypes, defaultProps の順番に書く KHButton.propTypes = { title: PropTypes.string.isRequired, textStyle: PropTypes.object, }; KHButton.defaultProps = { title: '', textStyle: {}, }; // ファイル末尾に export default を書く export default KHButton;
ソースコードの構成は通常時よりも非常時、例えば障害発生時の原因調査などで重要になります。非常時には平常時の心境でコードを読むのは困難です。そんな時に、書いてあるべき場所に書いてあることはコードを読むスピードに大きな影響を与えます。
propTypes と defaultProps の位置が逆に書いてあっても、エラーは起きません。しかし、非常時に読むことを考えると、他のファイルと違う順番に書いてあるだけでも、想像以上に読みにくいと感じてしまいます。コードのフォーマットはもちろん、Prettierでカバーできないコード構成も一貫性あるコードにするべく、レビュー・リファクタリングを行なっています。
メソッド名、クラス名、変数名
メソッド名などの名前調査もコードリーディングの大きな目的の一つです。キッチハイクチームには英語ネイティブの開発者は現状いないので、多くのソースコードを読むことによって、名前の引き出しをストックするようにしています。
例えば f8app に compatibility.js というデータの互換性をチェックするモジュールがあります。
主に以下の3つの関数で構成されています。
- ensureCompatibility
- resetCompatibility
- updateCompatibility
コード自体はシンプルで ensureCompatibility
で互換性をチェックして、必要だったら resetCompatibility
でAsyncStorage内の非互換データを消して updateCompatibility
でAsyncStorageで管理しているバージョンを更新するという流れです。
シンプルなコードだからこそ、checkではなく ensure の方がより具体的だな、storage reset なのでclearではないのか、など学ぶことが多いです。
自分では ensureCompatibility
という関数名はなかなか思いつかないので、もっと多くのソースコードを読んで引き出しを増やさなければと思います。
まとめ
この記事では、React Nativeアプリ開発のベストプラクティスを見つけるために、ソースコードの探索場所とコードリーディングの観点を紹介しました。
- ソースコードの探索場所
- ReactNativeNewsのShowcase
- React Docs ( React公式ドキュメント )
- react-nativeリポジトリのRNTester
- ライブラリのサンプルアプリ
- コードリーディングのポイント
- ディレクトリ構成
- Prettier でカバーできないコードブロックの構成
- メソッド名、クラス名、変数名
- 使用しているライブラリ
キッチハイクではエンジニアのOSS活動を推奨しています。実際に2018年はほとんどのメンバーがOSSにPRを出してマージされました。一緒にOSS活動とアプリ開発をするメンバーを募集しています!
We’re Hiring!
React Nativeエンジニア・Reactエンジニア・Railsエンジニア・インターンエンジニアを募集中です!