【LT全文書き起こしました】Tech Stand #1 React Native 中上級者向け勉強会
「Tech Stand」とは、株式会社stand.fmが主催するテックイベントで、会社・個人の技術に関する知見や知識、技術選定プロセスなどの実践的な情報共有をするオンライン勉強会です。
第1回となる今回のテーマは「React Nativeのレベルアップ」。4名の登壇者によるプレゼンテーションを通して、全国のReact Native中級者〜上級者の方々と一緒に、React Nativeへの理解をより深めることを目的に開催しました。
※本記事は、2020年8月21日に開催されたオンラインイベントより編集したものです。
・LT1本目:React Nativeにおけるアクセシビリティ対応について
(株式会社stand.fm / Yuta Mori氏)
・LT2本目:Flipperのはなし
(株式会社カンム / 伊藤友気氏)
・LT3本目:最近のNative Modules開発について
(BASE株式会社 / 大木聡氏)
・LT4本目:React NativeのVisual Regression Testについて
(株式会社CureApp / Jesse Katsumata氏)
LT1本目:React Nativeにおけるアクセシビリティ対応について
株式会社stand.fm エンジニア Yuta Mori氏:
stand.fmのMoriと申します。今日は、「React Nativeにおけるアクセシビリティ対応について」というテーマで発表させていただきます。よろしくお願いします。
GitHub:@moriyuu
Twitter:@moriyuu__
というIDでやっていますので、よかったらフォローしてください。
エンジニア歴は3〜4年目くらいで、React Nativeは1年くらい前から仕事で使い始めました。もともと、Webのフロントエンドをやっていたのですが、CSSを書いたりアニメーションの実装がわりと好きです。
stand.fmというサービスですが、音声配信プラットフォームで、アプリで録音から配信ができたり、ライブ配信ができたりする音声系のアプリを作っています。
今日は、「アクセシビリティ対策について」という形で発表させていただきますが、あらかじめお断りしておきますと、stand.fmのアプリはReact Native製ですが、実はまだアクセシビリティ対応が全然できていない状態でして、ついこの間お問い合わせのフォームから「読み上げ機能に全然対応させれていません」というメールが来て、「うわぁ」と結構辛い思いをしました。
また、音声のサービスなので、今後必ず、視覚障害を持った方にも使って欲しいと思っていて、こういったアクセシビリティ対応をしっかりやらないといけないな、と思っています。React Nativeにおけるというところだとあまり詳しくなかったので、今回は基本的なところから調べたものを発表させていただければと思います。
そもそもアクセシビリティとは
そもそもアクセシビリティとは、「多様な環境で多様な人たちがコンテンツを利用可能にできることを目指す」という考えなのですが、視覚障害や聴覚障害を持っている人でもコンテンツにアクセスできて、それを利用できる、というのをできるだけ可能性を高めていこう、という話です。実際に僕らがわりと直面する問題というのは、使用している色が十分なコントラストを取れていない、白地に薄いグレーの文字で読みにくい、などの場合は色弱の人が読みづらいなどの問題があったり、スクリーンリーダー、iOSやMacだとVoiceOverになるのですが、で内容を読み上げたりとか操作できたりすることを目指したりします。
accessibleというプロパティ
React Nativeにおける、という文脈で最初に知っておくべきことがaccessibleというプロパティなのです。これを入れると、要素がアクセシブルな要素になります。「アクセシブルとは何か」というと、VoiceOverなどを使ったことをある人はわかると思うのですが、読み上げのフォーカスが当たります。`accessible={false}`だと、この画像の「text one」や「text two」にフォーカスが当たるのですが、これをViewでまとめるとフォーカスが一度に当たる、という感じです。あとでデモをお見せしますので、それでイメージしていただければと思います。
主なアクセシビリティプロパティ
アクセシビリティ系のプロパティで他にもいろいろあるのですが、よく使いそうなものを紹介します。
accessibilityLabelはWebのaria-labelなどとほとんど一緒です。読み上げしてくれる時に、内容よりもラベルの方を優先して読む、というものです。
accessibilityHintというのは、ラベルを読み上げた後に補足情報を読み上げてくれるものです。
accessibilityRoleは、View要素をボタンとして使いたい場合に、`accessibilityRole=button`という風に。これもWebのroleと近いです。
accessibilityIgnoresInvertColorsは、OSが色を反転させて表示するモードがあるのですが、それをやった時も反転させずに表示させるというものです。
accessibilityViewIsModalは、Viewにこれを当てるとそれ以外の要素を一旦無視して読み上げないでおいてくれるというものです。
accessibilityLabelの例
accessibilityLabelの3つ例を作りました。
1つ目はViewにTextをつめただけ。
2つ目がaccessibleプロパティをViewにつけたもの。
最後がaccessibilityLabelをViewに’This is Hello World’という感じでつけたものです。
これを実際VoiceOverがどのように読んでくれるかというと、
1つ目は「Hello」と「World」を別々に読み上げてくれます。
2つ目は「Hello World」とつなげて読み上げてくれます。
最後は「This is Hello World」と、accessibilityLabelに設定した文字を読み上げてくれます。
accessibilityRoleの使い方
accessibilityRoleは、Webのroleと似ています。ただのテキストだとただのテキストになってしまうのですが、accessibilityRole=‘header’というのをつけると、要素がヘッダーだと理解してくれるので、読み上げの際に、「これは見出しです」というようなことを言ってくれるようになります。
React NativeにはButtonコンポーネントがあり、これにはaccessibilityRoleがデフォルトでbuttonが指定されてます。またTouchableOpacityをボタンの代わりに使うことがよくあると思うのですが、これはデフォルトではaccessibilityRoleがbuttonになっていないので、読み上げ時「ボタン」と言ってくれないんですね。そのため、これをわざわざ指定する必要があるのですが、それが触ってみて意外だな、と思いました。
目をつぶって操作すると、これのありがたみがわかるなと思いました。
XcodeのAccessibility Inspector
次ですが、一旦React Nativeの機能から逸れて、Xcodeの機能でAccessibility Inspectorというのがあります。
Xcodeのメニューから開けるのですが、インスペクタなのでソースごとにアクセシビリティの情報が見れたり、Run Auditというボタンがあって、それをクリックすると「ボタンがタップできる領域が小さすぎる」というような警告を出してくれる機能があります。
例えば、薄いボタンのようなものを作ると警告が出ないのですが、それはなぜかわかっていないので一旦飛ばします。
React Native for Webを使用するとき
ちなみになのですが、React Native for Webをstand.fmのWebページで実際に使っています。アプリのコンポーネントをWebで使い回すために使っているのですが、accessibilityRoleというのをテキストそれぞれつけると、React Native for Webではh1でレンダリングしてくれたりとか、適切にaria-level=“3”などをつけるとh3になったりとかというのがあるので、React Native for Webを使っている場合だと、結構、コードの共有というか、一石二鳥、三鳥という感じで嬉しいです。ただ、VewにaccessibilityRoleなどをつけないとただのdivでレンダリングされてしまうので、これはつけていかないといけないやつですね。
おわりに
発表は以上になります。今回、VoiceOverでいろんなアプリを操作して回ってみたのですが、Twitterのアプリのクオリティの高さが段違いで、Instagramとかも正直微妙だな、という感じでした。僕のVoiceOverの操作が不慣れというのも若干あるかもしれないのですが、Twitterのアクセシビリティのクオリティは頑張り度が感じられて凄かったですね。
アクセシビリティ対応は地道にやっていくしかないので、頑張っていきましょう、という感じです。
stand.fmではエンジニアを募集していますので、よければ。ありがとうございました。
LT2本目:Flipperのはなし
株式会社カンム 伊藤友気氏:
「Flipperのはなし」というタイトルで話をさせてください。カンムの伊藤と申します。
GitHub:@mururu
Twitter:@mururururu
というIDでやっています。
普段はReact Nativeを書いているというよりは、バックエンドの仕事をしていることの方が多いのですが、今回はReact Nativeについて話させてください。中上級者向けかと言われると怪しいのですが、お手柔らかによろしくお願いします。
Flipperとは
「Flipperって何なんですか」という話をさせていただきます。最近だと普通に使っていらっしゃる方も多いと思いますが、React Nativeの開発時に使うデバッガーです。
React Native 0.62以降でデフォルトで使えるようになっていますが、もともとはモバイル開発用のiOSやAndroid向けのデバッガーです。0.62以降はReact Nativeでもデフォルトで使えるようになっているので、最近は触っている人も多いのではないかと思います。
0.61以前でもちょっと面倒臭いのですが入れることはできるので使えると思います。
React Nativeのデバッグ(Flipper以前)
弊社もバンドルカードというアプリを4年ほど前からReact Nativeで開発しているのですが、React NativeのデバッグというとFlipperが出る以前はなかなか快適な環境ではないな、というのが正直なところでした。いろいろやり方はあると思うのですが、一番簡単なのはChrome DevTools経由でRemoteでJSレイヤのデバッグしたりとか。もう少しちゃんとやろうと思うと、react-native-debuggerを使っていろいろ細かいところを見るみたいなことはあったと思います。しかし、動作が怪しかったりとか、結構重いな、みたいな場面もあり、快適かといわれると怪しかったというのが実感です。
そこでFlipperという新しいデバッガーが出てきてくれて、弊社のバンドルカードではまだ完全にFlipperをみんな使っている状況ではないのですが、新しいプロダクトも作っていて、そっちはFlipperでずっとやっていて快適だなという感じでやっております。
Layout Inspector
紹介みたいな感じになってしまうのですが、少し話をさせてください。
1個目の特徴がLayout Inspectorなのですが、React DevToolsはもちろん入っていてプラスNativeのElementも確認可能です。react-native-debuggerでも確認可能だったのですが、入れ子になったりしていて、結構見にくいな、使いづらいな、みたいなのがあってあまり使えませんでした。しかし、Flipperが出てきて見やすくなったなというのがあります。
Network
ネットワークのデバッグも簡単です。
これもreact-native-deguggerでもできたと言えばできたのですが、結構面倒臭かったイメージがありました。バージョンをアップグレードしていく途中で見えない時期とかがあったりして、あまり良いイメージはなかったのですが、Flipperはデフォルトですごく簡単に見れます。かなり見やすいので、カジュアルに使えていいなという印象ですね。
その他
その他でまとめてしまったのですが、よく挙げられているもので、Shared PreferencesとかUserDefaultsが見やすかったりします。
Crash Reporterというのは、この文脈ではNativeのレイヤのクラッシュのレポートが見れますよという話です。普通にReact Nativeでそれが見たい場面ってそんなに多くないかなと個人的には思っているのですが、Native Modulesの開発をしている時などは、普通にちょいちょい見られた方がいいよなというところがあったので、統合してFlipper上で見れるのは楽チンでいいなと感じています。
Plugins
最後にPluginsの話をちょっとさせてください。「Flipperの文脈でプラグインって何なんだ」という話なのですが、Flipperは結構プラガブルな感じで実装されています。画像の左側に並んでいるものはFlipperのプラグインとしてほぼほぼ実装されていて、これをユーザーが実装できます。アプリ側でもFlipperのSDKが用意されていて、さらにこれらはどちらもJavaScriptで書くことができます。なので、自分たちのアプリケーション専用のデバッグの機能を足したいなという時は、このElectronで書かれているデスクトップアプリ用のSDKがあるのでそれを使ってプラグインを書いて、アプリ側の方にも対応するコードを入れてあげれば、Flipper上で自分たち独自のデバッグ機能みたいなものを簡単に実装することができます。結構シンプルに書けて使いやすいです。挙げるべき特徴は、一方的にアプリの情報を見るだけではなくて、双方向で通信ができるところですかね。デスクトップアプリ側から何かを送ったり、逆にアプリ側から何か送ったりということが柔軟にできます。
もともとあるサンプル実装のマルバツゲームで、Flipper上とシミュレーター上でゲームの対戦ができます、みたいな感じのものです。Flipperとシミュレーターでステートを共有しているような実装になっているのですが、両側それぞれのプラグインがコネクションを持っていて、コールバックを受け取ったらステートを更新して、またこっちの入力受け取ったらステートを更新して、というようなことが裏で行われています。こういったものがスッと簡単に書けるので、結構便利かなと思ったりします。
もう一個、他の例としてAsync Storageのデバッグをちょっとお見せしたいなと思います。Async Storageの中身の値を見たいな、みたいな場面がたまにあると思うのですが、そういう時にあまりオフィシャルな方法がないというか、うまいやり方ってあまりなかったと思います。そこら辺の機能がFlipperでプラグインとして提供されているのでそれを紹介させてください。アプリの方にAsync Storageと記載されているのですが、ここでUpdateTimeを押すとAsync Storageの値が更新されるような実装を入れています。Flipper上でプラグインをインストールする時は、公開されているものを簡単に入れることもできますし、あと、自分たちで開発していて公開していないものとかは、パスを指定して入れることができたりもします。今回は公開されているAsync StorageのプラグインなのでInstallをクリックして入れて、再起動すると、プラグインが有効化されてAsync Storageというタブが出てきます。これでシミュレーターのAsync Storageの値をFlipper上で確認できるようになります。これは、裏でシミュレーターとFlipperが通信していて、中身をFlipperに送っている感じですね。更新ボタンを押すと、Flipper上でも値が更新されていることを確認できます。こういった感じで簡単にプラグインが書けます。
今使っているこのプラグインでは値を見るだけなのですが、原理的には、削除する機能をFlipperのプラグイン上で実装して、シミュレーターでそれを受け取るような処理を書いておけば、値を見るだけではなく、Flipper上でAsync Storageの数値を削除するみたいなことも簡単に実装できたりします。という感じでプラガブルで拡張可能になっているので、ぜひぜひ、皆さんも開発で役立つように使ってもらえたらいいなと思っています。
以上になります。ありがとうございました。
LT3本目:最近のNative Modules開発について
BASE株式会社 大木聡氏:
今日は、「最近のNative Modules開発について」というテーマでお話しさせていただきます。大木聡と申します。
GitHub:@roothybrid7
Twitter:@roothybrid7
というIDでやっています。
BASE株式会社で、主にiOSアプリの開発に携わっていまして、それ以外にWebフロントエンドの開発も最近は行っています。React Native歴は1年くらいです。
Native Modulesとは?
はじめに、「Native Modulesとは」ということなのですが、簡単に言うと、iOSやAndroidなどのプラットフォームの機能を直接使うためのAPIにアクセスできるモジュールとなっております。
React Nativeのセットアップ改善
React Nativeのバージョン0.60以降に、ライブラリを導入する方法に改善がありました。パッケージをインストールした時に、自動でNative ModulesをリンクしてくれるAutolinkingという機能がサポートされました。
また、プロジェクトを管理する設定ファイルもサポートされていて、設定のカスタマイズも宣言できるようになりました。
セットアップする方法も改善されてきたので、アプリのネイティブコードに実装を追加するよりも、独立してパッケージとしてNative Modulesを開発するのも悪くなさそうかな、と感じてくるようになりました。
Native Modules開発の方針
公式ドキュメントや公開されているライブラリを参考にして、次のように設計の方針を決めていきました。
まず、「できる限り標準で推奨している方法で開発」ということなのですが、これは、Bob(@react-native-community/bob)というツールを使いました。公式ドキュメントにも、Bobを使ったセットアップの方法が載っています。これを使うと、2つのコマンドを実行するだけで、画像右のディレクトリ構成のようなプロジェクトが簡単にすぐ作れます。
Bobを使うことの利点は、すぐに動かせるexampleの環境が手に入る、ということです。
また、ライブラリを使う側が、JavaScript/TypeScriptベースどちらであってもすぐ使える設定とか、ビルドの設定もあらかじめ入っています。あとはコードを実装するだけになっています。
関係する技術が多いので、現在のアーキテクチャーを調べてみました。
Native Modulesを提供するためには、まず、Nativeコードを実装しなければなりません。それをReact Native Bridgeに登録する必要があります。これが最低限の実装となっています。
ただ、最低限の実装だと扱いづらいので、Native Modulesの型定義とか、それをラップしたヘルパー関数を用意します。
次に、Native Modulesを実装する言語ですが、実装する際に、誤った古いサンプルコードを参照しないように、Nativeのモダンな言語を採用しました。
SwiftやKotlinを使う利点としては、「先進的な機能がいち早く体験できる」ということと、「言語開発の最前線に触れることも可能」かなと思っています。ECMAScriptやTypeScriptでも見たような機能が数多く存在しています。例えば、Optional Chainingという機能ですが、TypeScriptだとバージョン3.7からサポートされていて、Swiftでも同じようにサポートされています。違う言語でも似たような使用感で実装しやすくなると思います。
SwiftでNative Moduleを実装した
次に、SwiftでNative Moduleを実装した例を紹介します。
キーチェーンというiOSのパスワードで使うストレージを使うためのNative ModuleをSwiftで実装しました。これは、会社のパブリックのリポジトリで公開しているので興味がある方は見ていただければと思います。実際弊社のBASE Creatorというアプリでも組み込んでいます。もともと、react-native-keychain-qという元からあるライブラリを使おうと最初は思っていたのですが、「複数アカウントのパスワード管理に対応していない」というところと、「Objective-Cで実装されている」という理由で、自前で実装しようと考えるようになりました。
実際のコード例を見て、「どう実装すればいいのか」というのを簡単にイメージしていただければと思います。
まず、Native Moduleクラスを実装する必要があるのですが、これはSwiftで実装できます。
次に、React Native Bridgeに登録する必要があるのですが、登録する処理はSwiftでは実装できないので、Objective-Cにこのクラスとこのメソッドをエクスポートする必要があります。@objcという属性を使ってエクスポートできます。
次に、実装したNative Moduleを登録する処理の実装を見ていきます。これは、C言語由来のマクロを使って実現しています。コードの中身を見たのですが、メタプログラミング的な、文字列からインスタンスを生成するという黒魔術的な処理が含まれていて、Swiftではこれはサポートされていないので、Objective-Cで登録処理はしないといけないというわけです。
先ほどまででNative Moduleの登録はできたのですが、Objective-C側のReact Native Bridgeで定義している型などをSwift側で使っているので、Promise用のコールバック関数のために、Objective-C側の定義をSwift側で参照できるようにする必要があります。そのためには、Bridging-HeaderというファイルにObjective-CのHeaderをインポートする必要があります。これをインポートすると、Swift側でここで定義されている型を参照できるようになります。
Swiftで一つNative Moduleを実装する
最後に、実装したNative Moduleを、JavaScriptとかTypeScriptで使うための型定義とかヘルパー関数を提供します。
実はこれはなくても、Native Moduleにアクセスはできるのですが、多くのライブラリだと、使いやすいように型定義とかヘルパー関数をJavaScriptやTypeScript側で定義しています。
今回はTypeScriptを使って実装したので、その時の例を見ていきます。
これは、Native Moduleが登録されているかチェックするコードです。
AutolinkingがあるReact Nativeのバージョン0.60以降であれば、あまり関係ないコードなのですが、react-native linkコマンドを使って手動でリンクする必要がある古いReact Nativeだと、リンク漏れとかがあるのでそれを防ぐためのコードです。
次に、Native Moduleの型定義を見ていきます。NativeコードのSwift側の返り値でPromiseを返すようにしていたので、TypeScript側のメソッドの返り値の型もPromiseとなります。TypeScriptでNative Moduleの型定義を追加することで、開発効率も上がると思われます。
最後に、ヘルパー関数経由でNative Moduleを呼び出せるようにしています。このコード例を見ていただくと、Native Moduleが読み込まれていればそれを使って値を取得して返す、という処理になっていて、例えばAndroidのような未対応のものの場合は初期値を返すという実装になっています。これは、いくつかのExpo SDKを参考にしました。Expo SDKだとWebでもNativeでもひとつのヘルパー関数で機能を提供するようになっていました。
Summary
まとめです。
Bobというツールを使うと開発環境をすぐにセットアップできて、すぐにコードを書く準備ができます。
Native Modules開発では、関係する技術が多いので、アーキテクチャーとか既に公開されているライブラリを調査しました。さらにNativeのモダンな言語で実装するためには、公式のドキュメントは参考になりました。
今回、一番実装の参考になったのは、コミュニティーのライブラリーやExpo SDKでした。今後もし、自分たちでNative Modulesを開発する必要がある場合は、React Native Communityのリポジトリなどが実装の参考になるかと思います。
以上です。ありがとうございました。
LT4本目:React NativeのVisual Regression Testについて
株式会社CureApp Jesse Katsumata氏:
「React NativeのVisual Regression Testについて」というタイトルで発表させていただきます。はじめにちょっと自己紹介をさせてください。Jesseと申します。
GitHub:@Naturalclar
Twitter:@natural_clar
というIDでやっています。
株式会社CureAppというところでエンジニアをやっています。また、OSSの活動も結構活発に行っており、先ほどちょっと名前が出たReact Native Communityの中の人のひとりでもあります。React Native Communityで開発しているModulesのいくつかをメンテナンスしていたり、React Native本体にもプルリクを出して最新のリリース情報などを提供しています。
会社の方も少し紹介させていただきたいのですが、CureAppという会社で治療アプリを開発しています。「アプリを病院で処方する」という未来を実現するために動いています。なんと今日起きたことなのですが、日本国内・アジア初の治療アプリというものが厚生労働省から薬事承認が出ました。我々が目指している未来に大きな一歩として近づけたのではないかと思っています。
社内のエンジニアの話をすると、全員がTypeScriptのエンジニアです。WebはReactで書いていて、サーバーはNode.js、アプリはもちろんReact Native、インフラ側もAWSを使っているのですがAWSCDKというTypeScriptでインフラの設定が書けるものを使っている、という上から下まで全部TypeScriptという会社です。とはいえ全員が全員、全部書けるというわけではなくて、UI部分、ロジックの部分、サーバーの部分、インフラの部分はちゃんと分業されていて、各管轄のところでテストをしっかりと書いています。
Visual Regression Testというのが今日の話したいことで、先ほど言ったUIテストにあたる部分の話になります。
Visual Regression Testとは
まずは、「Visual Regression Testとは何か」からご説明します。
先ほと少し話したように、Visual Regression Testは、UIテストの一環です。UIテストと言っても結構いろいろなやり方があって、スナップショットを撮るテストだったり、他にEnzymeとかを使って各コンポーネントが存在することを確認するテストだったりがあるのですが、Visual Regression Testというのは見た目にフォーカスしたテストです。
「Email入力欄がある」とか「ログインボタンがある」とか「レイアウトが崩れてないか」というのを、「実際にアプリでどう見えるか」というのを見て確認します。
どう動くかというと、もともとのメインブランチだったりデベロップブランチだったりで、すべての画面のスクリーンショットを保管しておきます。それとは別に、CIと連携して、Pull Requestが投げられたら、その度にそのPull Requestのbranchの中で全部の画面のスクリーンショットを撮って、それを元のメインブランチの画像とPull Requestのbranchの画像を比較する。それで、「不必要な変更が入っていないか」とか「変更がちゃんと行われているか」というのをテストするものです。
画像右に表示されているように、もし、ボタンの形に変更があった場合は、変更された部分を赤く検知したり、左右に新しい見た目と古い見た目を置いて、どこが変わったかを自分の目で実際に見たりすることができます。
Visual Regression Testで大事なところ、肝となるところは、DOMの実装方法に関して完全に無関心であること。これがなぜ嬉しいのか。一長一短はあるのですが、サードパーティのコンポーネントライブラリを使っているとします。React Nativeだったら、React Native Elementsだったり、React Native UI Kittenだったり、React Native Paperだったり、いろいろなWebでいうBootstrapみたいなコンポーネント集のライブラリがあります。それをアップデートした時に、ライブラリにアップデートがあった場合は、その中身の実装などもちょこちょこ変わっている可能性があると思うのですが、それでも、見た目が変わっていないかということを確実にテストするのに便利です。
例えば、先ほど言ったスナップショットテストというのは、実際にDOMの構造をチェックするので、ライブラリをアップデートした時にもしかしたらスナップショットが変わっているかもしれない。でも、それの結果、見た目が変わっただろうか、というのがスナップショットを見ただけではわからない。そういう問題を、Visual Regression Testは本当に見た目だけに集中するので、簡単に差分だけを検出することができます。
Visual Regression Testで、これから紹介するreg-suitというツールは、各Pull Requestに自動的にコメントを上の画像のように添えてくれます。こういうレポートを作ってくれて、例えば、ここに2つ表示されている赤い丸は「2つのコンポーネントの見た目が変わったよ」、青い丸は「他のコンポーネントの見た目は比較したけど一緒だったよ」ということを報告してくれます。他に新しくコンポーネントを作った時は白い丸だったり、コンポーネントを消した時は黒い丸でレポートが表示されます。
例えば、ひとつのボタンの見た目を変更した時に、それはひとつのページでしか見た目を変更して欲しくない、でも実はそのボタンをどこか他のページで使っていた、結果3つの場所で変更が行われていた、みたいな不本意な変更を、こういったレポートを見ることによって防ぐことができる。これがVisual Regression Testの強みです。
reg-suitの紹介
我々がVisual Regression Testとして使っているツールがreg-suitというものです。
reg-suitは本当に無料で使えてCLIでパパッとセットアップしてくれて、先ほど言った、コンポーネントのスクリーンショットを全部S3やGCS(Google Cloud Storage)だったりのクラウドに保管してくれるので、かなり管理が楽なツールです。
それをReact Nativeとどう紐付けるかという話なのですが、我々はStorybookというコンポーネントテストのためのツールを使っています。各コンポーネントの一覧を表示するというツールです。そして、最初の登壇でも少し話題に出たReact Native for WebというReact NativeのコンポーネントをWebで表示させるというツール。ツールというかライブラリでしょうか。この2つを組み合わせて我々のアプリのUIは実装されています。
Storybook + React Native for Web
Visual Regression Testとは別にこれをやる利点というのがあって、Storybookの特性として、ロジックの部分を省いたアプリのページの見た目の確認というのが簡単にできるようになるというのと、React Native for Webを使うことで、全部Webで動くのでエミューレーターを立ち上げる必要がなくなります。特にスペックが低いPCなどを使っていると、毎回AndroidとiOSのエミュレーターを立ち上げて動作確認というのはすごく重くて、そもそもアプリのビルドにも時間がかかったりするのですが、そういうのを全部取っ払って、Webの方で一旦画面を確認してパパパッと書いてそれをアプリに入れる、というプロセスが踏めるので、圧倒的に効率の良いUIの作成ができるということです。
このVisual Regression Test、UIテストが全般的にどういう場面で役立つのか、というのを見せるための極端な例をご紹介します。
ここにアプリのサインアップページがあったとします。「サインアップのページのボタンが小さいなぁ」と思うかもしれません。そのボタンをクリックしたいのですが、このボタンはPrimaryButtonというコンポーネントを使っていたとします。widthが150なので、ここを大きくすれば、このサインアップのページのボタンは大きくなりユーザーが押しやすくなる、widthを変えればボタンの横幅が変わり平和的に解決する。これでコミットして変える準備をするというようなことが想定できるかもしれません。
ここで想定していなかったのが、PrimaryButtonというのはログインの画面でも使われていました。ログインの画面は「Register」と「Login」という2つのボタンがPrimaryButtonを使って実装されていました。ここもwidthが先ほどの変更で変わってしまったので、ここのレイアウトが崩れてしまいました。
例えば、PrimaryButtonの変更だけでプルリクを送ったとします。プルリクの中身はこれしかないので、サインアップページとログインページの両方に変更があった、ということをプルリクをレビューする人がパッと気づけない危険性がある。もちろん自分で動作確認をすれば問題ないのですが、チームメートがいろいろ変わったりしてコードベースの理解をしていないとか、そういった時に、「あ、ここの変更だけだったら問題なさそうだな」とマージしてしまうかもしれません。そういったことをVisual Regression Testで自動的にテストすることによって事前に防ぐことができます。
まとめ
軽くまとめると、Visual Regression Testを実装することで、UIのレビュー時間が短縮になったり、コンポーネントライブラリのアップデートが安心してできるようになって、Storybookを使うことによってReact Nativeでもコンポーネントの開発が高速にできるといったメリットがあります。
ちょっと面白いところが、今回使ったスライドも全部React Nativeで書かれています。正確には、React Native for Webで書いています。
これにて発表を終わります。ありがとうございました。
ー ー ー
stand.fmでは積極的にエンジニア採用をしています。
少しでも興味を持っていただけましたら、ぜひこちらをご覧ください。
https://corp.stand.fm/recruit